From 0ed2bafa3425066ae3bf1716dbf8fb4ab89a7261 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 17 Jul 2024 15:12:34 +0200 Subject: [PATCH 01/54] mac: reduce log warning to info for non-existent LCIDs during DRB removal --- ...p_du_ue_context_modification_procedure.cpp | 3 +++ lib/mac/mac_config_interfaces.h | 3 +++ lib/mac/mac_ctrl/mac_controller.cpp | 2 ++ lib/mac/mac_ul/mac_ul_processor.cpp | 8 ++++++ lib/mac/mac_ul/mac_ul_processor.h | 2 ++ lib/mac/mac_ul/mac_ul_ue_manager.cpp | 25 ++++++++++++++++++- lib/mac/mac_ul/mac_ul_ue_manager.h | 5 ++++ lib/mac/mac_ul/pdu_rx_handler.cpp | 3 ++- tests/unittests/mac/mac_ctrl_test_dummies.h | 1 + 9 files changed, 50 insertions(+), 2 deletions(-) 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 ded8d93151..b3cedd0fe3 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 @@ -32,6 +32,9 @@ void f1ap_du_ue_context_modification_procedure::operator()(coro_contextrrc_container_present) { diff --git a/lib/mac/mac_config_interfaces.h b/lib/mac/mac_config_interfaces.h index 83d0b368b3..bdbaaabf98 100644 --- a/lib/mac/mac_config_interfaces.h +++ b/lib/mac/mac_config_interfaces.h @@ -25,6 +25,9 @@ class mac_ul_configurator virtual async_task remove_bearers(du_ue_index_t ue_index, span lcids_to_rem) = 0; virtual async_task remove_ue(const mac_ue_delete_request& msg) = 0; virtual bool flush_ul_ccch_msg(du_ue_index_t ue_index, byte_buffer pdu) = 0; + + /// Handle the confirmation that the UE applied the new configuration. + virtual void handle_ue_config_applied(du_ue_index_t ue_index) = 0; }; class mac_dl_configurator : public mac_cell_manager diff --git a/lib/mac/mac_ctrl/mac_controller.cpp b/lib/mac/mac_ctrl/mac_controller.cpp index 5e49bb2066..c45249f99a 100644 --- a/lib/mac/mac_ctrl/mac_controller.cpp +++ b/lib/mac/mac_ctrl/mac_controller.cpp @@ -68,6 +68,8 @@ void mac_controller::handle_ue_config_applied(du_ue_index_t ue_index) { srsran_assert(ue_db.contains(ue_index), "Invalid ue_index={}", ue_index); + ul_unit.handle_ue_config_applied(ue_index); + sched_cfg.handle_ue_config_applied(ue_index); } diff --git a/lib/mac/mac_ul/mac_ul_processor.cpp b/lib/mac/mac_ul/mac_ul_processor.cpp index 13b4578349..788b2ed40d 100644 --- a/lib/mac/mac_ul/mac_ul_processor.cpp +++ b/lib/mac/mac_ul/mac_ul_processor.cpp @@ -69,6 +69,14 @@ bool mac_ul_processor::flush_ul_ccch_msg(du_ue_index_t ue_index, byte_buffer ccc return true; } +void mac_ul_processor::handle_ue_config_applied(du_ue_index_t ue_index) +{ + if (not cfg.ue_exec_mapper.ctrl_executor(ue_index).execute( + [this, ue_index]() { ue_manager.handle_ue_config_applied(ue_index); })) { + logger.warning("ue={}: Unable to forward UE config applied to upper layers. Cause: task queue is full.", ue_index); + } +} + void mac_ul_processor::handle_rx_data_indication(mac_rx_data_indication msg) { for (mac_rx_pdu& pdu : msg.pdus) { diff --git a/lib/mac/mac_ul/mac_ul_processor.h b/lib/mac/mac_ul/mac_ul_processor.h index cb3571ed5d..ac132cda46 100644 --- a/lib/mac/mac_ul/mac_ul_processor.h +++ b/lib/mac/mac_ul/mac_ul_processor.h @@ -46,6 +46,8 @@ class mac_ul_processor final : public mac_ul_configurator, public mac_pdu_handle bool flush_ul_ccch_msg(du_ue_index_t ue_index, byte_buffer ccch_pdu) override; + void handle_ue_config_applied(du_ue_index_t ue_index) override; + /// Handles FAPI Rx_Data.Indication. /// The PDUs contained in the Rx_Data.Indication are dispatched to different executors, depending on their RNTI. void handle_rx_data_indication(mac_rx_data_indication msg) override; diff --git a/lib/mac/mac_ul/mac_ul_ue_manager.cpp b/lib/mac/mac_ul/mac_ul_ue_manager.cpp index 9049dd8e71..605b5945af 100644 --- a/lib/mac/mac_ul/mac_ul_ue_manager.cpp +++ b/lib/mac/mac_ul/mac_ul_ue_manager.cpp @@ -50,8 +50,11 @@ void mac_ul_ue_manager::remove_ue(du_ue_index_t ue_index) bool mac_ul_ue_manager::addmod_bearers(du_ue_index_t ue_index, const std::vector& ul_logical_channels) { + if (ul_logical_channels.empty()) { + return true; + } if (not ue_db.contains(ue_index)) { - logger.error("ue={}: Interrupting DEMUX update. Cause: The provided index does not exist", ue_index); + logger.error("ue={}: Interrupting DEMUX update. Cause: The provided UE ID does not exist", ue_index); return false; } mac_ul_ue_context& u = ue_db[ue_index]; @@ -60,11 +63,16 @@ bool mac_ul_ue_manager::addmod_bearers(du_ue_index_t u.ul_bearers.insert(channel.lcid, channel.ul_bearer); } + u.rrc_config_pending = true; + return true; } bool mac_ul_ue_manager::remove_bearers(du_ue_index_t ue_index, span lcids) { + if (lcids.empty()) { + return true; + } if (not ue_db.contains(ue_index)) { logger.error("ue={} Interrupting DEMUX update. Cause: The provided index does not exist", ue_index); return false; @@ -74,5 +82,20 @@ bool mac_ul_ue_manager::remove_bearers(du_ue_index_t ue_index, span ul_bearers; }; @@ -64,6 +67,8 @@ class mac_ul_ue_manager return nullptr; } + void handle_ue_config_applied(du_ue_index_t ue_index); + private: /// Arguments of UE manager. srslog::basic_logger& logger; diff --git a/lib/mac/mac_ul/pdu_rx_handler.cpp b/lib/mac/mac_ul/pdu_rx_handler.cpp index 8acb7ba35a..bb58a2c6ac 100644 --- a/lib/mac/mac_ul/pdu_rx_handler.cpp +++ b/lib/mac/mac_ul/pdu_rx_handler.cpp @@ -167,7 +167,8 @@ bool pdu_rx_handler::handle_sdu(const decoded_mac_rx_pdu& ctx, const mac_ul_sch_ lcid_t lcid = (lcid_t)sdu.lcid().value(); if (not ue->ul_bearers.contains(lcid)) { - logger.warning("{}: Discarding SDU. Cause: Non-existent LCID", create_prefix(ctx, sdu)); + srslog::log_channel& log_ch = ue->rrc_config_pending ? logger.info : logger.warning; + log_ch("{}: Discarding SDU. Cause: Non-existent LCID", create_prefix(ctx, sdu)); return false; } diff --git a/tests/unittests/mac/mac_ctrl_test_dummies.h b/tests/unittests/mac/mac_ctrl_test_dummies.h index e35fbad554..5e90b8ff18 100644 --- a/tests/unittests/mac/mac_ctrl_test_dummies.h +++ b/tests/unittests/mac/mac_ctrl_test_dummies.h @@ -51,6 +51,7 @@ class mac_ul_dummy_configurer final : public mac_ul_configurator ul_ccch_forwarded = true; return true; } + void handle_ue_config_applied(du_ue_index_t ue_index) override {} }; class mac_cell_dummy_controller final : public mac_cell_controller From abf062ea1045d8abac5d43a1358e9c9f9a45b23a Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Mon, 8 Jul 2024 10:01:30 +0200 Subject: [PATCH 02/54] e2sm_rc: update Slice-level PRB quota param ids --- .../e2sm_rc_control_action_du_executor.cpp | 18 +++++++++--------- .../e2/e2_ric_control_procedure_test.cpp | 16 ++++++---------- tests/unittests/e2/e2_setup_procedure_test.cpp | 2 +- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/lib/e2/e2sm/e2sm_rc/e2sm_rc_control_action_du_executor.cpp b/lib/e2/e2sm/e2sm_rc/e2sm_rc_control_action_du_executor.cpp index a60d811541..cd69e67718 100644 --- a/lib/e2/e2sm/e2sm_rc/e2sm_rc_control_action_du_executor.cpp +++ b/lib/e2/e2sm/e2sm_rc/e2sm_rc_control_action_du_executor.cpp @@ -85,15 +85,15 @@ e2sm_rc_control_action_2_6_du_executor::e2sm_rc_control_action_2_6_du_executor(d action_params.insert({1, "RRM Policy Ratio List"}); action_params.insert({2, "RRM Policy Ratio Group"}); action_params.insert({3, "RRM Policy"}); - action_params.insert({4, "RRM Policy Member List"}); - action_params.insert({5, "RRM Policy Member"}); - action_params.insert({6, "PLMN Identity"}); - action_params.insert({7, "S-NSSAI"}); - action_params.insert({8, "SST"}); - action_params.insert({9, "SD"}); - action_params.insert({10, "Min PRB Policy Ratio"}); - action_params.insert({11, "Max PRB Policy Ratio"}); - action_params.insert({12, "Dedicated PRB Policy Ratio"}); + action_params.insert({5, "RRM Policy Member List"}); + action_params.insert({6, "RRM Policy Member"}); + action_params.insert({7, "PLMN Identity"}); + action_params.insert({8, "S-NSSAI"}); + action_params.insert({9, "SST"}); + action_params.insert({10, "SD"}); + action_params.insert({11, "Min PRB Policy Ratio"}); + action_params.insert({12, "Max PRB Policy Ratio"}); + action_params.insert({13, "Dedicated PRB Policy Ratio"}); }; void e2sm_rc_control_action_2_6_du_executor::parse_action_ran_parameter_value(const ran_param_value_type_c& ran_param, diff --git a/tests/unittests/e2/e2_ric_control_procedure_test.cpp b/tests/unittests/e2/e2_ric_control_procedure_test.cpp index 13d8863641..e30ae6afcb 100644 --- a/tests/unittests/e2/e2_ric_control_procedure_test.cpp +++ b/tests/unittests/e2/e2_ric_control_procedure_test.cpp @@ -68,16 +68,12 @@ TEST_F(e2_test_setup, ric_control_procedure_fail) TEST_F(e2_test_setup, ric_control_procedure_packed) { uint8_t e2ap_ctrl_req[] = { - 0x00, 0x04, 0x00, 0x80, 0xb5, 0x00, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x05, 0x00, 0x03, 0xfd, 0x00, 0x00, 0x00, 0x05, - 0x00, 0x02, 0x00, 0x03, 0x00, 0x16, 0x00, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x10, 0x00, 0x00, - 0x00, 0x01, 0x02, 0x00, 0x00, 0x05, 0x00, 0x17, 0x00, 0x80, 0x84, 0x80, 0x82, 0x00, 0x00, 0x01, 0x00, 0x00, 0x60, - 0x00, 0x01, 0x40, 0x00, 0x03, 0x00, 0x02, 0x44, 0x00, 0x00, 0x00, 0x03, 0x60, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, - 0x05, 0x2a, 0x00, 0x05, 0x35, 0x30, 0x35, 0x30, 0x31, 0x00, 0x06, 0x44, 0x00, 0x01, 0x00, 0x07, 0x2a, 0x00, 0x01, - 0x31, 0x00, 0x08, 0x2a, 0x00, 0x01, 0x30, 0x00, 0x09, 0x28, 0x80, 0x01, 0x05, 0x00, 0x0a, 0x28, 0x80, 0x01, 0x33, - 0x00, 0x0b, 0x28, 0x80, 0x01, 0x46, 0x40, 0x00, 0x03, 0x00, 0x02, 0x44, 0x00, 0x00, 0x00, 0x03, 0x60, 0x00, 0x00, - 0x40, 0x00, 0x01, 0x00, 0x05, 0x2a, 0x00, 0x05, 0x35, 0x30, 0x35, 0x30, 0x31, 0x00, 0x06, 0x44, 0x00, 0x01, 0x00, - 0x07, 0x2a, 0x00, 0x01, 0x31, 0x00, 0x08, 0x2a, 0x00, 0x01, 0x35, 0x00, 0x09, 0x28, 0x80, 0x01, 0x05, 0x00, 0x0a, - 0x28, 0x80, 0x01, 0x33, 0x00, 0x0b, 0x28, 0x80, 0x01, 0x1e, 0x00, 0x15, 0x00, 0x01, 0x40}; + 0x00, 0x04, 0x00, 0x6e, 0x00, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x02, 0x00, 0x03, 0x00, 0x16, 0x00, 0x09, 0x08, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x05, 0x00, 0x17, 0x00, + 0x46, 0x45, 0x00, 0x00, 0x01, 0x00, 0x00, 0x60, 0x00, 0x00, 0x40, 0x00, 0x03, 0x00, 0x02, 0x44, 0x00, 0x00, 0x00, + 0x03, 0x60, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, 0x05, 0x2a, 0x00, 0x05, 0x30, 0x30, 0x31, 0x30, 0x31, 0x00, 0x06, + 0x44, 0x00, 0x01, 0x00, 0x07, 0x2a, 0x00, 0x01, 0x31, 0x00, 0x08, 0x2a, 0x00, 0x01, 0x30, 0x00, 0x09, 0x28, 0x80, + 0x01, 0x01, 0x00, 0x0a, 0x28, 0x80, 0x01, 0x05, 0x00, 0x0b, 0x28, 0x80, 0x01, 0x64, 0x00, 0x15, 0x00, 0x01, 0x40}; byte_buffer e2ap_ctrl_req_buf = byte_buffer::create(e2ap_ctrl_req, e2ap_ctrl_req + sizeof(e2ap_ctrl_req)).value(); packer->handle_packed_pdu(std::move(e2ap_ctrl_req_buf)); diff --git a/tests/unittests/e2/e2_setup_procedure_test.cpp b/tests/unittests/e2/e2_setup_procedure_test.cpp index 8f033b4e01..be55aab356 100644 --- a/tests/unittests/e2/e2_setup_procedure_test.cpp +++ b/tests/unittests/e2/e2_setup_procedure_test.cpp @@ -201,7 +201,7 @@ TEST_F(e2_test_setup, e2_sends_correct_rc_ran_function_definition) .ric_ctrl_action_list[0] .ran_ctrl_action_params_list[9] .ran_param_id, - 10); + 11); ASSERT_EQ(ran_func_def.ran_function_definition_ctrl.ric_ctrl_style_list[0] .ric_ctrl_action_list[0] .ran_ctrl_action_params_list[9] From 9a0a51a88654623c93910aec1ac207072af49a93 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Tue, 9 Jul 2024 17:50:31 +0200 Subject: [PATCH 03/54] sched: enable Format 0 in PUCCH allocator Signed-off-by: Carlo Galiotto --- .../flexible_du/du_high/du_high_config.h | 2 + .../du_high/du_high_config_cli11_schema.cpp | 6 + .../du_high/du_high_config_translators.cpp | 2 + .../du_high/du_high_config_yaml_writer.cpp | 1 + .../pucch_scheduling/pucch_allocator_impl.cpp | 150 ++++++++++++------ .../pucch_scheduling/pucch_allocator_impl.h | 9 +- 6 files changed, 119 insertions(+), 51 deletions(-) diff --git a/apps/units/flexible_du/du_high/du_high_config.h b/apps/units/flexible_du/du_high/du_high_config.h index b2b6dc38e7..ced6501bae 100644 --- a/apps/units/flexible_du/du_high/du_high_config.h +++ b/apps/units/flexible_du/du_high/du_high_config.h @@ -207,6 +207,8 @@ struct du_high_unit_pucch_config { /// \c PUCCH-ConfigCommon parameters. /// \c p0-nominal, TS 38.331. Value in dBm. Only even values allowed within {-202,...,24}. int p0_nominal = -90; + /// \c pucch-ResourceCommon, TS 38.331. Values: {0,...,15}. Defines the PUCCH resource set used common configuration. + unsigned pucch_resource_common = 11; /// \c PUCCH-Config parameters. /// Number of PUCCH Format 0/1 resources per UE for HARQ-ACK reporting. Values {1,...,8}. diff --git a/apps/units/flexible_du/du_high/du_high_config_cli11_schema.cpp b/apps/units/flexible_du/du_high/du_high_config_cli11_schema.cpp index 2ff4a2c8e3..0be5adaf42 100644 --- a/apps/units/flexible_du/du_high/du_high_config_cli11_schema.cpp +++ b/apps/units/flexible_du/du_high/du_high_config_cli11_schema.cpp @@ -755,6 +755,12 @@ static void configure_cli11_pucch_args(CLI::App& app, du_high_unit_pucch_config& return ""; }); + add_option(app, + "--pucch_resource_common", + pucch_params.nof_cell_sr_resources, + "Index of PUCCH resource set for the common configuration") + ->capture_default_str() + ->check(CLI::Range(1, 15)); add_option(app, "--sr_period_ms", pucch_params.sr_period_msec, "SR period in msec") ->capture_default_str() ->check(CLI::IsMember({1.0F, 2.0F, 2.5F, 4.0F, 5.0F, 8.0F, 10.0F, 16.0F, 20.0F, 40.0F, 80.0F, 160.0F, 320.0F})); diff --git a/apps/units/flexible_du/du_high/du_high_config_translators.cpp b/apps/units/flexible_du/du_high/du_high_config_translators.cpp index 145bc4c876..ecd91f0991 100644 --- a/apps/units/flexible_du/du_high/du_high_config_translators.cpp +++ b/apps/units/flexible_du/du_high/du_high_config_translators.cpp @@ -420,6 +420,8 @@ std::vector srsran::generate_du_cell_config(const du_high_unit_c out_cell.ul_cfg_common.init_ul_bwp.pucch_cfg_common.emplace(); } out_cell.ul_cfg_common.init_ul_bwp.pucch_cfg_common.value().p0_nominal = base_cell.pucch_cfg.p0_nominal; + out_cell.ul_cfg_common.init_ul_bwp.pucch_cfg_common.value().pucch_resource_common = + base_cell.pucch_cfg.pucch_resource_common; // Common PDCCH config. search_space_configuration& ss1_cfg = out_cell.dl_cfg_common.init_dl_bwp.pdcch_common.search_spaces.back(); diff --git a/apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp b/apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp index 3cea0938c5..d0cd8884a6 100644 --- a/apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp +++ b/apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp @@ -407,6 +407,7 @@ static YAML::Node build_du_high_pucch_section(const du_high_unit_pucch_config& c YAML::Node node; node["p0_nominal"] = config.p0_nominal; + node["pucch_resource_common"] = config.pucch_resource_common; node["sr_period_ms"] = config.sr_period_msec; node["f0_or_f1_nof_ue_res_harq"] = config.nof_ue_pucch_f0_or_f1_res_harq; node["f0_or_f1_nof_cell_res_sr"] = config.nof_cell_sr_resources; diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp index c68d45014a..ccbe677d7a 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp @@ -358,13 +358,19 @@ void pucch_allocator_impl::pucch_allocate_sr_opportunity(cell_slot_resource_allo // Allocate PUCCH SR grant only. const unsigned harq_ack_bits_increment = 0U; if (format == pucch_format::FORMAT_0) { - srsran_assertion_failure("PUCCH Format 0 is not yet supported for SR"); - } else { + fill_pucch_ded_format0_grant(pucch_slot_alloc.result.ul.pucchs.emplace_back(), + crnti, + *pucch_sr_res, + harq_ack_bits_increment, + sr_nof_bits::one); + } else if (format == pucch_format::FORMAT_1) { fill_pucch_ded_format1_grant(pucch_slot_alloc.result.ul.pucchs.emplace_back(), crnti, *pucch_sr_res, harq_ack_bits_increment, sr_nof_bits::one); + } else { + srsran_assertion_failure("Only PUCCH Format 0 and Format 1 are supported for SR dedicated grant"); } // Save the info in the scheduler list of PUCCH grants. @@ -407,8 +413,8 @@ void pucch_allocator_impl::pucch_allocate_csi_opportunity(cell_slot_resource_all } if (existing_grant_it != pucch_grants_alloc_grid[sl_tx.to_uint()].end() and existing_grant_it->has_common_pucch) { - // Allocation of dedicated + common resources are handled by allocating PUCCH common on existing CSI, not the other - // way around. If the function enters the path, it means it too early to start scheduling the CSI. + // Allocation of dedicated + common resources are handled by allocating PUCCH common on existing CSI, not the + // other way around. If the function enters the path, it means it too early to start scheduling the CSI. logger.info("rnti={}: CSI occasion allocation for slot={} skipped. Cause: There is a PUCCH common grant" "allocated at this slot", crnti, @@ -1023,11 +1029,11 @@ pucch_allocator_impl::find_common_and_ded_harq_res_available(cell_slot_resource_ // As per Section 9.2.1, TS 38.213, this is the max value of \f$\Delta_{PRI}\f$, which is a 3-bit unsigned. const unsigned max_d_pri = 7; for (unsigned d_pri = 0; d_pri != max_d_pri + 1; ++d_pri) { - // The PUCCH allocation may result in a temporary reservation of PUCCH resources, which need to be released in case - // of failure or in case the multiplexing results in a different final PUCCH resource. If we don't reset the - // previous record, we could release the resources that have been allocated for other UEs of allocated for this UE - // in a different slot. - // Reset at each iteration, as a new iteration indicates that the previous allocation failed. + // The PUCCH allocation may result in a temporary reservation of PUCCH resources, which need to be released in + // case of failure or in case the multiplexing results in a different final PUCCH resource. If we don't reset the + // previous record, we could release the resources that have been allocated for other UEs of allocated for this + // UE in a different slot. Reset at each iteration, as a new iteration indicates that the previous allocation + // failed. resource_manager.reset_latest_reserved_res_tracker(); // r_PUCCH, as per Section 9.2.1, TS 38.213. @@ -1117,12 +1123,19 @@ std::optional pucch_allocator_impl::allocate_harq_grant(cell_slot_reso // Allocate the new grant on PUCCH F1 resources for HARQ-ACK bits (without SR). pucch_info& pucch_pdu = pucch_slot_alloc.result.ul.pucchs.emplace_back(); const unsigned HARQ_BITS_IN_NEW_PUCCH_GRANT = 1; - fill_pucch_ded_format1_grant( - pucch_pdu, crnti, *pucch_harq_res_info.pucch_res, HARQ_BITS_IN_NEW_PUCCH_GRANT, sr_nof_bits::no_sr); - const auto pucch_res_indicator = static_cast(pucch_harq_res_info.pucch_res_indicator); + if (pucch_harq_res_info.pucch_res->format == pucch_format::FORMAT_0) { + fill_pucch_ded_format0_grant( + pucch_pdu, crnti, *pucch_harq_res_info.pucch_res, HARQ_BITS_IN_NEW_PUCCH_GRANT, sr_nof_bits::no_sr); + } else if (pucch_harq_res_info.pucch_res->format == pucch_format::FORMAT_1) { + fill_pucch_ded_format1_grant( + pucch_pdu, crnti, *pucch_harq_res_info.pucch_res, HARQ_BITS_IN_NEW_PUCCH_GRANT, sr_nof_bits::no_sr); + } else { + srsran_assertion_failure("Only PUCCH Format 0 or 1 can be used for UCI with only 1 HARQ-ACK bit"); + } // Save the info in the scheduler list of PUCCH grants. - auto& grants = pucch_grants_alloc_grid[sl_tx.to_uint()].emplace_back(ue_grants{.rnti = crnti}); + const auto pucch_res_indicator = static_cast(pucch_harq_res_info.pucch_res_indicator); + auto& grants = pucch_grants_alloc_grid[sl_tx.to_uint()].emplace_back(ue_grants{.rnti = crnti}); grants.pucch_grants.harq_resource.emplace(pucch_grant{.type = pucch_grant_type::harq_ack}); grants.pucch_grants.harq_resource.value().set_res_config(*pucch_harq_res_info.pucch_res); grants.pucch_grants.harq_resource.value().harq_id.pucch_set_idx = pucch_res_set_idx::set_0; @@ -1198,6 +1211,38 @@ void pucch_allocator_impl::allocate_csi_grant(cell_slot_resource_allocator& pucc csi_pucch_grant.pucch_grants.csi_resource.value().bits.csi_part1_nof_bits = csi_part1_bits; } +void pucch_allocator_impl::fill_pucch_ded_format0_grant(pucch_info& pucch_pdu, + rnti_t crnti, + const pucch_resource& pucch_ded_res_cfg, + unsigned harq_ack_bits, + sr_nof_bits sr_bits) + +{ + pucch_pdu.crnti = crnti; + pucch_pdu.bwp_cfg = &cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; + pucch_pdu.format = pucch_format::FORMAT_0; + + // Set PRBs and symbols, first. + // The number of PRBs is not explicitly stated in the TS, but it can be inferred it's 1. + const auto& res_f0 = std::get(pucch_ded_res_cfg.format_params); + pucch_pdu.resources.prbs.set(pucch_ded_res_cfg.starting_prb, + +pucch_ded_res_cfg.starting_prb + PUCCH_FORMAT_0_1_NOF_PRBS); + pucch_pdu.resources.symbols.set(res_f0.starting_sym_idx, res_f0.starting_sym_idx + res_f0.nof_symbols); + if (pucch_ded_res_cfg.second_hop_prb.has_value()) { + pucch_pdu.resources.second_hop_prbs.set(pucch_ded_res_cfg.second_hop_prb.value(), + pucch_ded_res_cfg.second_hop_prb.value() + PUCCH_FORMAT_0_1_NOF_PRBS); + } + // \c pucch-GroupHopping and \c hoppingId are set as per TS 38.211, Section 6.3.2.2.1. + pucch_pdu.format_0.group_hopping = cell_cfg.ul_cfg_common.init_ul_bwp.pucch_cfg_common->group_hopping; + pucch_pdu.format_0.n_id_hopping = cell_cfg.ul_cfg_common.init_ul_bwp.pucch_cfg_common->hopping_id.has_value() + ? cell_cfg.ul_cfg_common.init_ul_bwp.pucch_cfg_common->hopping_id.value() + : cell_cfg.pci; + pucch_pdu.format_0.initial_cyclic_shift = res_f0.initial_cyclic_shift; + // For PUCCH Format 0, only 1 SR bit. + pucch_pdu.format_0.sr_bits = sr_bits; + pucch_pdu.format_0.harq_ack_nof_bits = harq_ack_bits; +} + void pucch_allocator_impl::fill_pucch_ded_format1_grant(pucch_info& pucch_pdu, rnti_t crnti, const pucch_resource& pucch_ded_res_cfg, @@ -1212,11 +1257,11 @@ void pucch_allocator_impl::fill_pucch_ded_format1_grant(pucch_info& pu // The number of PRBs is not explicitly stated in the TS, but it can be inferred it's 1. const auto& res_f1 = std::get(pucch_ded_res_cfg.format_params); pucch_pdu.resources.prbs.set(pucch_ded_res_cfg.starting_prb, - pucch_ded_res_cfg.starting_prb + PUCCH_FORMAT_1_NOF_PRBS); + pucch_ded_res_cfg.starting_prb + PUCCH_FORMAT_0_1_NOF_PRBS); pucch_pdu.resources.symbols.set(res_f1.starting_sym_idx, res_f1.starting_sym_idx + res_f1.nof_symbols); if (pucch_ded_res_cfg.second_hop_prb.has_value()) { pucch_pdu.resources.second_hop_prbs.set(pucch_ded_res_cfg.second_hop_prb.value(), - pucch_ded_res_cfg.second_hop_prb.value() + PUCCH_FORMAT_1_NOF_PRBS); + pucch_ded_res_cfg.second_hop_prb.value() + PUCCH_FORMAT_0_1_NOF_PRBS); } // \c pucch-GroupHopping and \c hoppingId are set as per TS 38.211, Section 6.3.2.2.1. pucch_pdu.format_1.group_hopping = cell_cfg.ul_cfg_common.init_ul_bwp.pucch_cfg_common->group_hopping; @@ -1354,8 +1399,8 @@ pucch_allocator_impl::multiplex_and_allocate_pucch(cell_slot_resource_allocator& // information bits, the UE determines a PUCCH resource set to be ...". const pucch_uci_bits current_uci_bits = current_grants.pucch_grants.get_uci_bits(); const bool is_multiplexing_needed = - not((current_uci_bits.harq_ack_nof_bits == 1 and new_bits.harq_ack_nof_bits == 2) or - (current_uci_bits.harq_ack_nof_bits == 3 and new_bits.harq_ack_nof_bits > 3)); + not((current_uci_bits.harq_ack_nof_bits == 1U and new_bits.harq_ack_nof_bits == 2U) or + (current_uci_bits.harq_ack_nof_bits == 3U and new_bits.harq_ack_nof_bits > 3U)); pucch_grant_list grants_to_tx = is_multiplexing_needed @@ -1383,7 +1428,8 @@ pucch_allocator_impl::get_pucch_res_pre_multiplexing(slot_point const pucch_config& pucch_cfg = ue_cell_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.value(); if (new_bits.harq_ack_nof_bits > 0) { - // Case HARQ ACK bits 1 or 2, resource to be chosen from PUCCH resource set 0; else, pick from PUCCH resource set 1. + // Case HARQ ACK bits 1 or 2, resource to be chosen from PUCCH resource set 0; else, pick from PUCCH resource + // set 1. const pucch_res_set_idx pucch_set_idx = new_bits.harq_ack_nof_bits <= 2U ? pucch_res_set_idx::set_0 : pucch_res_set_idx::set_1; @@ -1435,8 +1481,8 @@ pucch_allocator_impl::get_pucch_res_pre_multiplexing(slot_point harq_candidate_grant.harq_id.pucch_res_ind = static_cast(harq_resource.pucch_res_indicator); harq_candidate_grant.set_res_config(*harq_resource.pucch_res); } - // Only copy the HARQ-ACK bits, as at this stage we only need to consider the UCI bits assuming the resources still - // need to be multiplexed. + // Only copy the HARQ-ACK bits, as at this stage we only need to consider the UCI bits assuming the resources + // still need to be multiplexed. harq_candidate_grant.bits.harq_ack_nof_bits = new_bits.harq_ack_nof_bits; harq_candidate_grant.bits.sr_bits = sr_nof_bits::no_sr; harq_candidate_grant.bits.csi_part1_nof_bits = 0U; @@ -1447,8 +1493,8 @@ pucch_allocator_impl::get_pucch_res_pre_multiplexing(slot_point pucch_grant& sr_candidate_grant = candidate_resources.sr_resource.value(); // Get the resource from the resource manager; the UCI bits will be added later. - // NOTE: if the SR resource was already assigned to this UE, the resource manager will only return the PUCCH config - // that was reserved previously. + // NOTE: if the SR resource was already assigned to this UE, the resource manager will only return the PUCCH + // config that was reserved previously. const pucch_resource* sr_resource = resource_manager.reserve_sr_res_available(sl_tx, ue_current_grants.rnti, pucch_cfg); // Save the resources that have been generated; if at some point the allocation fails, we need to release them. @@ -1471,8 +1517,8 @@ pucch_allocator_impl::get_pucch_res_pre_multiplexing(slot_point pucch_grant& csi_candidate_grant = candidate_resources.csi_resource.value(); // Get the resource from the resource manager; the UCI bits will be added later. - // NOTE: if the CSI resource was already assigned to this UE, the resource manager will only return the PUCCH config - // that was reserved previously. + // NOTE: if the CSI resource was already assigned to this UE, the resource manager will only return the PUCCH + // config that was reserved previously. const pucch_resource* csi_resource = resource_manager.reserve_csi_resource(sl_tx, ue_current_grants.rnti, ue_cell_cfg); // Save the resources that have been generated; if at some point the allocation fails, we need to release them. @@ -1483,8 +1529,8 @@ pucch_allocator_impl::get_pucch_res_pre_multiplexing(slot_point return std::nullopt; } csi_candidate_grant.set_res_config(*csi_resource); - // Only copy the HARQ-ACK bits, as at this stage we only need to consider the UCI bits assuming the resources still - // need to be multiplexed. + // Only copy the HARQ-ACK bits, as at this stage we only need to consider the UCI bits assuming the resources + // still need to be multiplexed. csi_candidate_grant.bits.harq_ack_nof_bits = 0U; csi_candidate_grant.bits.sr_bits = sr_nof_bits::no_sr; csi_candidate_grant.bits.csi_part1_nof_bits = new_bits.csi_part1_nof_bits; @@ -1675,11 +1721,11 @@ pucch_allocator_impl::merge_pucch_resources(span= 2: all PUCCH resources will be multiplexed in a PUCCH resource from PUCCH - // res set 1. - // NOTE: This rule is defined in Section 9.2.5.1 or 9.2.5.2 (if any CSI bits), TS 38.213. + // Apply HARQ merging rule for Format >= 2: all PUCCH resources will be multiplexed in a PUCCH resource from + // PUCCH res set 1. NOTE: This rule is defined in Section 9.2.5.1 or 9.2.5.2 (if any CSI bits), TS 38.213. // NOTE: For the case of HARQ-ACK with Format >= 2, the HARQ-ACK resource has HARQ-ACK bits and optionally CSI // bits. else { @@ -1700,9 +1745,9 @@ pucch_allocator_impl::merge_pucch_resources(span= 2: all PUCCH resources will be multiplexed in a PUCCH - // resource from PUCCH resource set 1. - // NOTE: This rule is defined in Section 9.2.5.2, TS 38.213. - // NOTE: SR bits, if present, can be in either HARQ or CSI, but not in both. + // HARQ and CSI only. Apply HARQ merging rule for Format >= 2: all PUCCH resources will be multiplexed in a + // PUCCH resource from PUCCH resource set 1. NOTE: This rule is defined in Section 9.2.5.2, TS 38.213. NOTE: SR + // bits, if present, can be in either HARQ or CSI, but not in both. if ((r_0.type == pucch_grant_type::harq_ack and r_1.type == pucch_grant_type::csi) or (r_0.type == pucch_grant_type::csi and r_1.type == pucch_grant_type::harq_ack)) { - // Apply F2 HARQ merging rule: all PUCCH resources will be multiplexed in a PUCCH resource from PUCCH res set 1. + // Apply F2 HARQ merging rule: all PUCCH resources will be multiplexed in a PUCCH resource from PUCCH res + // set 1. pucch_grant new_resource{.type = pucch_grant_type::harq_ack}; const pucch_grant& r_harq = r_0.type == pucch_grant_type::harq_ack ? r_0 : r_1; const pucch_grant& r_csi = r_0.type == pucch_grant_type::csi ? r_0 : r_1; @@ -1771,9 +1816,8 @@ pucch_allocator_impl::merge_pucch_resources(span pucch_allocator_impl::allocate_grants(cell_slot_resource pucch_info* grant = existing_pdus.get_next_grant(pucch_pdus); srsran_assert(grant != nullptr, "The return grant cannot be nullptr"); if (grants_to_tx.sr_resource.value().format == pucch_format::FORMAT_0) { - // TODO - srsran_assertion_failure("PUCCH Format 0 is not yet implemented"); - } else { + fill_pucch_ded_format0_grant(*grant, + crnti, + *grants_to_tx.sr_resource.value().pucch_res_cfg, + grants_to_tx.sr_resource.value().bits.harq_ack_nof_bits, + grants_to_tx.sr_resource.value().bits.sr_bits); + } else if (grants_to_tx.sr_resource.value().format == pucch_format::FORMAT_1) { fill_pucch_ded_format1_grant(*grant, crnti, *grants_to_tx.sr_resource.value().pucch_res_cfg, @@ -2018,8 +2065,11 @@ std::optional pucch_allocator_impl::allocate_grants(cell_slot_resource if (grants_to_tx.harq_resource.has_value() and not harq_grant_alloc_completed) { pucch_info* grant = existing_pdus.get_next_grant(pucch_pdus); if (grants_to_tx.harq_resource.value().format == pucch_format::FORMAT_0) { - // TODO - srsran_assertion_failure("PUCCH Format 0 is not yet implemented"); + fill_pucch_ded_format0_grant(*grant, + crnti, + *grants_to_tx.harq_resource.value().pucch_res_cfg, + grants_to_tx.harq_resource.value().bits.harq_ack_nof_bits, + grants_to_tx.harq_resource.value().bits.sr_bits); } else if (grants_to_tx.harq_resource.value().format == pucch_format::FORMAT_1) { fill_pucch_ded_format1_grant(*grant, crnti, diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.h b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.h index 217b94c045..b112ee4218 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.h +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.h @@ -211,6 +211,13 @@ class pucch_allocator_impl final : public pucch_allocator // Fills the PUCCH HARQ PDU for common resources. void fill_pucch_harq_common_grant(pucch_info& pucch_info, rnti_t rnti, const pucch_res_alloc_cfg& pucch_res); + // Fills the PUCCH Format 0 PDU. + void fill_pucch_ded_format0_grant(pucch_info& pucch_grant, + rnti_t crnti, + const pucch_resource& pucch_ded_res_cfg, + unsigned harq_ack_bits, + sr_nof_bits sr_bits); + // Fills the PUCCH Format 1 PDU. void fill_pucch_ded_format1_grant(pucch_info& pucch_grant, rnti_t crnti, @@ -240,7 +247,7 @@ class pucch_allocator_impl final : public pucch_allocator // \brief Ring of PUCCH allocations indexed by slot. circular_array pucch_grants_alloc_grid; - constexpr static unsigned PUCCH_FORMAT_1_NOF_PRBS{1}; + constexpr static unsigned PUCCH_FORMAT_0_1_NOF_PRBS{1}; const cell_configuration& cell_cfg; const unsigned max_pucch_grants_per_slot; const unsigned max_ul_grants_per_slot; From 31d72a6d50bfd7acd84b27d30e913b0d57a315f7 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Tue, 9 Jul 2024 18:28:42 +0200 Subject: [PATCH 04/54] sched: add pucch_alloc unittest for format 0 Signed-off-by: Carlo Galiotto --- .../pucch_scheduling/pucch_allocator_impl.cpp | 68 ++- .../scheduler/uci_and_pucch/CMakeLists.txt | 1 + .../pucch_alloc_harq_sr_csi_test.cpp | 561 ++++++++++++++---- .../uci_and_pucch/pucch_res_manager_test.cpp | 2 +- .../uci_and_pucch/uci_test_utils.cpp | 14 + .../scheduler/uci_and_pucch/uci_test_utils.h | 20 +- 6 files changed, 537 insertions(+), 129 deletions(-) diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp index ccbe677d7a..519350ffca 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp @@ -635,9 +635,10 @@ existing_pucch_pdus_handler::existing_pucch_pdus_handler(rnti_t c pucch.pdu_context.id = MAX_PUCCH_PDUS_PER_SLOT; if (pucch.format == srsran::pucch_format::FORMAT_0) { - // With Format 0, when there are both HARQ bits and SR bits, we only use the HARQ-ACK resource; the only - // case when the SR PUCCH F0 is used is when there are only SR bits. - if (pucch.format_0.sr_bits != sr_nof_bits::one and pucch.format_0.harq_ack_nof_bits == 0U) { + // With Format 0, when there are both HARQ bits and SR bits in the same PDU (this means that the PUCCH HARQ + // reource and SR resource have overlapping symbols), we only use the HARQ-ACK resource; the only case when the + // SR PUCCH F0 is used is when there are only SR bits. + if (pucch.format_0.sr_bits != sr_nof_bits::no_sr and pucch.format_0.harq_ack_nof_bits == 0U) { sr_pdu = &pucch; ++pdus_cnt; } else if (pucch.format_0.harq_ack_nof_bits != 0U and pucch.format_0.harq_ack_nof_bits <= 2U) { @@ -1579,7 +1580,9 @@ pucch_allocator_impl::update_grants_no_multiplexing(slot_point if (ue_current_grants.pucch_grants.sr_resource.has_value()) { srsran_assert(candidate_grants.sr_resource.has_value(), "PUCCH SR resource must be present"); grants_to_tx.sr_resource.value().set_res_config(*candidate_grants.sr_resource->pucch_res_cfg); - grants_to_tx.sr_resource.value().bits.harq_ack_nof_bits = harq_grant.bits.harq_ack_nof_bits; + // For Format 0, if the SR and HARQ resources are separate, the SR resuorce doesn't carry the HARQ-ACK bits. + grants_to_tx.sr_resource.value().bits.harq_ack_nof_bits = + grants_to_tx.sr_resource.value().format == pucch_format::FORMAT_0 ? 0U : harq_grant.bits.harq_ack_nof_bits; } return grants_to_tx; @@ -1960,17 +1963,28 @@ std::optional pucch_allocator_impl::allocate_grants(cell_slot_resource // If there was a SR grant, re-use the previous one and update UCI bits with HARQ bits. else if (grants_to_tx.sr_resource.has_value() and existing_pucchs.pucch_grants.sr_resource.has_value() and existing_pdus.sr_pdu != nullptr) { - // NOTE: the validator is responsible for checking that the is no mix of PUCCH Format 0 and Format 1. - logger.debug("rnti={}: PUCCH PDU allocated on SR resource (updated): slot={} prbs={} sym={} cs={} occ={} " - "h_bits={} sr_bits={}", - crnti, - pucch_slot_alloc.slot, - existing_pdus.sr_pdu->resources.prbs, - existing_pdus.sr_pdu->resources.symbols, - existing_pdus.sr_pdu->format_1.initial_cyclic_shift, - existing_pdus.sr_pdu->format_1.time_domain_occ, - grants_to_tx.sr_resource.value().bits.harq_ack_nof_bits, - grants_to_tx.sr_resource.value().bits.sr_bits); + if (grants_to_tx.sr_resource.value().format == pucch_format::FORMAT_0) { + logger.debug("rnti={}: PUCCH PDU allocated on SR FO resource (updated): slot={} prbs={} sym={} " + "h_bits={} sr_bits={}", + crnti, + pucch_slot_alloc.slot, + existing_pdus.sr_pdu->resources.prbs, + existing_pdus.sr_pdu->resources.symbols, + grants_to_tx.sr_resource.value().bits.harq_ack_nof_bits, + grants_to_tx.sr_resource.value().bits.sr_bits); + } else { + logger.debug("rnti={}: PUCCH PDU allocated on SR F1 resource (updated): slot={} prbs={} sym={} cs={} occ={} " + "h_bits={} sr_bits={}", + crnti, + pucch_slot_alloc.slot, + existing_pdus.sr_pdu->resources.prbs, + existing_pdus.sr_pdu->resources.symbols, + existing_pdus.sr_pdu->format_1.initial_cyclic_shift, + existing_pdus.sr_pdu->format_1.time_domain_occ, + grants_to_tx.sr_resource.value().bits.harq_ack_nof_bits, + grants_to_tx.sr_resource.value().bits.sr_bits); + } + existing_pdus.update_sr_pdu_bits(grants_to_tx.sr_resource.value().bits.sr_bits, grants_to_tx.sr_resource.value().bits.harq_ack_nof_bits); sr_grant_alloc_completed = true; @@ -1981,7 +1995,17 @@ std::optional pucch_allocator_impl::allocate_grants(cell_slot_resource grants_to_tx.harq_resource.value().format == existing_pucchs.pucch_grants.harq_resource.value().format and existing_pdus.harq_pdu != nullptr) { // Update bits; - if (grants_to_tx.harq_resource.value().format == pucch_format::FORMAT_1) { + if (grants_to_tx.harq_resource.value().format == pucch_format::FORMAT_0) { + logger.debug("rnti={}: PUCCH PDU allocated on F0 HARQ resource (updated): slot={} p_ind={} prbs={} sym={} " + "h_bits={} sr_bits={}", + crnti, + pucch_slot_alloc.slot, + grants_to_tx.harq_resource.value().harq_id.pucch_res_ind, + existing_pdus.harq_pdu->resources.prbs, + existing_pdus.harq_pdu->resources.symbols, + grants_to_tx.harq_resource.value().bits.harq_ack_nof_bits, + grants_to_tx.harq_resource.value().bits.sr_bits); + } else if (grants_to_tx.harq_resource.value().format == pucch_format::FORMAT_1) { logger.debug("rnti={}: PUCCH PDU allocated on F1 HARQ resource (updated): slot={} p_ind={} prbs={} sym={} cs={} " "occ={} h_bits={} sr_bits={}", crnti, @@ -2095,7 +2119,17 @@ std::optional pucch_allocator_impl::allocate_grants(cell_slot_resource grants_to_tx.harq_resource.value().bits.sr_bits, grants_to_tx.harq_resource.value().bits.csi_part1_nof_bits); } - if (grant->format == pucch_format::FORMAT_1) { + if (grant->format == pucch_format::FORMAT_0) { + logger.debug("rnti={}: PUCCH PDU allocated on F0 HARQ resource: slot={} p_ind={} prbs={} sym={} " + "h_bits={} sr_bits={}", + crnti, + pucch_slot_alloc.slot, + grants_to_tx.harq_resource.value().harq_id.pucch_res_ind, + grant->resources.prbs, + grant->resources.symbols, + grant->format_0.harq_ack_nof_bits, + grant->format_0.sr_bits); + } else if (grant->format == pucch_format::FORMAT_1) { logger.debug("rnti={}: PUCCH PDU allocated on F1 HARQ resource: slot={} p_ind={} prbs={} sym={} cs={} occ={} " "h_bits={} sr_bits={}", crnti, diff --git a/tests/unittests/scheduler/uci_and_pucch/CMakeLists.txt b/tests/unittests/scheduler/uci_and_pucch/CMakeLists.txt index f6f75f3b5f..3375747471 100644 --- a/tests/unittests/scheduler/uci_and_pucch/CMakeLists.txt +++ b/tests/unittests/scheduler/uci_and_pucch/CMakeLists.txt @@ -23,6 +23,7 @@ target_link_libraries(uci_pucch_sched_test uci_test_utils sched_config mac_configuration_helpers + sched_test_doubles gtest gtest_main) gtest_discover_tests(uci_pucch_sched_test) diff --git a/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp b/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp index 841487019e..b9a10b9368 100644 --- a/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp +++ b/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp @@ -18,79 +18,17 @@ const unsigned NOF_RBS = 52; /////// Test allocation of dedicated PUCCH resources /////// -class test_pucch_allocator_ded_resources : public ::testing::Test +class pucch_allocator_base_tester { public: - test_pucch_allocator_ded_resources(unsigned max_pucchs_per_slot_ = 32U, unsigned max_ul_grants_per_slot_ = 32U) : - t_bench(test_bench_params{.pucch_res_common = 11, .n_cces = 1}, max_pucchs_per_slot_, max_ul_grants_per_slot_) - { - // Set expected grant for PUCCH Format 1 SR. - pucch_expected_f1_sr.format = pucch_format::FORMAT_1; - pucch_expected_f1_sr.crnti = to_rnti(0x4601); - pucch_expected_f1_sr.bwp_cfg = &t_bench.cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; - - pucch_expected_f1_sr.resources.prbs = prb_interval{NOF_RBS - 3, NOF_RBS - 2}; - pucch_expected_f1_sr.resources.second_hop_prbs = prb_interval{0, 0}; - pucch_expected_f1_sr.resources.symbols = ofdm_symbol_range{0, 14}; - - pucch_expected_f1_sr.format_1.initial_cyclic_shift = 0; - pucch_expected_f1_sr.format_1.sr_bits = sr_nof_bits::one; - pucch_expected_f1_sr.format_1.harq_ack_nof_bits = 0; - pucch_expected_f1_sr.format_1.time_domain_occ = 0; - - pucch_expected_f1_sr.format_1.group_hopping = pucch_group_hopping::NEITHER; - pucch_expected_f1_sr.format_1.n_id_hopping = t_bench.cell_cfg.pci; - pucch_expected_f1_sr.format_1.slot_repetition = pucch_repetition_tx_slot::no_multi_slot; - - // Set expected grant for PUCCH Format 1 HARQ. - pucch_expected_f1_harq.format = srsran::pucch_format::FORMAT_1; - pucch_expected_f1_harq.crnti = to_rnti(0x4601); - pucch_expected_f1_harq.bwp_cfg = &t_bench.cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; - - pucch_expected_f1_harq.resources.prbs = prb_interval{NOF_RBS - 1, NOF_RBS}; - pucch_expected_f1_harq.resources.second_hop_prbs = prb_interval{0, 0}; - pucch_expected_f1_harq.resources.symbols = ofdm_symbol_range{0, 14}; - - pucch_expected_f1_harq.format_1.initial_cyclic_shift = 0; - pucch_expected_f1_harq.format_1.sr_bits = sr_nof_bits::no_sr; - pucch_expected_f1_harq.format_1.harq_ack_nof_bits = 1; - pucch_expected_f1_harq.format_1.time_domain_occ = 0; - - // Set expected grant for PUCCH Format 1. - pucch_expected_f1_harq.format_1.group_hopping = pucch_group_hopping::NEITHER; - pucch_expected_f1_harq.format_1.n_id_hopping = t_bench.cell_cfg.pci; - pucch_expected_f1_harq.format_1.slot_repetition = pucch_repetition_tx_slot::no_multi_slot; - - pucch_expected_f2.format = srsran::pucch_format::FORMAT_2; - pucch_expected_f2.crnti = to_rnti(0x4601); - pucch_expected_f2.bwp_cfg = &t_bench.cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; - pucch_expected_f2.resources.prbs = prb_interval{2, 3}; - pucch_expected_f2.resources.second_hop_prbs = prb_interval{0, 0}; - pucch_expected_f2.resources.symbols = ofdm_symbol_range{0, 2}; - - pucch_expected_f2.format_2.max_code_rate = max_pucch_code_rate::dot_25; - pucch_expected_f2.format_2.n_id_scambling = t_bench.cell_cfg.pci; - pucch_expected_f2.format_2.n_id_0_scrambling = t_bench.cell_cfg.pci; - - pucch_expected_csi.format = srsran::pucch_format::FORMAT_2; - pucch_expected_csi.crnti = to_rnti(0x4601); - pucch_expected_csi.bwp_cfg = &t_bench.cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; - pucch_expected_csi.resources.prbs = prb_interval{2, 3}; - pucch_expected_csi.resources.second_hop_prbs = prb_interval{0, 0}; - pucch_expected_csi.resources.symbols = ofdm_symbol_range{12, 14}; - - pucch_expected_csi.format_2.max_code_rate = max_pucch_code_rate::dot_25; - pucch_expected_csi.format_2.n_id_scambling = t_bench.cell_cfg.pci; - pucch_expected_csi.format_2.n_id_0_scrambling = t_bench.cell_cfg.pci; - }; + pucch_allocator_base_tester(test_bench_params params_ = test_bench_params{.pucch_res_common = 11, .n_cces = 1}, + unsigned max_pucchs_per_slot_ = 32U, + unsigned max_ul_grants_per_slot_ = 32U) : + t_bench(params_, max_pucchs_per_slot_, max_ul_grants_per_slot_){}; protected: // Parameters that are passed by the routine to run the tests. test_bench t_bench; - pucch_info pucch_expected_f1_sr; - pucch_info pucch_expected_f1_harq; - pucch_info pucch_expected_f2; - pucch_info pucch_expected_csi; const unsigned pucch_res_idx{0}; void add_sr_grant() @@ -180,10 +118,83 @@ class test_pucch_allocator_ded_resources : public ::testing::Test } }; -class test_pucch_f2_alloc_several_prbs : public ::testing::Test +class test_pucch_allocator_ded_resources : public ::testing::Test, public pucch_allocator_base_tester { public: - test_pucch_f2_alloc_several_prbs() : t_bench(test_bench_params{.pucch_f2_more_prbs = true}) + test_pucch_allocator_ded_resources() : pucch_allocator_base_tester() + { + // Set expected grant for PUCCH Format 1 SR. + pucch_expected_f1_sr.format = pucch_format::FORMAT_1; + pucch_expected_f1_sr.crnti = to_rnti(0x4601); + pucch_expected_f1_sr.bwp_cfg = &t_bench.cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; + + pucch_expected_f1_sr.resources.prbs = prb_interval{NOF_RBS - 3, NOF_RBS - 2}; + pucch_expected_f1_sr.resources.second_hop_prbs = prb_interval{0, 0}; + pucch_expected_f1_sr.resources.symbols = ofdm_symbol_range{0, 14}; + + pucch_expected_f1_sr.format_1.initial_cyclic_shift = 0; + pucch_expected_f1_sr.format_1.sr_bits = sr_nof_bits::one; + pucch_expected_f1_sr.format_1.harq_ack_nof_bits = 0; + pucch_expected_f1_sr.format_1.time_domain_occ = 0; + + pucch_expected_f1_sr.format_1.group_hopping = pucch_group_hopping::NEITHER; + pucch_expected_f1_sr.format_1.n_id_hopping = t_bench.cell_cfg.pci; + pucch_expected_f1_sr.format_1.slot_repetition = pucch_repetition_tx_slot::no_multi_slot; + + // Set expected grant for PUCCH Format 1 HARQ. + pucch_expected_f1_harq.format = srsran::pucch_format::FORMAT_1; + pucch_expected_f1_harq.crnti = to_rnti(0x4601); + pucch_expected_f1_harq.bwp_cfg = &t_bench.cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; + + pucch_expected_f1_harq.resources.prbs = prb_interval{NOF_RBS - 1, NOF_RBS}; + pucch_expected_f1_harq.resources.second_hop_prbs = prb_interval{0, 0}; + pucch_expected_f1_harq.resources.symbols = ofdm_symbol_range{0, 14}; + + pucch_expected_f1_harq.format_1.initial_cyclic_shift = 0; + pucch_expected_f1_harq.format_1.sr_bits = sr_nof_bits::no_sr; + pucch_expected_f1_harq.format_1.harq_ack_nof_bits = 1; + pucch_expected_f1_harq.format_1.time_domain_occ = 0; + + // Set expected grant for PUCCH Format 1. + pucch_expected_f1_harq.format_1.group_hopping = pucch_group_hopping::NEITHER; + pucch_expected_f1_harq.format_1.n_id_hopping = t_bench.cell_cfg.pci; + pucch_expected_f1_harq.format_1.slot_repetition = pucch_repetition_tx_slot::no_multi_slot; + + pucch_expected_f2.format = srsran::pucch_format::FORMAT_2; + pucch_expected_f2.crnti = to_rnti(0x4601); + pucch_expected_f2.bwp_cfg = &t_bench.cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; + pucch_expected_f2.resources.prbs = prb_interval{2, 3}; + pucch_expected_f2.resources.second_hop_prbs = prb_interval{0, 0}; + pucch_expected_f2.resources.symbols = ofdm_symbol_range{0, 2}; + + pucch_expected_f2.format_2.max_code_rate = max_pucch_code_rate::dot_25; + pucch_expected_f2.format_2.n_id_scambling = t_bench.cell_cfg.pci; + pucch_expected_f2.format_2.n_id_0_scrambling = t_bench.cell_cfg.pci; + + pucch_expected_csi.format = srsran::pucch_format::FORMAT_2; + pucch_expected_csi.crnti = to_rnti(0x4601); + pucch_expected_csi.bwp_cfg = &t_bench.cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; + pucch_expected_csi.resources.prbs = prb_interval{2, 3}; + pucch_expected_csi.resources.second_hop_prbs = prb_interval{0, 0}; + pucch_expected_csi.resources.symbols = ofdm_symbol_range{12, 14}; + + pucch_expected_csi.format_2.max_code_rate = max_pucch_code_rate::dot_25; + pucch_expected_csi.format_2.n_id_scambling = t_bench.cell_cfg.pci; + pucch_expected_csi.format_2.n_id_0_scrambling = t_bench.cell_cfg.pci; + }; + +protected: + // Parameters that are passed by the routine to run the tests. + pucch_info pucch_expected_f1_sr; + pucch_info pucch_expected_f1_harq; + pucch_info pucch_expected_f2; + pucch_info pucch_expected_csi; +}; + +class test_pucch_f2_alloc_several_prbs : public ::testing::Test, public pucch_allocator_base_tester +{ +public: + test_pucch_f2_alloc_several_prbs() : pucch_allocator_base_tester(test_bench_params{.pucch_f2_more_prbs = true}) { // This PUCCH grant will be for 5 HARQ bits, which fit in 1 PRB. pucch_expected_harq_only.format = srsran::pucch_format::FORMAT_2; @@ -216,41 +227,9 @@ class test_pucch_f2_alloc_several_prbs : public ::testing::Test protected: // Parameters that are passed by the routine to run the tests. - test_bench t_bench; pucch_info pucch_expected_harq_only; pucch_info pucch_expected_harq_csi; pucch_info pucch_expected_csi_only; - - void add_sr_grant() - { - t_bench.pucch_alloc.pucch_allocate_sr_opportunity(t_bench.res_grid[t_bench.k0 + t_bench.k1], - t_bench.get_main_ue().crnti, - t_bench.get_main_ue().get_pcell().cfg()); - } - - void add_harq_grant() - { - t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( - t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); - } - - std::optional add_format2_harq_grant() - { - t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( - t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); - t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( - t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); - return t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( - t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); - } - - void add_csi_grant(unsigned csi_part1_bits = 4) - { - t_bench.pucch_alloc.pucch_allocate_csi_opportunity(t_bench.res_grid[t_bench.k0 + t_bench.k1], - t_bench.get_main_ue().crnti, - t_bench.get_main_ue().get_pcell().cfg(), - csi_part1_bits); - } }; /////////////// Tests PUCCH allocator for SR. @@ -1431,10 +1410,13 @@ TEST_F(test_pucch_allocator_ded_resources, test_for_private_fnc_retrieving_exist /////// Test UL grants reached and PUCCH fails. /////// -class test_pucch_allocator_ded_resources_reached_ul_grants : public test_pucch_allocator_ded_resources +class test_pucch_allocator_ded_resources_reached_ul_grants : public ::testing::Test, public pucch_allocator_base_tester { public: - test_pucch_allocator_ded_resources_reached_ul_grants() : test_pucch_allocator_ded_resources(3U, 6U) {} + test_pucch_allocator_ded_resources_reached_ul_grants() : + pucch_allocator_base_tester(test_bench_params{.pucch_res_common = 11, .n_cces = 1}, 3U, 6U) + { + } }; TEST_F(test_pucch_allocator_ded_resources_reached_ul_grants, test_max_pucch_allocation_reached) @@ -1499,6 +1481,379 @@ TEST_F(test_pucch_allocator_ded_resources_reached_ul_grants, test_csi_max_ul_all ASSERT_EQ(0, slot_grid.result.ul.pucchs.size()); } +/////// Test PUCCH Format 0. /////// + +class test_pucch_allocator_format_0 : public ::testing::Test, public pucch_allocator_base_tester +{ +public: + test_pucch_allocator_format_0() : + pucch_allocator_base_tester(test_bench_params{.pucch_res_common = 0, .use_format_0 = true}) + { + // Set expected grant for PUCCH Format 1 SR. + pucch_expected_f0_sr.format = pucch_format::FORMAT_0; + pucch_expected_f0_sr.crnti = to_rnti(0x4601); + pucch_expected_f0_sr.bwp_cfg = &t_bench.cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; + + pucch_expected_f0_sr.resources.prbs = prb_interval{0, 1}; + pucch_expected_f0_sr.resources.second_hop_prbs = prb_interval{0, 0}; + pucch_expected_f0_sr.resources.symbols = ofdm_symbol_range{6, 8}; + + pucch_expected_f0_sr.format_0.initial_cyclic_shift = 0; + pucch_expected_f0_sr.format_0.sr_bits = sr_nof_bits::one; + pucch_expected_f0_sr.format_0.harq_ack_nof_bits = 0; + + pucch_expected_f0_sr.format_0.group_hopping = pucch_group_hopping::NEITHER; + pucch_expected_f0_sr.format_0.n_id_hopping = t_bench.cell_cfg.pci; + + // Set expected grant for PUCCH Format 1 HARQ. + pucch_expected_f0_harq.format = srsran::pucch_format::FORMAT_0; + pucch_expected_f0_harq.crnti = to_rnti(0x4601); + pucch_expected_f0_harq.bwp_cfg = &t_bench.cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; + + pucch_expected_f0_harq.resources.prbs = prb_interval{0, 1}; + pucch_expected_f0_harq.resources.second_hop_prbs = prb_interval{0, 0}; + pucch_expected_f0_harq.resources.symbols = ofdm_symbol_range{0, 2}; + + pucch_expected_f0_harq.format_0.initial_cyclic_shift = 0; + pucch_expected_f0_harq.format_0.sr_bits = sr_nof_bits::no_sr; + pucch_expected_f0_harq.format_0.harq_ack_nof_bits = 1; + + // Set expected grant for PUCCH Format 1. + pucch_expected_f0_harq.format_0.group_hopping = pucch_group_hopping::NEITHER; + pucch_expected_f0_harq.format_0.n_id_hopping = t_bench.cell_cfg.pci; + + pucch_expected_f2.format = srsran::pucch_format::FORMAT_2; + pucch_expected_f2.crnti = to_rnti(0x4601); + pucch_expected_f2.bwp_cfg = &t_bench.cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; + pucch_expected_f2.resources.prbs = prb_interval{2, 3}; + pucch_expected_f2.resources.second_hop_prbs = prb_interval{0, 0}; + pucch_expected_f2.resources.symbols = ofdm_symbol_range{0, 2}; + + pucch_expected_f2.format_2.max_code_rate = max_pucch_code_rate::dot_25; + pucch_expected_f2.format_2.n_id_scambling = t_bench.cell_cfg.pci; + pucch_expected_f2.format_2.n_id_0_scrambling = t_bench.cell_cfg.pci; + + pucch_expected_csi.format = srsran::pucch_format::FORMAT_2; + pucch_expected_csi.crnti = to_rnti(0x4601); + pucch_expected_csi.bwp_cfg = &t_bench.cell_cfg.ul_cfg_common.init_ul_bwp.generic_params; + pucch_expected_csi.resources.prbs = prb_interval{2, 3}; + pucch_expected_csi.resources.second_hop_prbs = prb_interval{0, 0}; + pucch_expected_csi.resources.symbols = ofdm_symbol_range{12, 14}; + + pucch_expected_csi.format_2.max_code_rate = max_pucch_code_rate::dot_25; + pucch_expected_csi.format_2.n_id_scambling = t_bench.cell_cfg.pci; + pucch_expected_csi.format_2.n_id_0_scrambling = t_bench.cell_cfg.pci; + }; + +protected: + // Parameters that are passed by the routine to run the tests. + pucch_info pucch_expected_f0_sr; + pucch_info pucch_expected_f0_harq; + pucch_info pucch_expected_f2; + pucch_info pucch_expected_csi; +}; + +TEST_F(test_pucch_allocator_format_0, test_sr_allocation_only) +{ + auto& slot_grid = t_bench.res_grid[t_bench.k0 + t_bench.k1]; + + t_bench.pucch_alloc.pucch_allocate_sr_opportunity( + slot_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg()); + + ASSERT_EQ(1, slot_grid.result.ul.pucchs.size()); + ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f0_sr](const auto& pdu) { + return pucch_info_match(expected, pdu); + })); +} + +TEST_F(test_pucch_allocator_format_0, test_harq_allocation_only) +{ + auto& slot_grid = t_bench.res_grid[t_bench.k0 + t_bench.k1]; + const std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + + ASSERT_TRUE(test_pucch_res_indicator.has_value()); + ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); + ASSERT_EQ(1, slot_grid.result.ul.pucchs.size()); + ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f0_harq](const auto& pdu) { + return pucch_info_match(expected, pdu); + })); +} + +TEST_F(test_pucch_allocator_format_0, test_harq_allocation_2_bits) +{ + auto& slot_grid = t_bench.res_grid[t_bench.k0 + t_bench.k1]; + t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + + const std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + + pucch_expected_f0_harq.format_0.harq_ack_nof_bits = 2U; + ASSERT_TRUE(test_pucch_res_indicator.has_value()); + ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); + ASSERT_EQ(1, slot_grid.result.ul.pucchs.size()); + ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f0_harq](const auto& pdu) { + return pucch_info_match(expected, pdu); + })); +} + +TEST_F(test_pucch_allocator_format_0, test_harq_allocation_over_sr) +{ + auto& slot_grid = t_bench.res_grid[t_bench.k0 + t_bench.k1]; + + t_bench.pucch_alloc.pucch_allocate_sr_opportunity( + slot_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg()); + + const std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + + pucch_expected_f0_harq.format_0.harq_ack_nof_bits = 1U; + pucch_expected_f0_harq.format_0.sr_bits = srsran::sr_nof_bits::no_sr; + pucch_expected_f0_sr.format_0.harq_ack_nof_bits = 0U; + pucch_expected_f0_sr.format_0.sr_bits = srsran::sr_nof_bits::one; + ASSERT_TRUE(test_pucch_res_indicator.has_value()); + ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); + ASSERT_EQ(2, slot_grid.result.ul.pucchs.size()); + ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f0_harq](const auto& pdu) { + return pucch_info_match(expected, pdu); + })); + ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f0_sr](const auto& pdu) { + return pucch_info_match(expected, pdu); + })); +} + +TEST_F(test_pucch_allocator_format_0, test_harq_allocation_2_bits_over_sr) +{ + auto& slot_grid = t_bench.res_grid[t_bench.k0 + t_bench.k1]; + + t_bench.pucch_alloc.pucch_allocate_sr_opportunity( + slot_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg()); + + t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + const std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + + pucch_expected_f0_harq.format_0.harq_ack_nof_bits = 2U; + pucch_expected_f0_harq.format_0.sr_bits = srsran::sr_nof_bits::no_sr; + pucch_expected_f0_sr.format_0.harq_ack_nof_bits = 0U; + pucch_expected_f0_sr.format_0.sr_bits = srsran::sr_nof_bits::one; + ASSERT_TRUE(test_pucch_res_indicator.has_value()); + ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); + ASSERT_EQ(2, slot_grid.result.ul.pucchs.size()); + ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f0_harq](const auto& pdu) { + return pucch_info_match(expected, pdu); + })); + ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f0_sr](const auto& pdu) { + return pucch_info_match(expected, pdu); + })); +} + +TEST_F(test_pucch_allocator_format_0, test_harq_allocation_3_bits_over_sr) +{ + auto& slot_grid = t_bench.res_grid[t_bench.k0 + t_bench.k1]; + + t_bench.pucch_alloc.pucch_allocate_sr_opportunity( + slot_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg()); + + t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + const std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + + pucch_expected_f2.format_2.harq_ack_nof_bits = 3U; + pucch_expected_f2.format_2.sr_bits = srsran::sr_nof_bits::no_sr; + // Change PRBs and symbol, as for Format 0 we use a different set of resources: + // - 4 PUCCH format 0 aligned on PRBs [0..1), 3 resources for HARQ with symbols [0..6), 1 for SR with symbols [6..8). + // - 6 PUCCH format 2 aligned on PRBs [1..2), 6 resources for HARQ with symbols [0..12), 1 for CSI with + // symbols [12..14). + pucch_expected_f2.resources.prbs.set(1, 2); + pucch_expected_f2.resources.symbols.set(0, 2); + pucch_expected_f0_sr.format_0.harq_ack_nof_bits = 0U; + pucch_expected_f0_sr.format_0.sr_bits = srsran::sr_nof_bits::one; + ASSERT_TRUE(test_pucch_res_indicator.has_value()); + ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); + ASSERT_EQ(2, slot_grid.result.ul.pucchs.size()); + ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f2](const auto& pdu) { + return pucch_info_match(expected, pdu); + })); + ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f0_sr](const auto& pdu) { + return pucch_info_match(expected, pdu); + })); +} + +TEST_F(test_pucch_allocator_format_0, test_harq_allocation_4_bits_over_sr) +{ + auto& slot_grid = t_bench.res_grid[t_bench.k0 + t_bench.k1]; + + t_bench.pucch_alloc.pucch_allocate_sr_opportunity( + slot_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg()); + + add_format2_harq_grant(); + const std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + + pucch_expected_f2.format_2.harq_ack_nof_bits = 4U; + pucch_expected_f2.format_2.sr_bits = srsran::sr_nof_bits::no_sr; + // Change PRBs and symbol, as for Format 0 we use a different set of resources: + // - 4 PUCCH format 0 aligned on PRBs [0..1), 3 resources for HARQ with symbols [0..6), 1 for SR with symbols [6..8). + // - 6 PUCCH format 2 aligned on PRBs [1..2), 6 resources for HARQ with symbols [0..12), 1 for CSI with + // symbols [12..14). + pucch_expected_f2.resources.prbs.set(1, 2); + pucch_expected_f2.resources.symbols.set(0, 2); + pucch_expected_f0_sr.format_0.harq_ack_nof_bits = 0U; + pucch_expected_f0_sr.format_0.sr_bits = srsran::sr_nof_bits::one; + ASSERT_TRUE(test_pucch_res_indicator.has_value()); + ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); + ASSERT_EQ(2, slot_grid.result.ul.pucchs.size()); + ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f2](const auto& pdu) { + return pucch_info_match(expected, pdu); + })); + ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f0_sr](const auto& pdu) { + return pucch_info_match(expected, pdu); + })); +} + +TEST_F(test_pucch_allocator_format_0, test_harq_allocation_over_csi) +{ + const unsigned csi_part1_bits = 4; + + auto& slot_grid = t_bench.res_grid[t_bench.k0 + t_bench.k1]; + t_bench.pucch_alloc.pucch_allocate_csi_opportunity( + slot_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), csi_part1_bits); + + const std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + + pucch_expected_f0_harq.format_0.harq_ack_nof_bits = 1U; + // Change PRBs and symbol, as for Format 0 we use a different set of resources: + // - 4 PUCCH format 0 aligned on PRBs [0..1), 3 resources for HARQ with symbols [0..6), 1 for SR with symbols [6..8). + // - 6 PUCCH format 2 aligned on PRBs [1..2), 6 resources for HARQ with symbols [0..12), 1 for CSI with + // symbols [12..14). + pucch_expected_csi.resources.prbs.set(1, 2); + pucch_expected_csi.resources.symbols.set(12, 14); + pucch_expected_csi.format_2.harq_ack_nof_bits = 0U; + pucch_expected_csi.format_2.csi_part1_bits = csi_part1_bits; + ASSERT_TRUE(test_pucch_res_indicator.has_value()); + ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); + ASSERT_EQ(2, slot_grid.result.ul.pucchs.size()); + ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f0_harq](const auto& pdu) { + return pucch_info_match(expected, pdu); + })); + ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_csi](const auto& pdu) { + return pucch_info_match(expected, pdu); + })); +} + +TEST_F(test_pucch_allocator_format_0, test_harq_allocation_2_bits_over_csi) +{ + const unsigned csi_part1_bits = 4; + + auto& slot_grid = t_bench.res_grid[t_bench.k0 + t_bench.k1]; + t_bench.pucch_alloc.pucch_allocate_csi_opportunity( + slot_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), csi_part1_bits); + + t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + const std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + + pucch_expected_f0_harq.format_0.harq_ack_nof_bits = 2U; + // Change PRBs and symbol, as for Format 0 we use a different set of resources: + // - 4 PUCCH format 0 aligned on PRBs [0..1), 3 resources for HARQ with symbols [0..6), 1 for SR with symbols [6..8). + // - 6 PUCCH format 2 aligned on PRBs [1..2), 6 resources for HARQ with symbols [0..12), 1 for CSI with + // symbols [12..14). + pucch_expected_csi.resources.prbs.set(1, 2); + pucch_expected_csi.resources.symbols.set(12, 14); + pucch_expected_csi.format_2.harq_ack_nof_bits = 0U; + pucch_expected_csi.format_2.csi_part1_bits = csi_part1_bits; + ASSERT_TRUE(test_pucch_res_indicator.has_value()); + ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); + ASSERT_EQ(2, slot_grid.result.ul.pucchs.size()); + ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f0_harq](const auto& pdu) { + return pucch_info_match(expected, pdu); + })); + ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_csi](const auto& pdu) { + return pucch_info_match(expected, pdu); + })); +} + +TEST_F(test_pucch_allocator_format_0, test_harq_allocation_3_bits_over_csi) +{ + const unsigned csi_part1_bits = 4; + + auto& slot_grid = t_bench.res_grid[t_bench.k0 + t_bench.k1]; + t_bench.pucch_alloc.pucch_allocate_csi_opportunity( + slot_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), csi_part1_bits); + + t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + const std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + + pucch_expected_f2.format_2.harq_ack_nof_bits = 3U; + pucch_expected_f2.format_2.sr_bits = srsran::sr_nof_bits::no_sr; + // Change PRBs and symbol, as for Format 0 we use a different set of resources: + // - 4 PUCCH format 0 aligned on PRBs [0..1), 3 resources for HARQ with symbols [0..6), 1 for SR with symbols [6..8). + // - 6 PUCCH format 2 aligned on PRBs [1..2), 6 resources for HARQ with symbols [0..12), 1 for CSI with + // symbols [12..14). + pucch_expected_f2.resources.prbs.set(1, 2); + pucch_expected_f2.resources.symbols.set(0, 2); + pucch_expected_csi.resources.prbs.set(1, 2); + pucch_expected_csi.resources.symbols.set(12, 14); + pucch_expected_csi.format_2.harq_ack_nof_bits = 0U; + pucch_expected_csi.format_2.csi_part1_bits = csi_part1_bits; + ASSERT_TRUE(test_pucch_res_indicator.has_value()); + ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); + ASSERT_EQ(2, slot_grid.result.ul.pucchs.size()); + ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f2](const auto& pdu) { + return pucch_info_match(expected, pdu); + })); + ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_csi](const auto& pdu) { + return pucch_info_match(expected, pdu); + })); +} + +TEST_F(test_pucch_allocator_format_0, test_harq_allocation_4_bits_over_csi) +{ + const unsigned csi_part1_bits = 4; + + auto& slot_grid = t_bench.res_grid[t_bench.k0 + t_bench.k1]; + t_bench.pucch_alloc.pucch_allocate_csi_opportunity( + slot_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), csi_part1_bits); + + add_format2_harq_grant(); + const std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + + pucch_expected_f2.format_2.harq_ack_nof_bits = 4U; + pucch_expected_f2.format_2.sr_bits = srsran::sr_nof_bits::no_sr; + // Change PRBs and symbol, as for Format 0 we use a different set of resources: + // - 4 PUCCH format 0 aligned on PRBs [0..1), 3 resources for HARQ with symbols [0..6), 1 for SR with symbols [6..8). + // - 6 PUCCH format 2 aligned on PRBs [1..2), 6 resources for HARQ with symbols [0..12), 1 for CSI with + // symbols [12..14). + pucch_expected_f2.resources.prbs.set(1, 2); + pucch_expected_f2.resources.symbols.set(0, 2); + pucch_expected_csi.resources.prbs.set(1, 2); + pucch_expected_csi.resources.symbols.set(12, 14); + pucch_expected_csi.format_2.harq_ack_nof_bits = 0U; + pucch_expected_csi.format_2.csi_part1_bits = csi_part1_bits; + ASSERT_TRUE(test_pucch_res_indicator.has_value()); + ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); + ASSERT_EQ(2, slot_grid.result.ul.pucchs.size()); + ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_f2](const auto& pdu) { + return pucch_info_match(expected, pdu); + })); + ASSERT_TRUE(find_pucch_pdu(slot_grid.result.ul.pucchs, [&expected = pucch_expected_csi](const auto& pdu) { + return pucch_info_match(expected, pdu); + })); +} + int main(int argc, char** argv) { srslog::fetch_basic_logger("TEST").set_level(srslog::basic_levels::info); diff --git a/tests/unittests/scheduler/uci_and_pucch/pucch_res_manager_test.cpp b/tests/unittests/scheduler/uci_and_pucch/pucch_res_manager_test.cpp index deeb3573a7..190c92228d 100644 --- a/tests/unittests/scheduler/uci_and_pucch/pucch_res_manager_test.cpp +++ b/tests/unittests/scheduler/uci_and_pucch/pucch_res_manager_test.cpp @@ -32,7 +32,7 @@ class test_pucch_resource_manager : public ::testing::Test test_pucch_resource_manager() : cell_cfg{sched_cfg, test_helpers::make_default_sched_cell_configuration_request()}, // TODO: when the CSI is enabled in the main config, replace create_initial_ue_serving_cell_config_with_csi() with - // config_helpers::create_default_initial_ue_serving_cell_config(). + // config_helpers::create_default_initial_ue_serving_cell_config(). ue_cell_cfg(to_rnti(0x4601), cell_cfg, create_initial_ue_serving_cell_config_with_csi()), pucch_cfg{ue_cell_cfg.cfg_dedicated().ul_config.value().init_ul_bwp.pucch_cfg.value()}, sl_tx(slot_point(0, 0)) diff --git a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp index c568dd3f25..8daad73aa0 100644 --- a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp +++ b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp @@ -125,6 +125,7 @@ test_bench::test_bench(const test_bench_params& params, max_pucchs_per_slot{max_pucchs_per_slot_}, max_ul_grants_per_slot{max_ul_grants_per_slot_}, pucch_f2_more_prbs{params.pucch_f2_more_prbs}, + use_format_0(params.use_format_0), pucch_alloc{cell_cfg, max_pucchs_per_slot, max_ul_grants_per_slot}, uci_alloc(pucch_alloc), uci_sched{cell_cfg, uci_alloc, ues}, @@ -190,6 +191,15 @@ test_bench::test_bench(const test_bench_params& params, csi_report.report_slot_period = params.csi_period; csi_report.report_slot_offset = params.csi_offset; + if (use_format_0) { + pucch_builder_params pucch_params{}; + pucch_params.f0_or_f1_params.emplace(); + pucch_builder.setup( + cell_cfg.ul_cfg_common.init_ul_bwp, params.is_tdd ? cell_cfg.tdd_cfg_common : std::nullopt, pucch_params); + srsran_assert(pucch_builder.add_build_new_ue_pucch_cfg(ue_req.cfg.cells.value().back().serv_cell_cfg), + "UE PUCCH configuration couldn't be built"); + } + ue_ded_cfgs.push_back(std::make_unique(ue_req.ue_index, ue_req.crnti, cell_cfg_list, ue_req.cfg)); ues.add_ue( std::make_unique(ue_creation_command{*ue_ded_cfgs.back(), ue_req.starts_in_fallback, harq_timeout_handler})); @@ -224,6 +234,10 @@ void test_bench::add_ue() ue_req.crnti = to_rnti(static_cast::type>(last_allocated_rnti) + 1); + srsran_assert(not use_format_0 or + pucch_builder.add_build_new_ue_pucch_cfg(ue_req.cfg.cells.value().back().serv_cell_cfg), + "UE PUCCH configuration couldn't be built"); + ue_ded_cfgs.push_back(std::make_unique(ue_req.ue_index, ue_req.crnti, cell_cfg_list, ue_req.cfg)); ues.add_ue( std::make_unique(ue_creation_command{*ue_ded_cfgs.back(), ue_req.starts_in_fallback, harq_timeout_handler})); diff --git a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.h b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.h index f17e141336..104fe682a4 100644 --- a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.h +++ b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.h @@ -13,6 +13,7 @@ #include "lib/scheduler/pucch_scheduling/pucch_allocator_impl.h" #include "lib/scheduler/uci_scheduling/uci_allocator_impl.h" #include "lib/scheduler/uci_scheduling/uci_scheduler_impl.h" +#include "tests/test_doubles/scheduler/pucch_res_test_builder_helper.h" #include "tests/unittests/scheduler/test_utils/config_generators.h" #include "tests/unittests/scheduler/test_utils/dummy_test_components.h" #include "tests/unittests/scheduler/test_utils/scheduler_test_suite.h" @@ -96,6 +97,7 @@ struct test_bench_params { bool is_tdd = false; bool pucch_f2_more_prbs = false; bool cfg_for_mimo_4x4 = false; + bool use_format_0 = false; }; // Test bench with all that is needed for the PUCCH. @@ -133,16 +135,18 @@ class test_bench du_ue_index_t main_ue_idx{du_ue_index_t::MIN_DU_UE_INDEX}; ue_repository ues; bool pucch_f2_more_prbs; + const bool use_format_0; // last_allocated_rnti keeps track of the last RNTI allocated. - rnti_t last_allocated_rnti; - du_ue_index_t last_allocated_ue_idx; - pucch_allocator_impl pucch_alloc; - uci_allocator_impl uci_alloc; - uci_scheduler_impl uci_sched; - slot_point sl_tx; - srslog::basic_logger& mac_logger = srslog::fetch_basic_logger("SCHED", true); - srslog::basic_logger& test_logger = srslog::fetch_basic_logger("TEST"); + rnti_t last_allocated_rnti; + du_ue_index_t last_allocated_ue_idx; + pucch_allocator_impl pucch_alloc; + uci_allocator_impl uci_alloc; + uci_scheduler_impl uci_sched; + slot_point sl_tx; + pucch_res_builder_test_helper pucch_builder; + srslog::basic_logger& mac_logger = srslog::fetch_basic_logger("SCHED", true); + srslog::basic_logger& test_logger = srslog::fetch_basic_logger("TEST"); }; } // namespace srsran From c6dd34b593b9f166d8b13b0a9d9da2add6b68c77 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Wed, 10 Jul 2024 19:13:26 +0200 Subject: [PATCH 05/54] du: add checks for PUCCH format 0 in validators Signed-off-by: Carlo Galiotto --- .../du_high/du_high_config_cli11_schema.cpp | 8 +++-- lib/du/du_update_config_helpers.cpp | 20 ++++++------ .../config/sched_cell_config_helpers.cpp | 31 ++++++++++++------- .../config/serving_cell_config_validator.cpp | 3 +- 4 files changed, 38 insertions(+), 24 deletions(-) diff --git a/apps/units/flexible_du/du_high/du_high_config_cli11_schema.cpp b/apps/units/flexible_du/du_high/du_high_config_cli11_schema.cpp index 0be5adaf42..ac47de8551 100644 --- a/apps/units/flexible_du/du_high/du_high_config_cli11_schema.cpp +++ b/apps/units/flexible_du/du_high/du_high_config_cli11_schema.cpp @@ -757,15 +757,17 @@ static void configure_cli11_pucch_args(CLI::App& app, du_high_unit_pucch_config& }); add_option(app, "--pucch_resource_common", - pucch_params.nof_cell_sr_resources, + pucch_params.pucch_resource_common, "Index of PUCCH resource set for the common configuration") ->capture_default_str() - ->check(CLI::Range(1, 15)); + ->check(CLI::Range(0, 15)); add_option(app, "--sr_period_ms", pucch_params.sr_period_msec, "SR period in msec") ->capture_default_str() ->check(CLI::IsMember({1.0F, 2.0F, 2.5F, 4.0F, 5.0F, 8.0F, 10.0F, 16.0F, 20.0F, 40.0F, 80.0F, 160.0F, 320.0F})); + add_option(app, "--use_format_0", pucch_params.use_format_0, "Use Format 0 for PUCCH resources from resource set 0") + ->capture_default_str(); add_option(app, - "--f1_nof_ue_res_harq", + "--f0_or_f1_nof_ue_res_harq", pucch_params.nof_ue_pucch_f0_or_f1_res_harq, "Number of PUCCH F0/F1 resources available per UE for HARQ") ->capture_default_str() diff --git a/lib/du/du_update_config_helpers.cpp b/lib/du/du_update_config_helpers.cpp index a2c0cec20d..5b42a07b1b 100644 --- a/lib/du/du_update_config_helpers.cpp +++ b/lib/du/du_update_config_helpers.cpp @@ -24,23 +24,25 @@ static unsigned greatest_used_rb_on_bwp_left_side(const pucch_resource& res, uns // in PRBs). auto is_on_bwp_left_side = [bwp_size](unsigned prb) { return prb < bwp_size / 2; }; - srsran_assert((res.format == srsran::pucch_format::FORMAT_1 and - std::holds_alternative(res.format_params)) or + srsran_assert((res.format == srsran::pucch_format::FORMAT_0 and + std::holds_alternative(res.format_params)) or + (res.format == srsran::pucch_format::FORMAT_1 and + std::holds_alternative(res.format_params)) or (res.format == srsran::pucch_format::FORMAT_2 or std::holds_alternative(res.format_params)), - "Only PUCCH Format 1 and 2 currently supported."); + "Only PUCCH Format 0, 1 and 2 currently supported."); unsigned max_rb_idx_on_left_side = 0; - if (res.format == srsran::pucch_format::FORMAT_1) { - const unsigned nof_prbs_f1 = 1U; + if (res.format == srsran::pucch_format::FORMAT_0 or res.format == srsran::pucch_format::FORMAT_1) { + const unsigned nof_prbs_f0_f1 = 1U; // Check if first hop and second hop separately. - if (is_on_bwp_left_side(res.starting_prb + nof_prbs_f1)) { - max_rb_idx_on_left_side = std::max(res.starting_prb + nof_prbs_f1, max_rb_idx_on_left_side); + if (is_on_bwp_left_side(res.starting_prb + nof_prbs_f0_f1)) { + max_rb_idx_on_left_side = std::max(res.starting_prb + nof_prbs_f0_f1, max_rb_idx_on_left_side); } - if (res.second_hop_prb.has_value() and is_on_bwp_left_side(res.second_hop_prb.value() + nof_prbs_f1)) { - max_rb_idx_on_left_side = std::max(res.second_hop_prb.value() + nof_prbs_f1, max_rb_idx_on_left_side); + if (res.second_hop_prb.has_value() and is_on_bwp_left_side(res.second_hop_prb.value() + nof_prbs_f0_f1)) { + max_rb_idx_on_left_side = std::max(res.second_hop_prb.value() + nof_prbs_f0_f1, max_rb_idx_on_left_side); } } if (res.format == srsran::pucch_format::FORMAT_2) { diff --git a/lib/scheduler/config/sched_cell_config_helpers.cpp b/lib/scheduler/config/sched_cell_config_helpers.cpp index e19f4c0756..ea625049a9 100644 --- a/lib/scheduler/config/sched_cell_config_helpers.cpp +++ b/lib/scheduler/config/sched_cell_config_helpers.cpp @@ -38,19 +38,28 @@ srsran::config_helpers::build_pucch_guardbands_list(const pucch_builder_params& }; for (const auto& pucch_res : res_list) { - srsran_assert(std::holds_alternative(pucch_res.format_params) or + srsran_assert(std::holds_alternative(pucch_res.format_params) or + std::holds_alternative(pucch_res.format_params) or std::holds_alternative(pucch_res.format_params), - "Only PUCCH format 1 and 2 are currently supported"); - const unsigned starting_sym = std::holds_alternative(pucch_res.format_params) - ? std::get(pucch_res.format_params).starting_sym_idx - : std::get(pucch_res.format_params).starting_sym_idx; - const unsigned nof_symbols = std::holds_alternative(pucch_res.format_params) - ? std::get(pucch_res.format_params).nof_symbols - : std::get(pucch_res.format_params).nof_symbols; + "Only PUCCH format 0, 1 and 2 are currently supported"); + + unsigned starting_sym = 0; + unsigned nof_symbols = 0; + if (std::holds_alternative(pucch_res.format_params)) { + starting_sym = std::get(pucch_res.format_params).starting_sym_idx; + nof_symbols = std::get(pucch_res.format_params).nof_symbols; + } else if (std::holds_alternative(pucch_res.format_params)) { + starting_sym = std::get(pucch_res.format_params).starting_sym_idx; + nof_symbols = std::get(pucch_res.format_params).nof_symbols; + } else { + starting_sym = std::get(pucch_res.format_params).starting_sym_idx; + nof_symbols = std::get(pucch_res.format_params).nof_symbols; + } + // For PUCCH format 1, the resource has 1 PRB only. - const unsigned nof_prbs = std::holds_alternative(pucch_res.format_params) - ? 1U - : std::get(pucch_res.format_params).nof_prbs; + const unsigned nof_prbs = std::holds_alternative(pucch_res.format_params) + ? std::get(pucch_res.format_params).nof_prbs + : 1U; // In the following, \c res_no_freq_hop contains the PRBs/symbols of the PUCCH resource with no frequency hopping, // or, if frequency hopping is enabled, the PRBs/symbols of the first hop. diff --git a/lib/scheduler/config/serving_cell_config_validator.cpp b/lib/scheduler/config/serving_cell_config_validator.cpp index 6e99db300c..cfdaf3e884 100644 --- a/lib/scheduler/config/serving_cell_config_validator.cpp +++ b/lib/scheduler/config/serving_cell_config_validator.cpp @@ -218,7 +218,8 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel VERIFY(pucch_cfg.pucch_res_list.end() != pucch_res_sr, "PUCCH cell res. id={} for SR could not be found in PUCCH resource list", pucch_cfg.sr_res_list.front().pucch_res_id.cell_res_id); - VERIFY(pucch_res_sr->format == pucch_format::FORMAT_1, "PUCCH resource used for SR is expected to be Format 1"); + VERIFY(pucch_res_sr->format == pucch_format::FORMAT_0 or pucch_res_sr->format == pucch_format::FORMAT_1, + "PUCCH resource used for SR is expected to be Format 1"); // Verify that the PUCCH setting used for CSI report have been configured properly. if (ue_cell_cfg.csi_meas_cfg.has_value()) { From f7e11608860bd38bc3dca16c4523d80ca3eb6a73 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Wed, 10 Jul 2024 19:41:12 +0200 Subject: [PATCH 06/54] phy: add PUCCH Format 0 as supported format Signed-off-by: Carlo Galiotto --- lib/phy/upper/uplink_processor_impl.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/phy/upper/uplink_processor_impl.cpp b/lib/phy/upper/uplink_processor_impl.cpp index 18510f8b0c..7e4b7a5c09 100644 --- a/lib/phy/upper/uplink_processor_impl.cpp +++ b/lib/phy/upper/uplink_processor_impl.cpp @@ -105,7 +105,8 @@ void uplink_processor_impl::process_pucch(upper_phy_rx_results_notifier& not { trace_point tp = l1_tracer.now(); - srsran_assert(pdu.context.format == pucch_format::FORMAT_1 || pdu.context.format == pucch_format::FORMAT_2, + srsran_assert(pdu.context.format == pucch_format::FORMAT_0 || pdu.context.format == pucch_format::FORMAT_1 || + pdu.context.format == pucch_format::FORMAT_2, "Currently supporting PUCCH Format 1 and 2 only."); pucch_processor_result proc_result; From 700bf0e72fc36eb67c7ff279301db186a4691fd9 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Thu, 11 Jul 2024 15:19:14 +0200 Subject: [PATCH 07/54] sched: add PUCCH format 0 in sched logger Signed-off-by: Carlo Galiotto --- lib/scheduler/logging/scheduler_result_logger.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/scheduler/logging/scheduler_result_logger.cpp b/lib/scheduler/logging/scheduler_result_logger.cpp index 7a274428fa..74a568be4f 100644 --- a/lib/scheduler/logging/scheduler_result_logger.cpp +++ b/lib/scheduler/logging/scheduler_result_logger.cpp @@ -249,7 +249,15 @@ void scheduler_result_logger::log_debug(const sched_result& result, std::chrono: } for (const pucch_info& pucch : result.ul.pucchs) { - if (pucch.format == pucch_format::FORMAT_1) { + if (pucch.format == pucch_format::FORMAT_0) { + const unsigned nof_harq_bits = pucch.format_0.harq_ack_nof_bits; + const unsigned nof_sr_bits = sr_nof_bits_to_uint(pucch.format_0.sr_bits); + fmt::format_to(fmtbuf, "\n- PUCCH: c-rnti={} format={} prb={}", pucch.crnti, pucch.format, pucch.resources.prbs); + if (not pucch.resources.second_hop_prbs.empty()) { + fmt::format_to(fmtbuf, " second_prbs={}", pucch.resources.second_hop_prbs); + } + fmt::format_to(fmtbuf, " symb={} uci: harq_bits={} sr={}", pucch.resources.symbols, nof_harq_bits, nof_sr_bits); + } else if (pucch.format == pucch_format::FORMAT_1) { const unsigned nof_harq_bits = pucch.format_1.harq_ack_nof_bits; const unsigned nof_sr_bits = sr_nof_bits_to_uint(pucch.format_1.sr_bits); fmt::format_to(fmtbuf, "\n- PUCCH: c-rnti={} format={} prb={}", pucch.crnti, pucch.format, pucch.resources.prbs); From de6fa686db414194f38fd22d3876e2ae1bf71a5b Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Fri, 12 Jul 2024 10:33:50 +0200 Subject: [PATCH 08/54] du: remove format 1 params when format 0 is used Signed-off-by: Carlo Galiotto --- .../units/flexible_du/du_high/du_high_config_yaml_writer.cpp | 1 + .../ran_resource_management/du_pucch_resource_manager.cpp | 5 ++++- lib/phy/upper/uplink_processor_impl.cpp | 2 +- lib/scheduler/config/serving_cell_config_validator.cpp | 2 +- lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp | 3 ++- .../scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp | 5 ++--- 6 files changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp b/apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp index d0cd8884a6..f73b512f68 100644 --- a/apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp +++ b/apps/units/flexible_du/du_high/du_high_config_yaml_writer.cpp @@ -408,6 +408,7 @@ static YAML::Node build_du_high_pucch_section(const du_high_unit_pucch_config& c node["p0_nominal"] = config.p0_nominal; node["pucch_resource_common"] = config.pucch_resource_common; + node["use_format_0"] = config.use_format_0; node["sr_period_ms"] = config.sr_period_msec; node["f0_or_f1_nof_ue_res_harq"] = config.nof_ue_pucch_f0_or_f1_res_harq; node["f0_or_f1_nof_cell_res_sr"] = config.nof_cell_sr_resources; diff --git a/lib/du_manager/ran_resource_management/du_pucch_resource_manager.cpp b/lib/du_manager/ran_resource_management/du_pucch_resource_manager.cpp index 2a99657013..6e98b88fa0 100644 --- a/lib/du_manager/ran_resource_management/du_pucch_resource_manager.cpp +++ b/lib/du_manager/ran_resource_management/du_pucch_resource_manager.cpp @@ -36,7 +36,10 @@ static bool csi_offset_exceeds_grant_cnt(unsigned offset_can // Helper that updates the starting PUCCH config with user-defined parameters. static pucch_config build_default_pucch_cfg(const pucch_config& pucch_cfg, const pucch_builder_params& user_params) { - pucch_config target_pucch_cfg = pucch_cfg; + pucch_config target_pucch_cfg = pucch_cfg; + if (not std::holds_alternative(user_params.f0_or_f1_params)) { + target_pucch_cfg.format_1_common_param.reset(); + } target_pucch_cfg.format_2_common_param.value().max_c_rate = user_params.f2_params.max_code_rate; return target_pucch_cfg; diff --git a/lib/phy/upper/uplink_processor_impl.cpp b/lib/phy/upper/uplink_processor_impl.cpp index 7e4b7a5c09..804da2ff7f 100644 --- a/lib/phy/upper/uplink_processor_impl.cpp +++ b/lib/phy/upper/uplink_processor_impl.cpp @@ -107,7 +107,7 @@ void uplink_processor_impl::process_pucch(upper_phy_rx_results_notifier& not srsran_assert(pdu.context.format == pucch_format::FORMAT_0 || pdu.context.format == pucch_format::FORMAT_1 || pdu.context.format == pucch_format::FORMAT_2, - "Currently supporting PUCCH Format 1 and 2 only."); + "Currently supporting PUCCH Format 0, 1 and 2 only."); pucch_processor_result proc_result; // Process the PUCCH. diff --git a/lib/scheduler/config/serving_cell_config_validator.cpp b/lib/scheduler/config/serving_cell_config_validator.cpp index cfdaf3e884..5e152add55 100644 --- a/lib/scheduler/config/serving_cell_config_validator.cpp +++ b/lib/scheduler/config/serving_cell_config_validator.cpp @@ -219,7 +219,7 @@ validator_result srsran::config_validators::validate_pucch_cfg(const serving_cel "PUCCH cell res. id={} for SR could not be found in PUCCH resource list", pucch_cfg.sr_res_list.front().pucch_res_id.cell_res_id); VERIFY(pucch_res_sr->format == pucch_format::FORMAT_0 or pucch_res_sr->format == pucch_format::FORMAT_1, - "PUCCH resource used for SR is expected to be Format 1"); + "PUCCH resource used for SR is expected to be Format 0 or Format 1"); // Verify that the PUCCH setting used for CSI report have been configured properly. if (ue_cell_cfg.csi_meas_cfg.has_value()) { diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp index 519350ffca..f14c37449b 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp @@ -1820,7 +1820,8 @@ pucch_allocator_impl::merge_pucch_resources(span Date: Thu, 18 Jul 2024 16:20:05 +0200 Subject: [PATCH 09/54] sched: remove format var from logs Signed-off-by: Carlo Galiotto --- .../units/flexible_du/du_high/du_high_config_cli11_schema.cpp | 2 +- lib/scheduler/logging/scheduler_result_logger.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/units/flexible_du/du_high/du_high_config_cli11_schema.cpp b/apps/units/flexible_du/du_high/du_high_config_cli11_schema.cpp index ac47de8551..99e5e0b698 100644 --- a/apps/units/flexible_du/du_high/du_high_config_cli11_schema.cpp +++ b/apps/units/flexible_du/du_high/du_high_config_cli11_schema.cpp @@ -767,7 +767,7 @@ static void configure_cli11_pucch_args(CLI::App& app, du_high_unit_pucch_config& add_option(app, "--use_format_0", pucch_params.use_format_0, "Use Format 0 for PUCCH resources from resource set 0") ->capture_default_str(); add_option(app, - "--f0_or_f1_nof_ue_res_harq", + "--f1_nof_ue_res_harq", pucch_params.nof_ue_pucch_f0_or_f1_res_harq, "Number of PUCCH F0/F1 resources available per UE for HARQ") ->capture_default_str() diff --git a/lib/scheduler/logging/scheduler_result_logger.cpp b/lib/scheduler/logging/scheduler_result_logger.cpp index 74a568be4f..c4cc30fc4f 100644 --- a/lib/scheduler/logging/scheduler_result_logger.cpp +++ b/lib/scheduler/logging/scheduler_result_logger.cpp @@ -252,7 +252,7 @@ void scheduler_result_logger::log_debug(const sched_result& result, std::chrono: if (pucch.format == pucch_format::FORMAT_0) { const unsigned nof_harq_bits = pucch.format_0.harq_ack_nof_bits; const unsigned nof_sr_bits = sr_nof_bits_to_uint(pucch.format_0.sr_bits); - fmt::format_to(fmtbuf, "\n- PUCCH: c-rnti={} format={} prb={}", pucch.crnti, pucch.format, pucch.resources.prbs); + fmt::format_to(fmtbuf, "\n- PUCCH: c-rnti={} format=0 prb={}", pucch.crnti, pucch.resources.prbs); if (not pucch.resources.second_hop_prbs.empty()) { fmt::format_to(fmtbuf, " second_prbs={}", pucch.resources.second_hop_prbs); } @@ -260,7 +260,7 @@ void scheduler_result_logger::log_debug(const sched_result& result, std::chrono: } else if (pucch.format == pucch_format::FORMAT_1) { const unsigned nof_harq_bits = pucch.format_1.harq_ack_nof_bits; const unsigned nof_sr_bits = sr_nof_bits_to_uint(pucch.format_1.sr_bits); - fmt::format_to(fmtbuf, "\n- PUCCH: c-rnti={} format={} prb={}", pucch.crnti, pucch.format, pucch.resources.prbs); + fmt::format_to(fmtbuf, "\n- PUCCH: c-rnti={} format=1 prb={}", pucch.crnti, pucch.resources.prbs); if (not pucch.resources.second_hop_prbs.empty()) { fmt::format_to(fmtbuf, " second_prbs={}", pucch.resources.second_hop_prbs); } From 3bb0d54800ffa1af202357cda4a4f1aa178703f8 Mon Sep 17 00:00:00 2001 From: asaezper Date: Thu, 18 Jul 2024 18:23:40 +0200 Subject: [PATCH 10/54] ci,e2e: amari zmq: add an extra wait between traffic and stop --- .gitlab/ci/e2e/.env | 2 +- tests/e2e/pyproject.toml | 2 +- tests/e2e/tests/iperf.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index d185555c50..215f1655ab 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -1,6 +1,6 @@ SRSGNB_REGISTRY_URI=registry.gitlab.com/softwareradiosystems/srsgnb RETINA_REGISTRY_PREFIX=registry.gitlab.com/softwareradiosystems/ci/retina -RETINA_VERSION=0.51.8 +RETINA_VERSION=0.51.9 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 diff --git a/tests/e2e/pyproject.toml b/tests/e2e/pyproject.toml index 211f283f61..c7b8084bb7 100644 --- a/tests/e2e/pyproject.toml +++ b/tests/e2e/pyproject.toml @@ -69,7 +69,7 @@ warn_return_any = true warn_unused_configs = true [tool.pylint] -disable = ["fixme", "no-name-in-module", "duplicate-code", "import-error"] +disable = ["no-name-in-module", "duplicate-code", "import-error"] ignore-signatures = true max-line-length = 120 diff --git a/tests/e2e/tests/iperf.py b/tests/e2e/tests/iperf.py index 181b0b4ca6..e25f7c62b6 100644 --- a/tests/e2e/tests/iperf.py +++ b/tests/e2e/tests/iperf.py @@ -68,7 +68,7 @@ { 20: int(43e6), 50: int(153e6), - 90: int(124e6), # TODO: update this value if lates are gone + 90: int(124e6), }, ) From 1a6cb1ca806241087c8c7de376bef1253c5b6387 Mon Sep 17 00:00:00 2001 From: Alejandro Leal Date: Thu, 11 Jul 2024 09:42:27 +0200 Subject: [PATCH 11/54] config: added property ru_timing_cpu to affinities Configure the OFH rx executors with the low priority bitmask --- apps/services/worker_manager.cpp | 19 ++++++++++++------- apps/services/worker_manager.h | 1 + .../flexible_du/split_7_2/ru_ofh_config.h | 2 ++ .../split_7_2/ru_ofh_config_cli11_schema.cpp | 8 ++++++++ .../split_7_2/ru_ofh_config_yaml_writer.cpp | 5 +++++ 5 files changed, 28 insertions(+), 7 deletions(-) diff --git a/apps/services/worker_manager.cpp b/apps/services/worker_manager.cpp index 05e731b038..9f0865e3ec 100644 --- a/apps/services/worker_manager.cpp +++ b/apps/services/worker_manager.cpp @@ -49,6 +49,10 @@ worker_manager::worker_manager(const dynamic_du_unit_config& du_cfg, unsigned gtpu_queue_size) : low_prio_affinity_mng({expert_appcfg.affinities.low_priority_cpu_cfg}) { + if (std::holds_alternative(du_cfg.ru_cfg)) { + ru_timing_mask = std::get(du_cfg.ru_cfg).config.expert_execution_cfg.ru_timing_cpu; + } + const unsigned nof_cells = du_cfg.du_high_cfg.config.expert_execution_cfg.cell_affinities.size(); for (unsigned i = 0, e = nof_cells; i != e; ++i) { std::variant affinity_mng; diff --git a/apps/units/flexible_du/split_7_2/ru_ofh_config.h b/apps/units/flexible_du/split_7_2/ru_ofh_config.h index fdabc04b5a..2e7005b9ca 100644 --- a/apps/units/flexible_du/split_7_2/ru_ofh_config.h +++ b/apps/units/flexible_du/split_7_2/ru_ofh_config.h @@ -125,6 +125,8 @@ struct ru_ofh_unit_expert_threads_config { /// Expert configuration. struct ru_ofh_unit_expert_execution_config { + /// RU timing thread. + os_sched_affinity_bitmask ru_timing_cpu; /// Expert thread configuration of the Open Fronthaul Radio Unit. ru_ofh_unit_expert_threads_config threads; /// CPU affinities per cell. diff --git a/apps/units/flexible_du/split_7_2/ru_ofh_config_cli11_schema.cpp b/apps/units/flexible_du/split_7_2/ru_ofh_config_cli11_schema.cpp index 923350945e..26fb6bb17d 100644 --- a/apps/units/flexible_du/split_7_2/ru_ofh_config_cli11_schema.cpp +++ b/apps/units/flexible_du/split_7_2/ru_ofh_config_cli11_schema.cpp @@ -271,6 +271,14 @@ static void configure_cli11_ofh_threads_args(CLI::App& app, ru_ofh_unit_expert_t static void configure_cli11_expert_execution_args(CLI::App& app, ru_ofh_unit_expert_execution_config& config) { + // Affinity section. + CLI::App* affinities_subcmd = add_subcommand(app, "affinities", "gNB CPU affinities configuration")->configurable(); + add_option_function( + *affinities_subcmd, + "--ru_timing_cpu", + [&config](const std::string& value) { parse_affinity_mask(config.ru_timing_cpu, value, "ru_timing_cpu"); }, + "CPU used for timing in the Radio Unit"); + // Threads section. CLI::App* threads_subcmd = add_subcommand(app, "threads", "Threads configuration")->configurable(); diff --git a/apps/units/flexible_du/split_7_2/ru_ofh_config_yaml_writer.cpp b/apps/units/flexible_du/split_7_2/ru_ofh_config_yaml_writer.cpp index 28153d42f5..81b2095bd4 100644 --- a/apps/units/flexible_du/split_7_2/ru_ofh_config_yaml_writer.cpp +++ b/apps/units/flexible_du/split_7_2/ru_ofh_config_yaml_writer.cpp @@ -20,6 +20,11 @@ static void fill_ru_ofh_log_section(YAML::Node node, const ru_ofh_unit_logger_co static void fill_ru_ofh_expert_execution_section(YAML::Node node, const ru_ofh_unit_expert_execution_config& config) { + { + YAML::Node affinities_node = node["affinities"]; + affinities_node["ru_timing_cpu"] = fmt::format("{:,}", span(config.ru_timing_cpu.get_cpu_ids())); + } + { YAML::Node threads_node = node["threads"]; YAML::Node ofh_node = threads_node["ofh"]; From 37a4608e4781904153b8f0aee27baa567644c001 Mon Sep 17 00:00:00 2001 From: sauka Date: Thu, 18 Jul 2024 13:43:36 +0300 Subject: [PATCH 12/54] ofh: decompression returns cbf16_t samples --- .../srsran/ofh/compression/iq_decompressor.h | 7 ++-- .../ofh_uplane_message_decoder_properties.h | 2 +- .../compression/iq_compression_bfp_avx2.cpp | 6 ++-- lib/ofh/compression/iq_compression_bfp_avx2.h | 2 +- .../compression/iq_compression_bfp_avx512.cpp | 6 ++-- .../compression/iq_compression_bfp_avx512.h | 2 +- .../compression/iq_compression_bfp_impl.cpp | 6 ++-- lib/ofh/compression/iq_compression_bfp_impl.h | 4 +-- .../compression/iq_compression_bfp_neon.cpp | 10 +++--- lib/ofh/compression/iq_compression_bfp_neon.h | 2 +- .../compression/iq_compression_death_impl.cpp | 2 +- .../compression/iq_compression_death_impl.h | 2 +- .../compression/iq_compression_none_avx2.cpp | 10 +++--- .../compression/iq_compression_none_avx2.h | 2 +- .../iq_compression_none_avx512.cpp | 10 +++--- .../compression/iq_compression_none_avx512.h | 2 +- .../compression/iq_compression_none_impl.cpp | 2 +- .../compression/iq_compression_none_impl.h | 2 +- .../compression/iq_compression_none_neon.cpp | 10 +++--- .../compression/iq_compression_none_neon.h | 2 +- .../compression/iq_decompressor_selector.cpp | 2 +- .../compression/iq_decompressor_selector.h | 2 +- lib/ofh/compression/quantizer.h | 14 ++++++++ ...h_uplane_prach_symbol_data_flow_writer.cpp | 9 ++++-- .../ofh_uplane_rx_symbol_data_flow_writer.cpp | 11 ++++--- lib/ofh/support/uplink_context_repository.h | 9 +++--- lib/srsvec/conversion.cpp | 2 +- .../ofh/ofh_compression_benchmark.cpp | 2 +- .../ofh/compression/ofh_compression_test.cpp | 27 ++++++++++------ .../ofh_iq_decompressor_test_doubles.h | 2 +- tests/unittests/ofh/receiver/helpers.h | 32 ++++++++++++++++--- ...data_flow_uplane_uplink_data_impl_test.cpp | 2 +- ...lane_rx_symbol_data_flow_notifier_test.cpp | 6 ++-- ...uplane_rx_symbol_data_flow_writer_test.cpp | 2 +- ...plane_packet_decoder_dynamic_impl_test.cpp | 2 +- ...uplane_packet_decoder_static_impl_test.cpp | 2 +- 36 files changed, 136 insertions(+), 81 deletions(-) diff --git a/include/srsran/ofh/compression/iq_decompressor.h b/include/srsran/ofh/compression/iq_decompressor.h index 53a61d12be..d5c5ba57e5 100644 --- a/include/srsran/ofh/compression/iq_decompressor.h +++ b/include/srsran/ofh/compression/iq_decompressor.h @@ -30,13 +30,14 @@ class iq_decompressor /// \brief Decompress received compressed PRBs. /// /// Decompresses compressed PRBs from the input buffer according to received compression parameters and puts the - /// results into an array of floating point IQ samples. + /// results into an array of brain floating point IQ samples. /// /// \param[out] iq_data Resulting IQ samples after decompression. /// \param[in] compressed_prbs A span containing received compressed PRBs. /// \param[in] params Compression parameters. - virtual void - decompress(span iq_data, span compressed_prbs, const ru_compression_params& params) = 0; + virtual void decompress(span iq_data, + span compressed_prbs, + const ru_compression_params& params) = 0; }; } // namespace ofh diff --git a/include/srsran/ofh/serdes/ofh_uplane_message_decoder_properties.h b/include/srsran/ofh/serdes/ofh_uplane_message_decoder_properties.h index bc7740bddc..2739f39337 100644 --- a/include/srsran/ofh/serdes/ofh_uplane_message_decoder_properties.h +++ b/include/srsran/ofh/serdes/ofh_uplane_message_decoder_properties.h @@ -43,7 +43,7 @@ struct uplane_section_params { /// \note For simplicity, all the PRBs use the same compression parameters. std::optional ud_comp_param; /// IQ samples for the number of PRBs indicated by \c nof_prbs. - static_vector iq_samples; + static_vector iq_samples; }; /// Open Fronthaul User-Plane message decoder results. diff --git a/lib/ofh/compression/iq_compression_bfp_avx2.cpp b/lib/ofh/compression/iq_compression_bfp_avx2.cpp index 1b80eb4406..de4a2de91d 100644 --- a/lib/ofh/compression/iq_compression_bfp_avx2.cpp +++ b/lib/ofh/compression/iq_compression_bfp_avx2.cpp @@ -81,7 +81,7 @@ void iq_compression_bfp_avx2::compress(span output, } } -void iq_compression_bfp_avx2::decompress(span output, +void iq_compression_bfp_avx2::decompress(span output, span input, const ru_compression_params& params) { @@ -106,11 +106,11 @@ void iq_compression_bfp_avx2::decompress(span output, // Unpack resource block. mm256::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); - span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); + span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); span unpacked_span(unpacked_iq_data.data(), NOF_SUBCARRIERS_PER_RB * 2); // Convert to complex samples. - q_out.to_float(output_span, unpacked_span, scaler); + q_out.to_brain_float(output_span, unpacked_span, scaler); out_idx += NOF_SUBCARRIERS_PER_RB; } } diff --git a/lib/ofh/compression/iq_compression_bfp_avx2.h b/lib/ofh/compression/iq_compression_bfp_avx2.h index 9148761bf0..04479ad5a1 100644 --- a/lib/ofh/compression/iq_compression_bfp_avx2.h +++ b/lib/ofh/compression/iq_compression_bfp_avx2.h @@ -29,7 +29,7 @@ class iq_compression_bfp_avx2 : public iq_compression_bfp_impl void compress(span output, span input, const ru_compression_params& params) override; // See interface for the documentation. - void decompress(span output, span input, const ru_compression_params& params) override; + void decompress(span output, span input, const ru_compression_params& params) override; }; } // namespace ofh diff --git a/lib/ofh/compression/iq_compression_bfp_avx512.cpp b/lib/ofh/compression/iq_compression_bfp_avx512.cpp index 15680b922e..98b4ed782d 100644 --- a/lib/ofh/compression/iq_compression_bfp_avx512.cpp +++ b/lib/ofh/compression/iq_compression_bfp_avx512.cpp @@ -123,7 +123,7 @@ void iq_compression_bfp_avx512::compress(span output, } } -void iq_compression_bfp_avx512::decompress(span output, +void iq_compression_bfp_avx512::decompress(span output, span input, const ru_compression_params& params) { @@ -148,11 +148,11 @@ void iq_compression_bfp_avx512::decompress(span output, // Unpack resource block. mm512::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); - span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); + span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); span unpacked_span(unpacked_iq_data.data(), NOF_SUBCARRIERS_PER_RB * 2); // Convert to complex samples. - q_out.to_float(output_span, unpacked_span, scaler); + q_out.to_brain_float(output_span, unpacked_span, scaler); out_idx += NOF_SUBCARRIERS_PER_RB; } } diff --git a/lib/ofh/compression/iq_compression_bfp_avx512.h b/lib/ofh/compression/iq_compression_bfp_avx512.h index 714e7c732b..2323fb8307 100644 --- a/lib/ofh/compression/iq_compression_bfp_avx512.h +++ b/lib/ofh/compression/iq_compression_bfp_avx512.h @@ -29,7 +29,7 @@ class iq_compression_bfp_avx512 : public iq_compression_bfp_impl void compress(span output, span input, const ru_compression_params& params) override; // See interface for the documentation. - void decompress(span output, span input, const ru_compression_params& params) override; + void decompress(span output, span input, const ru_compression_params& params) override; }; } // namespace ofh diff --git a/lib/ofh/compression/iq_compression_bfp_impl.cpp b/lib/ofh/compression/iq_compression_bfp_impl.cpp index 0ee7078787..b28a783f8b 100644 --- a/lib/ofh/compression/iq_compression_bfp_impl.cpp +++ b/lib/ofh/compression/iq_compression_bfp_impl.cpp @@ -83,7 +83,7 @@ void iq_compression_bfp_impl::compress(span output, } } -void iq_compression_bfp_impl::decompress_prb_generic(span output, +void iq_compression_bfp_impl::decompress_prb_generic(span output, const compressed_prb& c_prb, const quantizer& q_in, unsigned data_width) @@ -106,7 +106,7 @@ void iq_compression_bfp_impl::decompress_prb_generic(span outpu } } -void iq_compression_bfp_impl::decompress(span output, +void iq_compression_bfp_impl::decompress(span output, span input, const ru_compression_params& params) { @@ -115,7 +115,7 @@ void iq_compression_bfp_impl::decompress(span output, unsigned out_idx = 0; for (const auto& c_prb : input) { - span out_rb_samples = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); + span out_rb_samples = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); // Decompress resource block. decompress_prb_generic(out_rb_samples, c_prb, q_in, params.data_width); out_idx += NOF_SUBCARRIERS_PER_RB; diff --git a/lib/ofh/compression/iq_compression_bfp_impl.h b/lib/ofh/compression/iq_compression_bfp_impl.h index 027ca68ac0..ad19e646a6 100644 --- a/lib/ofh/compression/iq_compression_bfp_impl.h +++ b/lib/ofh/compression/iq_compression_bfp_impl.h @@ -34,7 +34,7 @@ class iq_compression_bfp_impl : public iq_compressor, public iq_decompressor // See interface for the documentation. virtual void - decompress(span output, span input, const ru_compression_params& params) override; + decompress(span output, span input, const ru_compression_params& params) override; protected: /// Number of quantized samples per resource block. @@ -80,7 +80,7 @@ class iq_compression_bfp_impl : public iq_compressor, public iq_decompressor /// \param[in] q Quantizer object. /// \param data_width Bit width of compressed samples. static void - decompress_prb_generic(span output, const compressed_prb& c_prb, const quantizer& q, unsigned data_width); + decompress_prb_generic(span output, const compressed_prb& c_prb, const quantizer& q, unsigned data_width); /// Quantizes complex float samples using the specified bit width. /// diff --git a/lib/ofh/compression/iq_compression_bfp_neon.cpp b/lib/ofh/compression/iq_compression_bfp_neon.cpp index 4bc21e775e..004ae68a17 100644 --- a/lib/ofh/compression/iq_compression_bfp_neon.cpp +++ b/lib/ofh/compression/iq_compression_bfp_neon.cpp @@ -187,9 +187,9 @@ void iq_compression_bfp_neon::compress(span output, } } -void iq_compression_bfp_neon::decompress(span output, - span input, - const srsran::ofh::ru_compression_params& params) +void iq_compression_bfp_neon::decompress(span output, + span input, + const ru_compression_params& params) { // Use generic implementation if NEON utils don't support requested bit width. if (!neon::iq_width_packing_supported(params.data_width)) { @@ -212,11 +212,11 @@ void iq_compression_bfp_neon::decompress(span // Unpack resource block. neon::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); - span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); + span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); span unpacked_span(unpacked_iq_data.data(), NOF_SUBCARRIERS_PER_RB * 2); // Convert to complex samples. - q_out.to_float(output_span, unpacked_span, scaler); + q_out.to_brain_float(output_span, unpacked_span, scaler); out_idx += NOF_SUBCARRIERS_PER_RB; } } diff --git a/lib/ofh/compression/iq_compression_bfp_neon.h b/lib/ofh/compression/iq_compression_bfp_neon.h index 3bbac94086..c2cb59dce7 100644 --- a/lib/ofh/compression/iq_compression_bfp_neon.h +++ b/lib/ofh/compression/iq_compression_bfp_neon.h @@ -29,7 +29,7 @@ class iq_compression_bfp_neon : public iq_compression_bfp_impl void compress(span output, span input, const ru_compression_params& params) override; // See interface for the documentation. - void decompress(span output, span input, const ru_compression_params& params) override; + void decompress(span output, span input, const ru_compression_params& params) override; }; } // namespace ofh diff --git a/lib/ofh/compression/iq_compression_death_impl.cpp b/lib/ofh/compression/iq_compression_death_impl.cpp index a576fa1feb..35646b9456 100644 --- a/lib/ofh/compression/iq_compression_death_impl.cpp +++ b/lib/ofh/compression/iq_compression_death_impl.cpp @@ -21,7 +21,7 @@ void iq_compression_death_impl::compress(span compressed report_error("Compression type '{}' is not supported", to_string(params.type)); } -void iq_compression_death_impl::decompress(span iq_data, +void iq_compression_death_impl::decompress(span iq_data, span compressed_prbs, const ru_compression_params& params) { diff --git a/lib/ofh/compression/iq_compression_death_impl.h b/lib/ofh/compression/iq_compression_death_impl.h index 96fc3dcd1f..cbaffed93e 100644 --- a/lib/ofh/compression/iq_compression_death_impl.h +++ b/lib/ofh/compression/iq_compression_death_impl.h @@ -28,7 +28,7 @@ class iq_compression_death_impl : public iq_compressor, public iq_decompressor const ru_compression_params& params) override; // See interface for documentation. - void decompress(span iq_data, + void decompress(span iq_data, span compressed_prbs, const ru_compression_params& params) override; }; diff --git a/lib/ofh/compression/iq_compression_none_avx2.cpp b/lib/ofh/compression/iq_compression_none_avx2.cpp index 99b1740d07..8abec79574 100644 --- a/lib/ofh/compression/iq_compression_none_avx2.cpp +++ b/lib/ofh/compression/iq_compression_none_avx2.cpp @@ -73,9 +73,9 @@ void iq_compression_none_avx2::compress(span output, } } -void iq_compression_none_avx2::decompress(span output, - span input, - const srsran::ofh::ru_compression_params& params) +void iq_compression_none_avx2::decompress(span output, + span input, + const ru_compression_params& params) { // Use generic implementation if AVX2 utils don't support requested bit width. if (!mm256::iq_width_packing_supported(params.data_width)) { @@ -95,11 +95,11 @@ void iq_compression_none_avx2::decompress(span // Unpack resource block. mm256::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); - span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); + span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); span unpacked_span(unpacked_iq_data.data(), NOF_SUBCARRIERS_PER_RB * 2); // Convert to complex samples. - q.to_float(output_span, unpacked_span, 1); + q.to_brain_float(output_span, unpacked_span, 1); out_idx += NOF_SUBCARRIERS_PER_RB; } } diff --git a/lib/ofh/compression/iq_compression_none_avx2.h b/lib/ofh/compression/iq_compression_none_avx2.h index 241c1f8f68..75146657fb 100644 --- a/lib/ofh/compression/iq_compression_none_avx2.h +++ b/lib/ofh/compression/iq_compression_none_avx2.h @@ -29,7 +29,7 @@ class iq_compression_none_avx2 : public iq_compression_none_impl void compress(span output, span input, const ru_compression_params& params) override; // See interface for the documentation. - void decompress(span output, span input, const ru_compression_params& params) override; + void decompress(span output, span input, const ru_compression_params& params) override; }; } // namespace ofh diff --git a/lib/ofh/compression/iq_compression_none_avx512.cpp b/lib/ofh/compression/iq_compression_none_avx512.cpp index 81d50fc870..00bdd83246 100644 --- a/lib/ofh/compression/iq_compression_none_avx512.cpp +++ b/lib/ofh/compression/iq_compression_none_avx512.cpp @@ -59,9 +59,9 @@ void iq_compression_none_avx512::compress(span output, } } -void iq_compression_none_avx512::decompress(span output, - span input, - const srsran::ofh::ru_compression_params& params) +void iq_compression_none_avx512::decompress(span output, + span input, + const ru_compression_params& params) { // Use generic implementation if AVX512 utils don't support requested bit width. if (!mm512::iq_width_packing_supported(params.data_width)) { @@ -78,11 +78,11 @@ void iq_compression_none_avx512::decompress(span // Unpack resource block. mm512::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); - span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); + span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); span unpacked_span(unpacked_iq_data.data(), NOF_SUBCARRIERS_PER_RB * 2); // Convert to complex samples. - q.to_float(output_span, unpacked_span, 1); + q.to_brain_float(output_span, unpacked_span, 1); out_idx += NOF_SUBCARRIERS_PER_RB; } } diff --git a/lib/ofh/compression/iq_compression_none_avx512.h b/lib/ofh/compression/iq_compression_none_avx512.h index b7a8f22875..6dcb60301e 100644 --- a/lib/ofh/compression/iq_compression_none_avx512.h +++ b/lib/ofh/compression/iq_compression_none_avx512.h @@ -29,7 +29,7 @@ class iq_compression_none_avx512 : public iq_compression_none_impl void compress(span output, span input, const ru_compression_params& params) override; // See interface for the documentation. - void decompress(span output, span input, const ru_compression_params& params) override; + void decompress(span output, span input, const ru_compression_params& params) override; }; } // namespace ofh diff --git a/lib/ofh/compression/iq_compression_none_impl.cpp b/lib/ofh/compression/iq_compression_none_impl.cpp index 5888745a99..f2dd72253b 100644 --- a/lib/ofh/compression/iq_compression_none_impl.cpp +++ b/lib/ofh/compression/iq_compression_none_impl.cpp @@ -41,7 +41,7 @@ void iq_compression_none_impl::compress(span output, } } -void iq_compression_none_impl::decompress(span output, +void iq_compression_none_impl::decompress(span output, span input, const ru_compression_params& params) { diff --git a/lib/ofh/compression/iq_compression_none_impl.h b/lib/ofh/compression/iq_compression_none_impl.h index d55af0ddc0..54a654515c 100644 --- a/lib/ofh/compression/iq_compression_none_impl.h +++ b/lib/ofh/compression/iq_compression_none_impl.h @@ -33,7 +33,7 @@ class iq_compression_none_impl : public iq_compressor, public iq_decompressor // See interface for the documentation. virtual void - decompress(span output, span input, const ru_compression_params& params) override; + decompress(span output, span input, const ru_compression_params& params) override; protected: /// \brief Prints to the log the root mean square (RMS) value of the given samples. diff --git a/lib/ofh/compression/iq_compression_none_neon.cpp b/lib/ofh/compression/iq_compression_none_neon.cpp index bb77888f50..d2925ab929 100644 --- a/lib/ofh/compression/iq_compression_none_neon.cpp +++ b/lib/ofh/compression/iq_compression_none_neon.cpp @@ -95,9 +95,9 @@ void iq_compression_none_neon::compress(span } } -void iq_compression_none_neon::decompress(span output, - span input, - const srsran::ofh::ru_compression_params& params) +void iq_compression_none_neon::decompress(span output, + span input, + const ru_compression_params& params) { // Use generic implementation if NEON utils don't support requested bit width. if (!neon::iq_width_packing_supported(params.data_width)) { @@ -113,9 +113,9 @@ void iq_compression_none_neon::decompress(span std::array unpacked_iq_data; neon::unpack_prb_big_endian(unpacked_iq_data, c_prb.get_packed_data(), params.data_width); - span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); + span output_span = output.subspan(out_idx, NOF_SUBCARRIERS_PER_RB); // Convert to complex samples. - q_out.to_float(output_span, unpacked_iq_data, 1); + q_out.to_brain_float(output_span, unpacked_iq_data, 1); out_idx += NOF_SUBCARRIERS_PER_RB; } } diff --git a/lib/ofh/compression/iq_compression_none_neon.h b/lib/ofh/compression/iq_compression_none_neon.h index 15b35cf2ff..b91440e04c 100644 --- a/lib/ofh/compression/iq_compression_none_neon.h +++ b/lib/ofh/compression/iq_compression_none_neon.h @@ -29,7 +29,7 @@ class iq_compression_none_neon : public iq_compression_none_impl void compress(span output, span input, const ru_compression_params& params) override; // See interface for the documentation. - void decompress(span output, span input, const ru_compression_params& params) override; + void decompress(span output, span input, const ru_compression_params& params) override; }; } // namespace ofh diff --git a/lib/ofh/compression/iq_decompressor_selector.cpp b/lib/ofh/compression/iq_decompressor_selector.cpp index f21afe6b33..68147683e6 100644 --- a/lib/ofh/compression/iq_decompressor_selector.cpp +++ b/lib/ofh/compression/iq_decompressor_selector.cpp @@ -26,7 +26,7 @@ iq_decompressor_selector::iq_decompressor_selector( } } -void iq_decompressor_selector::decompress(span iq_data, +void iq_decompressor_selector::decompress(span iq_data, span compressed_prbs, const ru_compression_params& params) { diff --git a/lib/ofh/compression/iq_decompressor_selector.h b/lib/ofh/compression/iq_decompressor_selector.h index 043e13bec6..e54a85bd79 100644 --- a/lib/ofh/compression/iq_decompressor_selector.h +++ b/lib/ofh/compression/iq_decompressor_selector.h @@ -26,7 +26,7 @@ class iq_decompressor_selector : public iq_decompressor std::array, NOF_COMPRESSION_TYPES_SUPPORTED> decompressors_); // See interface for documentation. - void decompress(span iq_data, + void decompress(span iq_data, span compressed_prbs, const ru_compression_params& params) override; diff --git a/lib/ofh/compression/quantizer.h b/lib/ofh/compression/quantizer.h index 9b8daa7404..f0d379d9d1 100644 --- a/lib/ofh/compression/quantizer.h +++ b/lib/ofh/compression/quantizer.h @@ -96,6 +96,20 @@ class quantizer srsvec::convert(x, scale, z); } + /// \brief Converts a sequence of fixed point values to complex brain floating point values. + /// + /// \param[out] z Resultant complex brain floating point values. + /// \param[in] x Sequence of 16-bit integer values. + /// \param[in] in_scale Scaling factor (expected to be bigger or equal to 1) applied to the input prior conversion. + /// + /// \remark The size of \c x must be twice the size of \c z as \x is comprised by the quantized pairs of real and + /// imaginary parts of complex values. + void to_brain_float(span z, span x, int16_t in_scale) const + { + float scale = gain / in_scale; + srsvec::convert(z, x, scale); + } + /// Sign extends the input value. int16_t sign_extend(int16_t value) const { diff --git a/lib/ofh/receiver/ofh_uplane_prach_symbol_data_flow_writer.cpp b/lib/ofh/receiver/ofh_uplane_prach_symbol_data_flow_writer.cpp index d0ac4730cb..3a9544bb8a 100644 --- a/lib/ofh/receiver/ofh_uplane_prach_symbol_data_flow_writer.cpp +++ b/lib/ofh/receiver/ofh_uplane_prach_symbol_data_flow_writer.cpp @@ -10,6 +10,7 @@ #include "ofh_uplane_prach_symbol_data_flow_writer.h" #include "srsran/ofh/serdes/ofh_uplane_message_decoder_properties.h" +#include "srsran/srsvec/conversion.h" using namespace srsran; using namespace ofh; @@ -17,6 +18,8 @@ using namespace ofh; void uplane_prach_symbol_data_flow_writer::write_to_prach_buffer(unsigned eaxc, const uplane_message_decoder_results& results) { + std::array conv_buffer; + slot_point slot = results.params.slot; prach_context prach_context = prach_context_repo->get(slot); @@ -89,10 +92,12 @@ void uplane_prach_symbol_data_flow_writer::write_to_prach_buffer(unsigned unsigned iq_size_re = std::min(section_nof_re, prach_nof_res); // Grab the data. - span prach_in_data = span(section.iq_samples).subspan(iq_start_re, iq_size_re); + span prach_in_data_cbf16 = span(section.iq_samples).subspan(iq_start_re, iq_size_re); + span prach_in_data_cf(conv_buffer.data(), prach_in_data_cbf16.size()); + srsvec::convert(prach_in_data_cf, prach_in_data_cbf16); // Copy the data in the buffer. - prach_context_repo->write_iq(slot, port, results.params.symbol_id, start_re, prach_in_data); + prach_context_repo->write_iq(slot, port, results.params.symbol_id, start_re, prach_in_data_cf); logger.debug("Handling PRACH in slot '{}', symbol '{}' and port '{}'", slot, results.params.symbol_id, port); } diff --git a/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_writer.cpp b/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_writer.cpp index d01a89fddf..691ca53416 100644 --- a/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_writer.cpp +++ b/lib/ofh/receiver/ofh_uplane_rx_symbol_data_flow_writer.cpp @@ -60,11 +60,12 @@ void uplane_rx_symbol_data_flow_writer::write_to_resource_grid(unsigned trace_point write_rg_tp = ofh_tracer.now(); - ul_context_repo->write_grid(slot, - rg_port, - symbol, - section.start_prb * NOF_SUBCARRIERS_PER_RB, - span(section.iq_samples).first(nof_prbs_to_write * NOF_SUBCARRIERS_PER_RB)); + ul_context_repo->write_grid( + slot, + rg_port, + symbol, + section.start_prb * NOF_SUBCARRIERS_PER_RB, + span(section.iq_samples).first(nof_prbs_to_write * NOF_SUBCARRIERS_PER_RB)); ofh_tracer << trace_event("ofh_receiver_write_rg", write_rg_tp); diff --git a/lib/ofh/support/uplink_context_repository.h b/lib/ofh/support/uplink_context_repository.h index a741077c2d..35e8864a62 100644 --- a/lib/ofh/support/uplink_context_repository.h +++ b/lib/ofh/support/uplink_context_repository.h @@ -21,6 +21,7 @@ #include "srsran/ran/resource_allocation/ofdm_symbol_range.h" #include "srsran/ran/resource_block.h" #include "srsran/srslog/srslog.h" +#include "srsran/srsvec/copy.h" #include namespace srsran { @@ -65,7 +66,7 @@ class uplink_context span> get_re_written_mask() const { return re_written; } /// Writes the given RE IQ buffer into the port and start RE. - void write_grid(unsigned port, unsigned start_re, span re_iq_buffer) + void write_grid(unsigned port, unsigned start_re, span re_iq_buffer) { srsran_assert(grid.grid, "Invalid resource grid"); @@ -73,8 +74,8 @@ class uplink_context if (port >= grid.grid->get_writer().get_nof_ports()) { return; } - - grid.grid->get_writer().put(port, symbol, start_re, re_iq_buffer); + span grid_view = grid.grid->get_writer().get_view(port, symbol).subspan(start_re, re_iq_buffer.size()); + srsvec::copy(grid_view, re_iq_buffer); re_written[port].fill(start_re, start_re + re_iq_buffer.size()); } @@ -173,7 +174,7 @@ class uplink_context_repository } /// Writes to the grid at the given slot, port, symbol and start resource element the given IQ buffer. - void write_grid(slot_point slot, unsigned port, unsigned symbol, unsigned start_re, span re_iq_buffer) + void write_grid(slot_point slot, unsigned port, unsigned symbol, unsigned start_re, span re_iq_buffer) { std::lock_guard lock(mutex); entry(slot, symbol).write_grid(port, start_re, re_iq_buffer); diff --git a/lib/srsvec/conversion.cpp b/lib/srsvec/conversion.cpp index bd82e11862..d1897e8493 100644 --- a/lib/srsvec/conversion.cpp +++ b/lib/srsvec/conversion.cpp @@ -371,7 +371,7 @@ void srsran::srsvec::convert(span z, span x, float scale { srsran_assert(x.size() == 2 * z.size(), "Invalid input or output span sizes"); - convert_int16_to_bf16_simd(reinterpret_cast(z.data()), x.data(), scale, z.size()); + convert_int16_to_bf16_simd(reinterpret_cast(z.data()), x.data(), scale, x.size()); } void srsran::srsvec::convert(span z, span x, float scale) diff --git a/tests/benchmarks/ofh/ofh_compression_benchmark.cpp b/tests/benchmarks/ofh/ofh_compression_benchmark.cpp index a61b07f962..167ca92d0f 100644 --- a/tests/benchmarks/ofh/ofh_compression_benchmark.cpp +++ b/tests/benchmarks/ofh/ofh_compression_benchmark.cpp @@ -187,7 +187,7 @@ int main(int argc, char** argv) std::string meas_descr_decompression = common_meas_name + " decompression"; std::vector> test_data(nof_ports); - std::vector> decompressed_data(nof_ports); + std::vector> decompressed_data(nof_ports); std::vector> compressed_data(nof_ports); for (unsigned i = 0; i != nof_ports; ++i) { test_data[i].resize(nof_prbs * NOF_SUBCARRIERS_PER_RB); diff --git a/tests/unittests/ofh/compression/ofh_compression_test.cpp b/tests/unittests/ofh/compression/ofh_compression_test.cpp index df33c08ee4..d7100eda1e 100644 --- a/tests/unittests/ofh/compression/ofh_compression_test.cpp +++ b/tests/unittests/ofh/compression/ofh_compression_test.cpp @@ -85,7 +85,7 @@ TEST_P(OFHCompressionFixture, match_test_case_result_and_decompress_to_original) // Prepare vectors to store compression/decompression results. std::vector compressed_data(nof_prb); - std::vector decompressed_data(nof_prb * NOF_SUBCARRIERS_PER_RB); + std::vector decompressed_data(nof_prb * NOF_SUBCARRIERS_PER_RB); // Compress input test data. compressor->compress(compressed_data, test_data_cbf16, params); @@ -114,14 +114,21 @@ TEST_P(OFHCompressionFixture, match_test_case_result_and_decompress_to_original) // Check resulting samples versus the original ones considering also a precision loss caused by initial // single-precision float to brain float conversion. - float resolution = 2.0F / (1 << (params.data_width - 1)) + 1 / 256.0F / 2; - ASSERT_TRUE(std::equal(test_data.begin(), - test_data.end(), - decompressed_data.begin(), + float resolution = 2.0F / (1 << (params.data_width - 1)) + 1 / 256.0F; + + std::vector decompressed_data_cf(nof_prb * NOF_SUBCARRIERS_PER_RB); + srsvec::convert(decompressed_data_cf, decompressed_data); + for (auto& result : decompressed_data_cf) { + result = {std::real(result) / iq_scaling, std::imag(result) / iq_scaling}; + } + + ASSERT_TRUE(std::equal(test_data_cf.begin(), + test_data_cf.end(), + decompressed_data_cf.begin(), [&](cf_t& test_value, cf_t& result) { // Make sure the sign is the same and diff is minimal. - return (std::abs(std::real(test_value) - std::real(result) / iq_scaling) <= resolution) && - (std::abs(std::imag(test_value) - std::imag(result) / iq_scaling) <= resolution); + return (std::abs(std::real(test_value) - std::real(result)) <= resolution) && + (std::abs(std::imag(test_value) - std::imag(result)) <= resolution); })) << "Decompressed data don't match the original ones"; } @@ -138,14 +145,16 @@ TEST_P(OFHCompressionFixture, zero_input_compression_is_correct) srsvec::convert(test_data_cbf16, test_data); std::vector compressed_data(nof_prb); - std::vector decompressed_data(nof_prb * NOF_SUBCARRIERS_PER_RB); + std::vector decompressed_data(nof_prb * NOF_SUBCARRIERS_PER_RB); // Compress it. compressor->compress(compressed_data, test_data_cbf16, params); // Decompress back. decompressor->decompress(decompressed_data, compressed_data, params); - ASSERT_EQ(test_data, decompressed_data); + std::vector decompressed_data_cf(nof_prb * NOF_SUBCARRIERS_PER_RB); + srsvec::convert(decompressed_data_cf, decompressed_data); + ASSERT_EQ(test_data, decompressed_data_cf); } // Verify BPSK modulated data are correctly processed. diff --git a/tests/unittests/ofh/compression/ofh_iq_decompressor_test_doubles.h b/tests/unittests/ofh/compression/ofh_iq_decompressor_test_doubles.h index 35c667d293..161134f1fb 100644 --- a/tests/unittests/ofh/compression/ofh_iq_decompressor_test_doubles.h +++ b/tests/unittests/ofh/compression/ofh_iq_decompressor_test_doubles.h @@ -21,7 +21,7 @@ class iq_decompressor_dummy : public iq_decompressor { public: // See interface for documentation. - void decompress(span iq_data, + void decompress(span iq_data, span compressed_prbs, const ru_compression_params& params) override { diff --git a/tests/unittests/ofh/receiver/helpers.h b/tests/unittests/ofh/receiver/helpers.h index 6346b8adab..30fd6c03ff 100644 --- a/tests/unittests/ofh/receiver/helpers.h +++ b/tests/unittests/ofh/receiver/helpers.h @@ -62,10 +62,21 @@ class prach_buffer_dummy : public prach_buffer /// Spy implementation of the resource grid writer that returns if the functions were called. class resource_grid_writer_bool_spy : public resource_grid_writer { - bool grid_written = false; - unsigned nof_prbs_written = 0; + static inline const cbf16_t init_value{-1.0, +1.0}; + + bool grid_written = false; + unsigned nof_prbs_written = 0; + std::vector grid_data; public: + resource_grid_writer_bool_spy() = default; + explicit resource_grid_writer_bool_spy(unsigned nof_prbs) : grid_data(nof_prbs * NOF_SUBCARRIERS_PER_RB) + { + for (auto& sample : grid_data) { + sample = init_value; + } + } + unsigned get_nof_ports() const override { return 1; }; unsigned get_nof_subc() const override { return 51 * NOF_SUBCARRIERS_PER_RB; }; unsigned get_nof_symbols() const override { return MAX_NSYMB_PER_SLOT; }; @@ -107,14 +118,27 @@ class resource_grid_writer_bool_spy : public resource_grid_writer span get_view(unsigned port, unsigned l) override { grid_written = true; - return {}; + return grid_data; } /// Returns true if the gris has been written, otherise false. bool has_grid_been_written() const { return grid_written; } /// Returns the number of PRBs written. - unsigned get_nof_prbs_written() const { return nof_prbs_written; } + unsigned get_nof_prbs_written() const + { + if (!nof_prbs_written && grid_written) { + // Check how many REs are storing a value different from the initial one. + unsigned written_re_count = 0; + for (auto sample : grid_data) { + if (sample != init_value) { + ++written_re_count; + } + } + return written_re_count / NOF_SUBCARRIERS_PER_RB; + } + return nof_prbs_written; + } }; class resource_grid_dummy_with_spy_writer : public resource_grid diff --git a/tests/unittests/ofh/receiver/ofh_data_flow_uplane_uplink_data_impl_test.cpp b/tests/unittests/ofh/receiver/ofh_data_flow_uplane_uplink_data_impl_test.cpp index 64745d3468..8d226c839d 100644 --- a/tests/unittests/ofh/receiver/ofh_data_flow_uplane_uplink_data_impl_test.cpp +++ b/tests/unittests/ofh/receiver/ofh_data_flow_uplane_uplink_data_impl_test.cpp @@ -55,7 +55,7 @@ class data_flow_uplane_uplink_data_impl_fixture : public ::testing::Test public: data_flow_uplane_uplink_data_impl_fixture() : - slot(0, 0, 1), grid(rg_writer), data_flow(get_config(), get_dependencies()) + slot(0, 0, 1), rg_writer(nof_prbs), grid(rg_writer), data_flow(get_config(), get_dependencies()) { ul_cplane_context context; context.prb_start = 0; diff --git a/tests/unittests/ofh/receiver/ofh_uplane_rx_symbol_data_flow_notifier_test.cpp b/tests/unittests/ofh/receiver/ofh_uplane_rx_symbol_data_flow_notifier_test.cpp index 1a6c8a8eed..6c275d9ccf 100644 --- a/tests/unittests/ofh/receiver/ofh_uplane_rx_symbol_data_flow_notifier_test.cpp +++ b/tests/unittests/ofh/receiver/ofh_uplane_rx_symbol_data_flow_notifier_test.cpp @@ -62,7 +62,7 @@ TEST(ofh_data_flow_uplane_rx_symbol_notifier, completed_resource_grid_triggers_n unsigned sector = 0; resource_grid_spy grid(2, 14, 273); - static_vector samples(grid.get_writer().get_nof_subc()); + static_vector samples(grid.get_writer().get_nof_subc()); repo->add({slot, sector}, grid, symbol_range); ASSERT_FALSE(repo->get(slot, symbol).empty()); @@ -91,7 +91,7 @@ TEST(ofh_data_flow_uplane_rx_symbol_notifier, uncompleted_port_does_not_notify) unsigned sector = 0; resource_grid_spy grid(2, 14, 273); - static_vector samples(grid.get_writer().get_nof_subc()); + static_vector samples(grid.get_writer().get_nof_subc()); repo->add({slot, sector}, grid, symbol_range); // Fill the grid. @@ -114,7 +114,7 @@ TEST(ofh_data_flow_uplane_rx_symbol_notifier, uncompleted_prbs_does_not_notify) unsigned sector = 0; resource_grid_spy grid(1, 14, 273); - static_vector samples(grid.get_writer().get_nof_subc() - 1); + static_vector samples(grid.get_writer().get_nof_subc() - 1); repo->add({slot, sector}, grid, symbol_range); // Fill the grid. diff --git a/tests/unittests/ofh/receiver/ofh_uplane_rx_symbol_data_flow_writer_test.cpp b/tests/unittests/ofh/receiver/ofh_uplane_rx_symbol_data_flow_writer_test.cpp index 329419f425..92057ddb02 100644 --- a/tests/unittests/ofh/receiver/ofh_uplane_rx_symbol_data_flow_writer_test.cpp +++ b/tests/unittests/ofh/receiver/ofh_uplane_rx_symbol_data_flow_writer_test.cpp @@ -33,7 +33,7 @@ class ofh_uplane_rx_symbol_data_flow_writer_fixture : public ::testing::Test public: ofh_uplane_rx_symbol_data_flow_writer_fixture() : - slot(0, 0, 1), grid(rg_writer), writer(eaxc, srslog::fetch_basic_logger("TEST"), repo) + slot(0, 0, 1), rg_writer(MAX_NOF_PRBS), grid(rg_writer), writer(eaxc, srslog::fetch_basic_logger("TEST"), repo) { results.params.slot = slot; results.params.symbol_id = symbol_id; diff --git a/tests/unittests/ofh/serdes/ofh_uplane_packet_decoder_dynamic_impl_test.cpp b/tests/unittests/ofh/serdes/ofh_uplane_packet_decoder_dynamic_impl_test.cpp index 24668d0104..4d43453e12 100644 --- a/tests/unittests/ofh/serdes/ofh_uplane_packet_decoder_dynamic_impl_test.cpp +++ b/tests/unittests/ofh/serdes/ofh_uplane_packet_decoder_dynamic_impl_test.cpp @@ -23,7 +23,7 @@ namespace { class iq_decompressor_dummy : public iq_decompressor { public: - void decompress(span iq_data, + void decompress(span iq_data, span compressed_prbs, const ru_compression_params& params) override { diff --git a/tests/unittests/ofh/serdes/ofh_uplane_packet_decoder_static_impl_test.cpp b/tests/unittests/ofh/serdes/ofh_uplane_packet_decoder_static_impl_test.cpp index 3c8dd7508f..41cbefa28b 100644 --- a/tests/unittests/ofh/serdes/ofh_uplane_packet_decoder_static_impl_test.cpp +++ b/tests/unittests/ofh/serdes/ofh_uplane_packet_decoder_static_impl_test.cpp @@ -23,7 +23,7 @@ namespace { class iq_decompressor_dummy : public iq_decompressor { public: - void decompress(span iq_data, + void decompress(span iq_data, span compressed_prbs, const ru_compression_params& params) override { From 7bc8382e94bc1e7d3bb2958cbda64283512b7e59 Mon Sep 17 00:00:00 2001 From: asaezper Date: Fri, 19 Jul 2024 10:13:29 +0200 Subject: [PATCH 13/54] ci,e2e: fix zmq jobs titles --- .gitlab/ci/e2e.yml | 13 ++++++++----- tests/e2e/tests/attach_detach.py | 4 ++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index dc66bc7f9b..0e72ea1d95 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -326,7 +326,11 @@ amari 8UE: parallel: matrix: - KEYWORDS: - ["reestablishment and sequentially", "handover and sequentially"] + [ + "attach_detach", + "reestablishment and sequentially", + "handover and sequentially", + ] amari 8UE beta: extends: amari 8UE @@ -354,7 +358,6 @@ amari 32UE: matrix: - KEYWORDS: [ - "attach_detach", "ping", "iperf and udp and band:3", "iperf and udp and not band:3", @@ -362,7 +365,7 @@ amari 32UE: "iperf and tcp and not band:3", ] -amari 32UE asan: +amari 4UE asan: extends: .zmq variables: MARKERS: "smoke" @@ -373,7 +376,7 @@ amari 32UE asan: - *txrx-lib - *retina-needs -amari 32UE tsan: +amari 4UE tsan: extends: .zmq variables: MARKERS: "smoke" @@ -384,7 +387,7 @@ amari 32UE tsan: - *txrx-lib - *retina-needs -amari 32UE memcheck: +amari 4UE memcheck: extends: .zmq variables: MARKERS: "zmq_valgrind" diff --git a/tests/e2e/tests/attach_detach.py b/tests/e2e/tests/attach_detach.py index e47950eb9d..ead5b102bc 100644 --- a/tests/e2e/tests/attach_detach.py +++ b/tests/e2e/tests/attach_detach.py @@ -56,7 +56,7 @@ def test_zmq( retina_manager: RetinaTestManager, retina_data: RetinaTestData, - ue_4: Tuple[UEStub, ...], + ue_8: Tuple[UEStub, ...], fivegc: FiveGCStub, gnb: GNBStub, band: int, @@ -72,7 +72,7 @@ def test_zmq( _attach_and_detach_multi_ues( retina_manager=retina_manager, retina_data=retina_data, - ue_array=ue_4, + ue_array=ue_8, gnb=gnb, fivegc=fivegc, band=band, From 638585cd2768203347b5082c325a56b201b7156c Mon Sep 17 00:00:00 2001 From: asaezper Date: Fri, 19 Jul 2024 10:14:11 +0200 Subject: [PATCH 14/54] ci,e2e: add a retry option --- tests/e2e/tests/iperf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/e2e/tests/iperf.py b/tests/e2e/tests/iperf.py index e25f7c62b6..0b7b660ff6 100644 --- a/tests/e2e/tests/iperf.py +++ b/tests/e2e/tests/iperf.py @@ -490,6 +490,7 @@ def test_zmq_smoke( "Attach timeout reached", "iperf did not achieve the expected data rate", "socket is already closed", + "failed to connect to all addresses", ], ) # pylint: disable=too-many-arguments From 4376c8495cc82169aea6c10d90f24239c6e3f60a Mon Sep 17 00:00:00 2001 From: asaezper Date: Fri, 19 Jul 2024 12:30:48 +0200 Subject: [PATCH 15/54] ci,test mode: increase gnb stop timeout --- tests/e2e/tests/test_mode.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/tests/test_mode.py b/tests/e2e/tests/test_mode.py index c0bc95bb1d..389d15ae2c 100644 --- a/tests/e2e/tests/test_mode.py +++ b/tests/e2e/tests/test_mode.py @@ -172,7 +172,7 @@ def test_ru_not_crash( Run gnb with sanitizers in test mode ru dummy. It ignores warnings and KOs, so it will fail if the gnb+sanitizer fails """ - _test_ru(retina_manager, retina_data, gnb, warning_as_errors=False, fail_if_kos=False) + _test_ru(retina_manager, retina_data, gnb, gnb_stop_timeout=150, warning_as_errors=False, fail_if_kos=False) # pylint: disable=too-many-arguments From c427b49667a843e97dc83be7ed028c4aa6e120b9 Mon Sep 17 00:00:00 2001 From: asaezper Date: Fri, 19 Jul 2024 12:33:42 +0200 Subject: [PATCH 16/54] ci,e2e: amarisoft: restore deregister call before power off --- .gitlab/ci/e2e/.env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index 215f1655ab..bd3844c8c6 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -1,6 +1,6 @@ SRSGNB_REGISTRY_URI=registry.gitlab.com/softwareradiosystems/srsgnb RETINA_REGISTRY_PREFIX=registry.gitlab.com/softwareradiosystems/ci/retina -RETINA_VERSION=0.51.9 +RETINA_VERSION=0.51.10 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 From c8d55e5c8476aea3a7188abad935033e6464e09c Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 17 Jul 2024 16:21:13 +0200 Subject: [PATCH 17/54] cu-cp: remove redundant du processor methods --- lib/cu_cp/cu_cp_impl.cpp | 35 +++++++++---------- lib/cu_cp/du_processor/du_processor.h | 16 --------- lib/cu_cp/du_processor/du_processor_impl.h | 6 +--- .../du_processor/du_processor_repository.cpp | 2 +- 4 files changed, 19 insertions(+), 40 deletions(-) diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index ac3b91c855..bc406e607a 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -233,7 +233,7 @@ async_task cu_cp_impl::handle_rrc_reestablishment_context_modification_req ue_index, ue->get_security_manager().get_up_as_config(), cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0))->get_e1ap_bearer_context_manager(), - du_db.get_du_processor(ue->get_du_index()).get_f1ap_interface().get_f1ap_ue_context_manager(), + du_db.get_du_processor(ue->get_du_index()).get_f1ap_interface().get_f1ap_handler(), ue->get_rrc_ue_notifier(), get_cu_cp_rrc_ue_interface(), ue->get_task_sched(), @@ -398,7 +398,7 @@ cu_cp_impl::handle_new_initial_context_setup_request(const ngap_init_context_set *rrc_ue, ngap_entity->get_ngap_ue_radio_cap_management_handler(), ue->get_security_manager(), - du_db.get_du_processor(ue->get_du_index()).get_f1ap_interface().get_f1ap_ue_context_manager(), + du_db.get_du_processor(ue->get_du_index()).get_f1ap_interface().get_f1ap_handler(), get_cu_cp_ngap_handler()); } @@ -415,7 +415,7 @@ cu_cp_impl::handle_new_pdu_session_resource_setup_request(cu_cp_pdu_session_reso request, ue->get_security_manager().get_up_as_config(), cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0))->get_e1ap_bearer_context_manager(), - du_db.get_du_processor(ue->get_du_index()).get_f1ap_interface().get_f1ap_ue_context_manager(), + du_db.get_du_processor(ue->get_du_index()).get_f1ap_interface().get_f1ap_handler(), ue->get_rrc_ue_notifier(), get_cu_cp_rrc_ue_interface(), ue->get_task_sched(), @@ -434,7 +434,7 @@ cu_cp_impl::handle_new_pdu_session_resource_modify_request(const cu_cp_pdu_sessi return routine_mng.start_pdu_session_resource_modification_routine( request, cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0))->get_e1ap_bearer_context_manager(), - du_db.get_du_processor(ue->get_du_index()).get_f1ap_interface().get_f1ap_ue_context_manager(), + du_db.get_du_processor(ue->get_du_index()).get_f1ap_interface().get_f1ap_handler(), ue->get_rrc_ue_notifier(), get_cu_cp_rrc_ue_interface(), ue->get_task_sched(), @@ -453,7 +453,7 @@ cu_cp_impl::handle_new_pdu_session_resource_release_command(const cu_cp_pdu_sess return routine_mng.start_pdu_session_resource_release_routine( command, cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0))->get_e1ap_bearer_context_manager(), - du_db.get_du_processor(ue->get_du_index()).get_f1ap_interface().get_f1ap_ue_context_manager(), + du_db.get_du_processor(ue->get_du_index()).get_f1ap_interface().get_f1ap_handler(), ue->get_rrc_ue_notifier(), get_cu_cp_rrc_ue_interface(), ue->get_task_sched(), @@ -474,7 +474,7 @@ cu_cp_impl::handle_ue_context_release_command(const cu_cp_ue_context_release_com return routine_mng.start_ue_context_release_routine( command, e1ap_bearer_ctxt_mng, - du_db.get_du_processor(ue->get_du_index()).get_f1ap_interface().get_f1ap_ue_context_manager(), + du_db.get_du_processor(ue->get_du_index()).get_f1ap_interface().get_f1ap_handler(), get_cu_cp_ue_removal_handler()); } @@ -490,7 +490,7 @@ cu_cp_impl::handle_ngap_handover_request(const ngap_handover_request& request) return routine_mng.start_inter_cu_handover_target_routine( request, cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0))->get_e1ap_bearer_context_manager(), - du_db.get_du_processor(ue->get_du_index()).get_f1ap_interface().get_f1ap_ue_context_manager(), + du_db.get_du_processor(ue->get_du_index()).get_f1ap_interface().get_f1ap_handler(), get_cu_cp_ue_removal_handler()); } @@ -524,7 +524,7 @@ async_task cu_cp_impl::handle_new_handover_command(ue_index_t ue_index, by CORO_AWAIT_VALUE(ue_context_mod_response, du_db.get_du_processor(ue_mng.find_du_ue(ue_index)->get_du_index()) .get_f1ap_interface() - .get_f1ap_ue_context_manager() + .get_f1ap_handler() .handle_ue_context_modification_request(ue_context_mod_request)); CORO_RETURN(ue_context_mod_response.success); @@ -578,8 +578,8 @@ cu_cp_impl::handle_inter_du_handover_request(const cu_cp_inter_du_handover_reque request, std::move(sib1), cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0))->get_e1ap_bearer_context_manager(), - du_db.get_du_processor(source_du_index).get_f1ap_interface().get_f1ap_ue_context_manager(), - du_db.get_du_processor(target_du_index).get_f1ap_interface().get_f1ap_ue_context_manager(), + du_db.get_du_processor(source_du_index).get_f1ap_interface().get_f1ap_handler(), + du_db.get_du_processor(target_du_index).get_f1ap_interface().get_f1ap_handler(), *this, get_cu_cp_ue_removal_handler(), *this); @@ -603,14 +603,13 @@ async_task cu_cp_impl::handle_ue_removal_request(ue_index_t ue_index) e1ap_removal_handler = &cu_up_db.find_cu_up_processor(cu_up_index)->get_e1ap_bearer_context_removal_handler(); } - return launch_async( - ue_index, - rrc_du_adapters.at(du_index), - e1ap_removal_handler, - du_db.get_du_processor(du_index).get_f1ap_interface().get_f1ap_ue_context_removal_handler(), - ngap_entity->get_ngap_ue_context_removal_handler(), - ue_mng, - logger); + return launch_async(ue_index, + rrc_du_adapters.at(du_index), + e1ap_removal_handler, + du_db.get_du_processor(du_index).get_f1ap_interface().get_f1ap_handler(), + ngap_entity->get_ngap_ue_context_removal_handler(), + ue_mng, + logger); } void cu_cp_impl::handle_pending_ue_task_cancellation(ue_index_t ue_index) diff --git a/lib/cu_cp/du_processor/du_processor.h b/lib/cu_cp/du_processor/du_processor.h index 42131d8ae7..bf0ef1e0f3 100644 --- a/lib/cu_cp/du_processor/du_processor.h +++ b/lib/cu_cp/du_processor/du_processor.h @@ -29,10 +29,6 @@ class du_processor_f1ap_interface public: virtual ~du_processor_f1ap_interface() = default; - /// \brief Get the DU index. - /// \return The DU index. - virtual du_index_t get_du_index() = 0; - /// \brief Request to create a new UE RRC context. /// /// This method should be called when a C-RNTI and PCell are assigned to a UE. @@ -48,21 +44,9 @@ class du_processor_f1ap_interface /// \brief Retrieve F1AP handler for the respective DU. virtual f1ap_cu& get_f1ap_handler() = 0; - /// \brief Get the F1AP UE context management handler interface of the DU processor object. - /// \return The F1AP UE context management handler interface of the DU processor object. - virtual f1ap_ue_context_manager& get_f1ap_ue_context_manager() = 0; - - /// \brief Get the F1AP UE context removal handler interface of the DU processor object. - /// \return The F1AP UE context removal handler interface of the DU processor object. - virtual f1ap_ue_context_removal_handler& get_f1ap_ue_context_removal_handler() = 0; - /// \brief Handle the loss of some transaction information for some UEs. /// \return Asynchronous task that is completed when the event is fully handled. virtual async_task handle_ue_transaction_info_loss(const f1_ue_transaction_info_loss_event& request) = 0; - - /// \brief Get the F1AP statistics handler interface of the DU processor object. - /// \return The F1AP statistics handler interface of the DU processor object. - virtual f1ap_statistics_handler& get_f1ap_statistics_handler() = 0; }; /// Interface to notify UE context management procedures. diff --git a/lib/cu_cp/du_processor/du_processor_impl.h b/lib/cu_cp/du_processor/du_processor_impl.h index 39720f7ac8..d114780aa4 100644 --- a/lib/cu_cp/du_processor/du_processor_impl.h +++ b/lib/cu_cp/du_processor/du_processor_impl.h @@ -48,11 +48,7 @@ class du_processor_impl : public du_processor, // getter functions - du_index_t get_du_index() override { return cfg.du_index; } - f1ap_cu& get_f1ap_handler() override { return *f1ap; }; - f1ap_ue_context_manager& get_f1ap_ue_context_manager() override { return *f1ap; } - f1ap_ue_context_removal_handler& get_f1ap_ue_context_removal_handler() override { return *f1ap; } - f1ap_statistics_handler& get_f1ap_statistics_handler() override { return *f1ap; } + f1ap_cu& get_f1ap_handler() override { return *f1ap; }; size_t get_nof_ues() const override { return ue_mng.get_nof_du_ues(cfg.du_index); }; diff --git a/lib/cu_cp/du_processor/du_processor_repository.cpp b/lib/cu_cp/du_processor/du_processor_repository.cpp index 366d7e927c..108d0ff7b5 100644 --- a/lib/cu_cp/du_processor/du_processor_repository.cpp +++ b/lib/cu_cp/du_processor/du_processor_repository.cpp @@ -154,7 +154,7 @@ size_t du_processor_repository::get_nof_f1ap_ues() { size_t nof_ues = 0; for (auto& du : du_db) { - nof_ues += du.second.processor->get_f1ap_interface().get_f1ap_statistics_handler().get_nof_ues(); + nof_ues += du.second.processor->get_f1ap_interface().get_f1ap_handler().get_nof_ues(); } return nof_ues; } From 8783aa137e43ff2420287d3595bc528c659ba606 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 17 Jul 2024 16:34:41 +0200 Subject: [PATCH 18/54] cu-cp: move f1ap_handler out of du_processor_f1ap_interface --- .../du_connection_manager.cpp | 2 +- lib/cu_cp/cu_cp_impl.cpp | 39 +++++++++---------- lib/cu_cp/du_processor/du_processor.h | 6 +-- .../du_processor/du_processor_repository.cpp | 4 +- .../cu_cp/du_processor/du_processor_test.cpp | 16 ++++---- .../du_processor_test_helpers.cpp | 2 +- 6 files changed, 33 insertions(+), 36 deletions(-) diff --git a/lib/cu_cp/cu_cp_controller/du_connection_manager.cpp b/lib/cu_cp/cu_cp_controller/du_connection_manager.cpp index f84294491d..61b52f6c4e 100644 --- a/lib/cu_cp/cu_cp_controller/du_connection_manager.cpp +++ b/lib/cu_cp/cu_cp_controller/du_connection_manager.cpp @@ -32,7 +32,7 @@ class du_connection_manager::shared_du_connection_context void connect_du(du_index_t du_idx_) { du_idx = du_idx_; - msg_handler = &parent.dus.get_du_processor(du_idx).get_f1ap_interface().get_f1ap_handler(); + msg_handler = &parent.dus.get_du_processor(du_idx).get_f1ap_handler(); } /// Determines whether a DU repository has been created for this connection. diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index bc406e607a..190b51cae8 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -233,7 +233,7 @@ async_task cu_cp_impl::handle_rrc_reestablishment_context_modification_req ue_index, ue->get_security_manager().get_up_as_config(), cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0))->get_e1ap_bearer_context_manager(), - du_db.get_du_processor(ue->get_du_index()).get_f1ap_interface().get_f1ap_handler(), + du_db.get_du_processor(ue->get_du_index()).get_f1ap_handler(), ue->get_rrc_ue_notifier(), get_cu_cp_rrc_ue_interface(), ue->get_task_sched(), @@ -393,13 +393,12 @@ cu_cp_impl::handle_new_initial_context_setup_request(const ngap_init_context_set rrc_ue_interface* rrc_ue = rrc_du_adapters.at(ue->get_du_index()).find_rrc_ue(request.ue_index); srsran_assert(rrc_ue != nullptr, "ue={}: Could not find RRC UE", request.ue_index); - return routine_mng.start_initial_context_setup_routine( - request, - *rrc_ue, - ngap_entity->get_ngap_ue_radio_cap_management_handler(), - ue->get_security_manager(), - du_db.get_du_processor(ue->get_du_index()).get_f1ap_interface().get_f1ap_handler(), - get_cu_cp_ngap_handler()); + return routine_mng.start_initial_context_setup_routine(request, + *rrc_ue, + ngap_entity->get_ngap_ue_radio_cap_management_handler(), + ue->get_security_manager(), + du_db.get_du_processor(ue->get_du_index()).get_f1ap_handler(), + get_cu_cp_ngap_handler()); } async_task @@ -415,7 +414,7 @@ cu_cp_impl::handle_new_pdu_session_resource_setup_request(cu_cp_pdu_session_reso request, ue->get_security_manager().get_up_as_config(), cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0))->get_e1ap_bearer_context_manager(), - du_db.get_du_processor(ue->get_du_index()).get_f1ap_interface().get_f1ap_handler(), + du_db.get_du_processor(ue->get_du_index()).get_f1ap_handler(), ue->get_rrc_ue_notifier(), get_cu_cp_rrc_ue_interface(), ue->get_task_sched(), @@ -434,7 +433,7 @@ cu_cp_impl::handle_new_pdu_session_resource_modify_request(const cu_cp_pdu_sessi return routine_mng.start_pdu_session_resource_modification_routine( request, cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0))->get_e1ap_bearer_context_manager(), - du_db.get_du_processor(ue->get_du_index()).get_f1ap_interface().get_f1ap_handler(), + du_db.get_du_processor(ue->get_du_index()).get_f1ap_handler(), ue->get_rrc_ue_notifier(), get_cu_cp_rrc_ue_interface(), ue->get_task_sched(), @@ -453,7 +452,7 @@ cu_cp_impl::handle_new_pdu_session_resource_release_command(const cu_cp_pdu_sess return routine_mng.start_pdu_session_resource_release_routine( command, cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0))->get_e1ap_bearer_context_manager(), - du_db.get_du_processor(ue->get_du_index()).get_f1ap_interface().get_f1ap_handler(), + du_db.get_du_processor(ue->get_du_index()).get_f1ap_handler(), ue->get_rrc_ue_notifier(), get_cu_cp_rrc_ue_interface(), ue->get_task_sched(), @@ -471,11 +470,10 @@ cu_cp_impl::handle_ue_context_release_command(const cu_cp_ue_context_release_com e1ap_bearer_ctxt_mng = &cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0))->get_e1ap_bearer_context_manager(); } - return routine_mng.start_ue_context_release_routine( - command, - e1ap_bearer_ctxt_mng, - du_db.get_du_processor(ue->get_du_index()).get_f1ap_interface().get_f1ap_handler(), - get_cu_cp_ue_removal_handler()); + return routine_mng.start_ue_context_release_routine(command, + e1ap_bearer_ctxt_mng, + du_db.get_du_processor(ue->get_du_index()).get_f1ap_handler(), + get_cu_cp_ue_removal_handler()); } async_task @@ -490,7 +488,7 @@ cu_cp_impl::handle_ngap_handover_request(const ngap_handover_request& request) return routine_mng.start_inter_cu_handover_target_routine( request, cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0))->get_e1ap_bearer_context_manager(), - du_db.get_du_processor(ue->get_du_index()).get_f1ap_interface().get_f1ap_handler(), + du_db.get_du_processor(ue->get_du_index()).get_f1ap_handler(), get_cu_cp_ue_removal_handler()); } @@ -523,7 +521,6 @@ async_task cu_cp_impl::handle_new_handover_command(ue_index_t ue_index, by CORO_AWAIT_VALUE(ue_context_mod_response, du_db.get_du_processor(ue_mng.find_du_ue(ue_index)->get_du_index()) - .get_f1ap_interface() .get_f1ap_handler() .handle_ue_context_modification_request(ue_context_mod_request)); @@ -578,8 +575,8 @@ cu_cp_impl::handle_inter_du_handover_request(const cu_cp_inter_du_handover_reque request, std::move(sib1), cu_up_db.find_cu_up_processor(uint_to_cu_up_index(0))->get_e1ap_bearer_context_manager(), - du_db.get_du_processor(source_du_index).get_f1ap_interface().get_f1ap_handler(), - du_db.get_du_processor(target_du_index).get_f1ap_interface().get_f1ap_handler(), + du_db.get_du_processor(source_du_index).get_f1ap_handler(), + du_db.get_du_processor(target_du_index).get_f1ap_handler(), *this, get_cu_cp_ue_removal_handler(), *this); @@ -606,7 +603,7 @@ async_task cu_cp_impl::handle_ue_removal_request(ue_index_t ue_index) return launch_async(ue_index, rrc_du_adapters.at(du_index), e1ap_removal_handler, - du_db.get_du_processor(du_index).get_f1ap_interface().get_f1ap_handler(), + du_db.get_du_processor(du_index).get_f1ap_handler(), ngap_entity->get_ngap_ue_context_removal_handler(), ue_mng, logger); diff --git a/lib/cu_cp/du_processor/du_processor.h b/lib/cu_cp/du_processor/du_processor.h index bf0ef1e0f3..68e50b61a2 100644 --- a/lib/cu_cp/du_processor/du_processor.h +++ b/lib/cu_cp/du_processor/du_processor.h @@ -41,9 +41,6 @@ class du_processor_f1ap_interface /// \param[in] req The F1AP UE Context Release Request. virtual void handle_du_initiated_ue_context_release_request(const f1ap_ue_context_release_request& request) = 0; - /// \brief Retrieve F1AP handler for the respective DU. - virtual f1ap_cu& get_f1ap_handler() = 0; - /// \brief Handle the loss of some transaction information for some UEs. /// \return Asynchronous task that is completed when the event is fully handled. virtual async_task handle_ue_transaction_info_loss(const f1_ue_transaction_info_loss_event& request) = 0; @@ -292,6 +289,9 @@ class du_processor : public du_processor_cell_info_interface public: virtual ~du_processor() = default; + /// \brief Retrieve F1AP handler for the respective DU. + virtual f1ap_cu& get_f1ap_handler() = 0; + virtual du_processor_f1ap_interface& get_f1ap_interface() = 0; virtual du_processor_paging_handler& get_paging_handler() = 0; virtual du_processor_statistics_handler& get_statistics_handler() = 0; diff --git a/lib/cu_cp/du_processor/du_processor_repository.cpp b/lib/cu_cp/du_processor/du_processor_repository.cpp index 108d0ff7b5..55a53bd577 100644 --- a/lib/cu_cp/du_processor/du_processor_repository.cpp +++ b/lib/cu_cp/du_processor/du_processor_repository.cpp @@ -70,7 +70,7 @@ async_task du_processor_repository::remove_du(du_index_t du_index) } // Stop DU activity, eliminating pending transactions for the DU and respective UEs. - CORO_AWAIT(du_db.find(du_index)->second.processor->get_f1ap_interface().get_f1ap_handler().stop()); + CORO_AWAIT(du_db.find(du_index)->second.processor->get_f1ap_handler().stop()); // Notify the CU-CP about the removal of the DU processor. cfg.cu_cp_du_handler.handle_du_processor_removal(du_index); @@ -154,7 +154,7 @@ size_t du_processor_repository::get_nof_f1ap_ues() { size_t nof_ues = 0; for (auto& du : du_db) { - nof_ues += du.second.processor->get_f1ap_interface().get_f1ap_handler().get_nof_ues(); + nof_ues += du.second.processor->get_f1ap_handler().get_nof_ues(); } return nof_ues; } diff --git a/tests/unittests/cu_cp/du_processor/du_processor_test.cpp b/tests/unittests/cu_cp/du_processor/du_processor_test.cpp index a1274632bb..f82370ff0f 100644 --- a/tests/unittests/cu_cp/du_processor/du_processor_test.cpp +++ b/tests/unittests/cu_cp/du_processor/du_processor_test.cpp @@ -29,7 +29,7 @@ TEST_F(du_processor_test, when_valid_f1setup_received_then_f1_setup_response_sen { // Pass F1 Setup Request to DU processor f1ap_message f1_setup_req = test_helpers::generate_f1_setup_request(); - du_processor_obj->get_f1ap_interface().get_f1ap_handler().get_f1ap_message_handler().handle_message(f1_setup_req); + du_processor_obj->get_f1ap_handler().get_f1ap_message_handler().handle_message(f1_setup_req); // Check response is F1SetupResponse ASSERT_EQ(f1ap_pdu_notifier.last_f1ap_msg.pdu.type(), f1ap_pdu_c::types_opts::options::successful_outcome); @@ -45,7 +45,7 @@ TEST_F(du_processor_test, when_du_served_cells_list_missing_then_f1setup_rejecte f1_setup_req.pdu.init_msg().value.f1_setup_request()->gnb_du_served_cells_list.clear(); // Pass message to DU processor - du_processor_obj->get_f1ap_interface().get_f1ap_handler().get_f1ap_message_handler().handle_message(f1_setup_req); + du_processor_obj->get_f1ap_handler().get_f1ap_message_handler().handle_message(f1_setup_req); // Check the generated PDU is indeed the F1 Setup failure ASSERT_EQ(f1ap_pdu_notifier.last_f1ap_msg.pdu.type(), f1ap_pdu_c::types_opts::options::unsuccessful_outcome); @@ -65,7 +65,7 @@ TEST_F(du_processor_test, when_gnb_du_sys_info_missing_then_f1setup_rejected) .gnb_du_sys_info_present = false; // Pass message to DU processor - du_processor_obj->get_f1ap_interface().get_f1ap_handler().get_f1ap_message_handler().handle_message(f1_setup_req); + du_processor_obj->get_f1ap_handler().get_f1ap_message_handler().handle_message(f1_setup_req); // Check the generated PDU is indeed the F1 Setup failure ASSERT_EQ(f1ap_pdu_notifier.last_f1ap_msg.pdu.type(), f1ap_pdu_c::types_opts::options::unsuccessful_outcome); @@ -79,7 +79,7 @@ TEST_F(du_processor_test, when_max_nof_du_cells_exeeded_then_f1setup_rejected) f1ap_message f1ap_msg = create_f1_setup_request_with_too_many_cells(); // Pass message to DU processor - du_processor_obj->get_f1ap_interface().get_f1ap_handler().get_f1ap_message_handler().handle_message(f1ap_msg); + du_processor_obj->get_f1ap_handler().get_f1ap_message_handler().handle_message(f1ap_msg); // Check the generated PDU is indeed the F1 Setup failure ASSERT_EQ(f1ap_pdu_notifier.last_f1ap_msg.pdu.type(), f1ap_pdu_c::types_opts::options::unsuccessful_outcome); @@ -94,7 +94,7 @@ TEST_F(du_processor_test, when_max_nof_du_cells_exeeded_then_f1setup_rejected) TEST_F(du_processor_test, when_ue_creation_msg_valid_then_ue_added) { // Pass message to DU processor - du_processor_obj->get_f1ap_interface().get_f1ap_handler().get_f1ap_message_handler().handle_message( + du_processor_obj->get_f1ap_handler().get_f1ap_message_handler().handle_message( test_helpers::generate_f1_setup_request()); // Generate ue_creation message @@ -112,7 +112,7 @@ TEST_F(du_processor_test, when_ue_creation_msg_valid_then_ue_added) TEST_F(du_processor_test, when_cell_id_invalid_then_ue_creation_fails) { // Generate valid F1SetupRequest and pass it to DU processor - du_processor_obj->get_f1ap_interface().get_f1ap_handler().get_f1ap_message_handler().handle_message( + du_processor_obj->get_f1ap_handler().get_f1ap_message_handler().handle_message( test_helpers::generate_f1_setup_request()); // Generate ue_creation message @@ -132,7 +132,7 @@ TEST_F(du_processor_test, when_ue_rrc_context_exists_then_new_ue_rrc_context_not generate_valid_f1_setup_request(f1_setup_request); // Pass message to DU processor - du_processor_obj->get_f1ap_interface().get_f1ap_handler().get_f1ap_message_handler().handle_message( + du_processor_obj->get_f1ap_handler().get_f1ap_message_handler().handle_message( test_helpers::generate_f1_setup_request()); // Generate ue_creation message @@ -158,7 +158,7 @@ TEST_F(du_processor_test, when_ue_rrc_context_exists_then_new_ue_rrc_context_not TEST_F(du_processor_test, when_max_nof_ues_exceeded_then_ue_not_added) { // Generate valid F1SetupRequest and pass it to DU processor - du_processor_obj->get_f1ap_interface().get_f1ap_handler().get_f1ap_message_handler().handle_message( + du_processor_obj->get_f1ap_handler().get_f1ap_message_handler().handle_message( test_helpers::generate_f1_setup_request()); // Reduce logger loglevel to warning to reduce console output diff --git a/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.cpp b/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.cpp index 3248b55811..1d34e1d287 100644 --- a/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.cpp +++ b/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.cpp @@ -73,7 +73,7 @@ void du_processor_test::attach_ue() // Generate valid F1SetupRequest f1ap_message f1_setup_req = test_helpers::generate_f1_setup_request(); // Pass message to DU processor - du_processor_obj->get_f1ap_interface().get_f1ap_handler().get_f1ap_message_handler().handle_message(f1_setup_req); + du_processor_obj->get_f1ap_handler().get_f1ap_message_handler().handle_message(f1_setup_req); // Generate ue_creation message ue_index_t ue_index = ue_index_t::min; From 218925625e75ab741932bc8bf89a136974c0a267 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 17 Jul 2024 18:04:29 +0200 Subject: [PATCH 19/54] cu-cp: refactor f1ap du adapter --- include/srsran/f1ap/cu_cp/f1ap_cu.h | 3 ++ lib/cu_cp/adapters/f1ap_adapters.h | 47 ------------------ lib/cu_cp/du_processor/du_processor.h | 8 --- lib/cu_cp/du_processor/du_processor_impl.cpp | 52 ++++++++++++++++---- lib/cu_cp/du_processor/du_processor_impl.h | 22 ++++++--- lib/cu_cp/du_processor/du_setup_handler.h | 30 ----------- 6 files changed, 62 insertions(+), 100 deletions(-) delete mode 100644 lib/cu_cp/du_processor/du_setup_handler.h diff --git a/include/srsran/f1ap/cu_cp/f1ap_cu.h b/include/srsran/f1ap/cu_cp/f1ap_cu.h index 86fc8893c6..7be1e1b5c8 100644 --- a/include/srsran/f1ap/cu_cp/f1ap_cu.h +++ b/include/srsran/f1ap/cu_cp/f1ap_cu.h @@ -150,7 +150,10 @@ class f1ap_du_processor_notifier : public du_setup_notifier, public f1ap_common_ /// section 8.3.2. virtual void on_du_initiated_ue_context_release_request(const f1ap_ue_context_release_request& req) = 0; + /// \brief Indicates that there was some loss of transaction information for some UEs. + /// /// Called when an F1 removal or F1 Reset is received, or when the DU disconnects. + /// \return Asynchronous task that handles the event virtual async_task on_transaction_info_loss(const f1_ue_transaction_info_loss_event& ev) = 0; }; diff --git a/lib/cu_cp/adapters/f1ap_adapters.h b/lib/cu_cp/adapters/f1ap_adapters.h index f043ca4c8b..bdd11467d1 100644 --- a/lib/cu_cp/adapters/f1ap_adapters.h +++ b/lib/cu_cp/adapters/f1ap_adapters.h @@ -12,7 +12,6 @@ #include "../cu_cp_controller/common_task_scheduler.h" #include "../du_processor/du_processor.h" -#include "../du_processor/du_setup_handler.h" #include "srsran/f1ap/cu_cp/f1ap_cu.h" namespace srsran { @@ -20,52 +19,6 @@ namespace srs_cu_cp { class cu_cp_controller; -/// Adapter between F1AP and DU processor -class f1ap_du_processor_adapter : public f1ap_du_processor_notifier -{ -public: - f1ap_du_processor_adapter(common_task_scheduler& common_task_sched_, du_setup_handler& du_setup_hdlr_) : - common_task_sched(&common_task_sched_), du_setup_hdlr(&du_setup_hdlr_) - { - } - - void connect_du_processor(du_processor_f1ap_interface& du_processor_f1ap_) { du_f1ap_handler = &du_processor_f1ap_; } - - du_setup_result on_new_du_setup_request(const du_setup_request& msg) override - { - srsran_assert(du_setup_hdlr != nullptr, "F1AP handler must not be nullptr"); - return du_setup_hdlr->handle_du_setup_request(msg); - } - - ue_rrc_context_creation_outcome - on_ue_rrc_context_creation_request(const ue_rrc_context_creation_request& req) override - { - srsran_assert(du_f1ap_handler != nullptr, "F1AP handler must not be nullptr"); - return du_f1ap_handler->handle_ue_rrc_context_creation_request(req); - } - - void on_du_initiated_ue_context_release_request(const f1ap_ue_context_release_request& req) override - { - srsran_assert(du_f1ap_handler != nullptr, "F1AP handler must not be nullptr"); - du_f1ap_handler->handle_du_initiated_ue_context_release_request(req); - } - - bool schedule_async_task(async_task task) override - { - return common_task_sched->schedule_async_task(std::move(task)); - } - - async_task on_transaction_info_loss(const f1_ue_transaction_info_loss_event& ev) override - { - return du_f1ap_handler->handle_ue_transaction_info_loss(ev); - } - -private: - common_task_scheduler* common_task_sched = nullptr; - du_setup_handler* du_setup_hdlr = nullptr; - du_processor_f1ap_interface* du_f1ap_handler = nullptr; -}; - /// Adapter between F1AP and RRC UE class f1ap_rrc_ue_adapter : public f1ap_rrc_message_notifier { diff --git a/lib/cu_cp/du_processor/du_processor.h b/lib/cu_cp/du_processor/du_processor.h index 68e50b61a2..4ad70804eb 100644 --- a/lib/cu_cp/du_processor/du_processor.h +++ b/lib/cu_cp/du_processor/du_processor.h @@ -36,14 +36,6 @@ class du_processor_f1ap_interface /// \return Response to whether the request was successful or failed. virtual ue_rrc_context_creation_outcome handle_ue_rrc_context_creation_request(const ue_rrc_context_creation_request& req) = 0; - - /// \brief Handle the reception of a F1AP UE Context Release Request and notify NGAP. - /// \param[in] req The F1AP UE Context Release Request. - virtual void handle_du_initiated_ue_context_release_request(const f1ap_ue_context_release_request& request) = 0; - - /// \brief Handle the loss of some transaction information for some UEs. - /// \return Asynchronous task that is completed when the event is fully handled. - virtual async_task handle_ue_transaction_info_loss(const f1_ue_transaction_info_loss_event& request) = 0; }; /// Interface to notify UE context management procedures. diff --git a/lib/cu_cp/du_processor/du_processor_impl.cpp b/lib/cu_cp/du_processor/du_processor_impl.cpp index 4693b08c5d..afc412bad7 100644 --- a/lib/cu_cp/du_processor/du_processor_impl.cpp +++ b/lib/cu_cp/du_processor/du_processor_impl.cpp @@ -32,6 +32,47 @@ static rrc_cfg_t create_rrc_config(const cu_cp_configuration& cu_cp_cfg) return rrc_cfg; } +class du_processor_impl::f1ap_du_processor_adapter : public f1ap_du_processor_notifier +{ +public: + f1ap_du_processor_adapter(du_processor_impl& parent_, common_task_scheduler& common_task_sched_) : + parent(parent_), common_task_sched(&common_task_sched_) + { + } + + du_setup_result on_new_du_setup_request(const du_setup_request& msg) override + { + return parent.handle_du_setup_request(msg); + } + + ue_rrc_context_creation_outcome + on_ue_rrc_context_creation_request(const ue_rrc_context_creation_request& req) override + { + return parent.handle_ue_rrc_context_creation_request(req); + } + + void on_du_initiated_ue_context_release_request(const f1ap_ue_context_release_request& req) override + { + parent.handle_du_initiated_ue_context_release_request(req); + } + + bool schedule_async_task(async_task task) override + { + return common_task_sched->schedule_async_task(std::move(task)); + } + + async_task on_transaction_info_loss(const f1_ue_transaction_info_loss_event& ev) override + { + return parent.cu_cp_notifier.on_transaction_info_loss(ev); + } + +private: + du_processor_impl& parent; + common_task_scheduler* common_task_sched = nullptr; +}; + +// du_processor_impl + du_processor_impl::du_processor_impl(du_processor_config_t du_processor_config_, du_processor_cu_cp_notifier& cu_cp_notifier_, f1ap_message_notifier& f1ap_pdu_notifier_, @@ -45,16 +86,14 @@ du_processor_impl::du_processor_impl(du_processor_config_t du_proc f1ap_pdu_notifier(f1ap_pdu_notifier_), rrc_ue_nas_pdu_notifier(rrc_ue_nas_pdu_notifier_), ue_mng(ue_mng_), - f1ap_ev_notifier(common_task_sched_, *this) + f1ap_ev_notifier(std::make_unique(*this, common_task_sched_)) { // create f1ap f1ap = create_f1ap(cfg.cu_cp_cfg.f1ap, f1ap_pdu_notifier, - f1ap_ev_notifier, + *f1ap_ev_notifier, *cfg.cu_cp_cfg.services.timers, *cfg.cu_cp_cfg.services.cu_cp_executor); - - f1ap_ev_notifier.connect_du_processor(get_f1ap_interface()); f1ap_ue_context_notifier.connect_f1(f1ap->get_f1ap_ue_context_manager()); // create RRC @@ -248,11 +287,6 @@ void du_processor_impl::handle_du_initiated_ue_context_release_request(const f1a })); } -async_task du_processor_impl::handle_ue_transaction_info_loss(const f1_ue_transaction_info_loss_event& request) -{ - return cu_cp_notifier.on_transaction_info_loss(request); -} - void du_processor_impl::handle_paging_message(cu_cp_paging_message& msg) { // Add assist data for paging diff --git a/lib/cu_cp/du_processor/du_processor_impl.h b/lib/cu_cp/du_processor/du_processor_impl.h index d114780aa4..85fa6a5f2f 100644 --- a/lib/cu_cp/du_processor/du_processor_impl.h +++ b/lib/cu_cp/du_processor/du_processor_impl.h @@ -28,7 +28,6 @@ namespace srsran { namespace srs_cu_cp { class du_processor_impl : public du_processor, - public du_setup_handler, public du_metrics_handler, public du_processor_f1ap_interface, public du_processor_paging_handler, @@ -53,11 +52,14 @@ class du_processor_impl : public du_processor, size_t get_nof_ues() const override { return ue_mng.get_nof_du_ues(cfg.du_index); }; // du_processor_f1ap_interface - du_setup_result handle_du_setup_request(const du_setup_request& req) override; + + /// \brief Request to create a new UE RRC context. + /// + /// This method should be called when a C-RNTI and PCell are assigned to a UE. + /// \param req Request to setup a new UE RRC context. + /// \return Response to whether the request was successful or failed. ue_rrc_context_creation_outcome - handle_ue_rrc_context_creation_request(const ue_rrc_context_creation_request& req) override; - void handle_du_initiated_ue_context_release_request(const f1ap_ue_context_release_request& request) override; - async_task handle_ue_transaction_info_loss(const f1_ue_transaction_info_loss_event& request) override; + handle_ue_rrc_context_creation_request(const ue_rrc_context_creation_request& req) override; // du_processor_mobility_manager_interface std::optional get_cgi(pci_t pci) override; @@ -80,6 +82,14 @@ class du_processor_impl : public du_processor, du_metrics_handler& get_metrics_handler() override { return *this; } private: + class f1ap_du_processor_adapter; + + du_setup_result handle_du_setup_request(const du_setup_request& req); + + /// \brief Handle the reception of a F1AP UE Context Release Request and notify NGAP. + /// \param[in] req The F1AP UE Context Release Request. + void handle_du_initiated_ue_context_release_request(const f1ap_ue_context_release_request& request); + /// \brief Create RRC UE object for given UE. /// \return True on success, falso otherwise. bool create_rrc_ue(cu_cp_ue& ue, @@ -99,7 +109,7 @@ class du_processor_impl : public du_processor, du_processor_f1ap_paging_adapter f1ap_paging_notifier; // F1AP to DU processor adapter - f1ap_du_processor_adapter f1ap_ev_notifier; + std::unique_ptr f1ap_ev_notifier; std::map> tac_to_nr_cgi; diff --git a/lib/cu_cp/du_processor/du_setup_handler.h b/lib/cu_cp/du_processor/du_setup_handler.h deleted file mode 100644 index bfdead0515..0000000000 --- a/lib/cu_cp/du_processor/du_setup_handler.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * - * 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/f1ap/cu_cp/du_setup_notifier.h" - -namespace srsran { -namespace srs_cu_cp { - -/// \brief Class responsible for handling the setup of the DUs that connect to this CU-CP. -class du_setup_handler -{ -public: - virtual ~du_setup_handler() = default; - - /// \brief Determines whether a DU setup should be accepted by the CU-CP, given the state of the CU-CP and resources - /// available. - virtual du_setup_result handle_du_setup_request(const du_setup_request& req) = 0; -}; - -} // namespace srs_cu_cp -} // namespace srsran \ No newline at end of file From d8205255520a0b0bfabffe989c0b106b3a90061c Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 17 Jul 2024 18:33:20 +0200 Subject: [PATCH 20/54] cu-cp: remove uneeded e1 interface --- include/srsran/cu_cp/cu_cp_e1_handler.h | 11 ----------- .../cu_cp_controller/cu_up_connection_manager.cpp | 2 +- .../cu_up_processor/cu_up_processor_repository.cpp | 9 ++------- .../cu_up_processor/cu_up_processor_repository.h | 6 ++---- 4 files changed, 5 insertions(+), 23 deletions(-) diff --git a/include/srsran/cu_cp/cu_cp_e1_handler.h b/include/srsran/cu_cp/cu_cp_e1_handler.h index 2f641be6a5..2b1fe3c645 100644 --- a/include/srsran/cu_cp/cu_cp_e1_handler.h +++ b/include/srsran/cu_cp/cu_cp_e1_handler.h @@ -15,17 +15,6 @@ namespace srsran { namespace srs_cu_cp { -/// Handler of the E1 interface of a single CU-UP connected to the CU-CP. -class cu_up_e1_handler -{ -public: - virtual ~cu_up_e1_handler() = default; - - /// \brief Get the E1AP message handler interface of the CU-UP processor object. - /// \return The E1AP message handler interface of the CU-UP processor object. - virtual e1ap_message_handler& get_message_handler() = 0; -}; - /// \brief Handler of the E1 interface of the CU-CP. /// /// This interface is used to forward E1AP messages or CU-UP connection updates to the CU-CP. diff --git a/lib/cu_cp/cu_cp_controller/cu_up_connection_manager.cpp b/lib/cu_cp/cu_cp_controller/cu_up_connection_manager.cpp index cd3cd92ff1..d4f03ec29d 100644 --- a/lib/cu_cp/cu_cp_controller/cu_up_connection_manager.cpp +++ b/lib/cu_cp/cu_cp_controller/cu_up_connection_manager.cpp @@ -33,7 +33,7 @@ class cu_up_connection_manager::shared_cu_up_connection_context void connect_cu_up(cu_up_index_t cu_up_idx_) { cu_up_idx = cu_up_idx_; - msg_handler = &parent.cu_ups.get_cu_up(cu_up_idx).get_message_handler(); + msg_handler = &parent.cu_ups.get_cu_up(cu_up_idx).get_e1ap_message_handler(); } /// Determines whether a CU-UP repository has been created for this connection. diff --git a/lib/cu_cp/cu_up_processor/cu_up_processor_repository.cpp b/lib/cu_cp/cu_up_processor/cu_up_processor_repository.cpp index 4713bf89f7..1785d196f6 100644 --- a/lib/cu_cp/cu_up_processor/cu_up_processor_repository.cpp +++ b/lib/cu_cp/cu_up_processor/cu_up_processor_repository.cpp @@ -100,11 +100,11 @@ async_task cu_up_processor_repository::remove_cu_up(cu_up_index_t cu_up_in }); } -cu_up_e1_handler& cu_up_processor_repository::get_cu_up(cu_up_index_t cu_up_index) +cu_up_processor_e1ap_interface& cu_up_processor_repository::get_cu_up(cu_up_index_t cu_up_index) { srsran_assert(cu_up_index != cu_up_index_t::invalid, "Invalid cu_up_index={}", cu_up_index); srsran_assert(cu_up_db.find(cu_up_index) != cu_up_db.end(), "CU-UP not found cu_up_index={}", cu_up_index); - return cu_up_db.at(cu_up_index); + return *cu_up_db.at(cu_up_index).processor; } cu_up_processor_impl_interface* cu_up_processor_repository::find_cu_up_processor(cu_up_index_t cu_up_index) @@ -124,8 +124,3 @@ size_t cu_up_processor_repository::get_nof_e1ap_ues() } return nof_ues; } - -e1ap_message_handler& cu_up_processor_repository::cu_up_context::get_message_handler() -{ - return processor->get_e1ap_message_handler(); -} diff --git a/lib/cu_cp/cu_up_processor/cu_up_processor_repository.h b/lib/cu_cp/cu_up_processor/cu_up_processor_repository.h index 56e4705630..991b1d7a1c 100644 --- a/lib/cu_cp/cu_up_processor/cu_up_processor_repository.h +++ b/lib/cu_cp/cu_up_processor/cu_up_processor_repository.h @@ -42,7 +42,7 @@ class cu_up_processor_repository size_t get_nof_cu_ups() const { return cu_up_db.size(); } - cu_up_e1_handler& get_cu_up(cu_up_index_t cu_up_index); + cu_up_processor_e1ap_interface& get_cu_up(cu_up_index_t cu_up_index); /// \brief Find a CU-UP object. /// \param[in] cu_up_index The index of the CU-UP processor object. @@ -52,13 +52,11 @@ class cu_up_processor_repository size_t get_nof_e1ap_ues(); private: - struct cu_up_context final : public cu_up_e1_handler { + struct cu_up_context { std::unique_ptr processor; /// Notifier used by the CU-CP to push E1AP Tx messages to the respective CU-UP. std::unique_ptr e1ap_tx_pdu_notifier; - - e1ap_message_handler& get_message_handler() override; }; /// \brief Get the next available index from the CU-UP processor database. From 7ce843d696b69c1ecf588305e64c16a77e5aef86 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Thu, 18 Jul 2024 12:41:58 +0200 Subject: [PATCH 21/54] cu-cp: remove internal methods from the du_processor public interface --- lib/cu_cp/adapters/rrc_ue_adapters.h | 24 ++-- lib/cu_cp/cu_cp_controller/cu_cp_controller.h | 5 +- .../cu_cp_ue_admission_controller.h | 26 ++++ lib/cu_cp/du_processor/du_processor.h | 43 +------ lib/cu_cp/du_processor/du_processor_impl.h | 23 ++-- lib/cu_cp/ue_manager/ue_manager_impl.h | 1 + .../cu_cp/du_processor/CMakeLists.txt | 3 +- .../cu_cp/du_processor/du_processor_test.cpp | 116 ++++-------------- .../du_processor_test_helpers.cpp | 99 ++++++++++++--- .../du_processor/du_processor_test_helpers.h | 28 ++--- 10 files changed, 167 insertions(+), 201 deletions(-) create mode 100644 lib/cu_cp/cu_cp_controller/cu_cp_ue_admission_controller.h diff --git a/lib/cu_cp/adapters/rrc_ue_adapters.h b/lib/cu_cp/adapters/rrc_ue_adapters.h index 5132231ba3..db9b66a3b9 100644 --- a/lib/cu_cp/adapters/rrc_ue_adapters.h +++ b/lib/cu_cp/adapters/rrc_ue_adapters.h @@ -10,7 +10,7 @@ #pragma once -#include "../cu_cp_controller/cu_cp_controller.h" +#include "../cu_cp_controller/cu_cp_ue_admission_controller.h" #include "../cu_cp_impl_interface.h" #include "../ue_manager/cu_cp_ue_impl_interface.h" #include "../up_resource_manager/up_resource_manager_impl.h" @@ -170,11 +170,11 @@ class rrc_ue_cu_cp_adapter : public rrc_ue_context_update_notifier, public rrc_u public: rrc_ue_cu_cp_adapter(ue_index_t ue_index_) : ue_index(ue_index_) {} - void connect_cu_cp(cu_cp_rrc_ue_interface& cu_cp_rrc_ue_, - cu_cp_ue_removal_handler& ue_removal_handler_, - cu_cp_controller& ctrl_, - up_resource_manager& up_mng_, - cu_cp_measurement_handler& meas_handler_) + void connect_cu_cp(cu_cp_rrc_ue_interface& cu_cp_rrc_ue_, + cu_cp_ue_removal_handler& ue_removal_handler_, + cu_cp_ue_admission_controller& ctrl_, + up_resource_manager& up_mng_, + cu_cp_measurement_handler& meas_handler_) { cu_cp_rrc_ue_handler = &cu_cp_rrc_ue_; ue_removal_handler = &ue_removal_handler_; @@ -257,12 +257,12 @@ class rrc_ue_cu_cp_adapter : public rrc_ue_context_update_notifier, public rrc_u } private: - cu_cp_rrc_ue_interface* cu_cp_rrc_ue_handler = nullptr; - cu_cp_ue_removal_handler* ue_removal_handler = nullptr; - up_resource_manager* up_mng = nullptr; - cu_cp_controller* controller = nullptr; - cu_cp_measurement_handler* meas_handler = nullptr; - ue_index_t ue_index; + cu_cp_rrc_ue_interface* cu_cp_rrc_ue_handler = nullptr; + cu_cp_ue_removal_handler* ue_removal_handler = nullptr; + up_resource_manager* up_mng = nullptr; + cu_cp_ue_admission_controller* controller = nullptr; + cu_cp_measurement_handler* meas_handler = nullptr; + ue_index_t ue_index; }; } // namespace srs_cu_cp diff --git a/lib/cu_cp/cu_cp_controller/cu_cp_controller.h b/lib/cu_cp/cu_cp_controller/cu_cp_controller.h index 0a7cfab042..9f5799e26e 100644 --- a/lib/cu_cp/cu_cp_controller/cu_cp_controller.h +++ b/lib/cu_cp/cu_cp_controller/cu_cp_controller.h @@ -11,6 +11,7 @@ #pragma once #include "amf_connection_manager.h" +#include "cu_cp_ue_admission_controller.h" #include "cu_up_connection_manager.h" #include "du_connection_manager.h" #include "node_connection_notifier.h" @@ -31,7 +32,7 @@ class ue_manager; /// - determining whether a new DU setup request should be accepted based on the status of other remote node /// connections; /// - determining whether new UEs should be accepted depending on the status of the CU-CP remote connections. -class cu_cp_controller +class cu_cp_controller : public cu_cp_ue_admission_controller { public: cu_cp_controller(const cu_cp_configuration& config_, @@ -49,7 +50,7 @@ class cu_cp_controller bool handle_du_setup_request(du_index_t du_idx, const du_setup_request& req); /// \brief Determines whether the CU-CP should accept a new UE connection. - bool request_ue_setup() const; + bool request_ue_setup() const override; cu_cp_f1c_handler& get_f1c_handler() { return du_mng; } cu_cp_e1_handler& get_e1_handler() { return cu_up_mng; } diff --git a/lib/cu_cp/cu_cp_controller/cu_cp_ue_admission_controller.h b/lib/cu_cp/cu_cp_controller/cu_cp_ue_admission_controller.h new file mode 100644 index 0000000000..fcc60af980 --- /dev/null +++ b/lib/cu_cp/cu_cp_controller/cu_cp_ue_admission_controller.h @@ -0,0 +1,26 @@ +/* + * + * 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 + +namespace srsran { +namespace srs_cu_cp { + +class cu_cp_ue_admission_controller +{ +public: + virtual ~cu_cp_ue_admission_controller() = default; + + /// Determines whether the CU-CP is in a condition to accept new UEs. + virtual bool request_ue_setup() const = 0; +}; + +} // namespace srs_cu_cp +} // namespace srsran \ No newline at end of file diff --git a/lib/cu_cp/du_processor/du_processor.h b/lib/cu_cp/du_processor/du_processor.h index 4ad70804eb..07723880f8 100644 --- a/lib/cu_cp/du_processor/du_processor.h +++ b/lib/cu_cp/du_processor/du_processor.h @@ -23,21 +23,6 @@ namespace srs_cu_cp { /// Forward declared messages. struct rrc_ue_creation_message; -/// Interface for an F1AP notifier to communicate with the DU processor. -class du_processor_f1ap_interface -{ -public: - virtual ~du_processor_f1ap_interface() = default; - - /// \brief Request to create a new UE RRC context. - /// - /// This method should be called when a C-RNTI and PCell are assigned to a UE. - /// \param req Request to setup a new UE RRC context. - /// \return Response to whether the request was successful or failed. - virtual ue_rrc_context_creation_outcome - handle_ue_rrc_context_creation_request(const ue_rrc_context_creation_request& req) = 0; -}; - /// Interface to notify UE context management procedures. class du_processor_f1ap_ue_context_notifier { @@ -192,17 +177,6 @@ class du_processor_mobility_handler virtual byte_buffer get_packed_sib1(nr_cell_global_id_t cgi) = 0; }; -/// Interface to notify the F1AP about control messages. -class du_processor_f1ap_control_notifier -{ -public: - virtual ~du_processor_f1ap_control_notifier() = default; - - /// \brief Notify about the reception of a new PDU Session Resource Setup List. - virtual async_task - on_new_pdu_session_resource_setup_request(f1ap_ue_context_modification_request& msg) = 0; -}; - /// Methods used by DU processor to notify about DU specific events. class du_processor_cu_cp_notifier { @@ -265,17 +239,6 @@ class du_repository_ngap_handler virtual void handle_paging_message(cu_cp_paging_message& msg) = 0; }; -/// Methods to get statistics of the DU processor. -class du_processor_statistics_handler -{ -public: - virtual ~du_processor_statistics_handler() = default; - - /// \brief Returns the number of connected UEs at the DU processor - /// \return The number of connected UEs. - virtual size_t get_nof_ues() const = 0; -}; - class du_processor : public du_processor_cell_info_interface { public: @@ -284,10 +247,8 @@ class du_processor : public du_processor_cell_info_interface /// \brief Retrieve F1AP handler for the respective DU. virtual f1ap_cu& get_f1ap_handler() = 0; - virtual du_processor_f1ap_interface& get_f1ap_interface() = 0; - virtual du_processor_paging_handler& get_paging_handler() = 0; - virtual du_processor_statistics_handler& get_statistics_handler() = 0; - virtual du_processor_mobility_handler& get_mobility_handler() = 0; + virtual du_processor_paging_handler& get_paging_handler() = 0; + virtual du_processor_mobility_handler& get_mobility_handler() = 0; /// \brief Get the F1AP message handler interface of the DU processor object. /// \return The F1AP message handler interface of the DU processor object. diff --git a/lib/cu_cp/du_processor/du_processor_impl.h b/lib/cu_cp/du_processor/du_processor_impl.h index 85fa6a5f2f..054a7b743e 100644 --- a/lib/cu_cp/du_processor/du_processor_impl.h +++ b/lib/cu_cp/du_processor/du_processor_impl.h @@ -29,9 +29,7 @@ namespace srs_cu_cp { class du_processor_impl : public du_processor, public du_metrics_handler, - public du_processor_f1ap_interface, public du_processor_paging_handler, - public du_processor_statistics_handler, public du_processor_mobility_handler { public: @@ -49,17 +47,7 @@ class du_processor_impl : public du_processor, f1ap_cu& get_f1ap_handler() override { return *f1ap; }; - size_t get_nof_ues() const override { return ue_mng.get_nof_du_ues(cfg.du_index); }; - - // du_processor_f1ap_interface - - /// \brief Request to create a new UE RRC context. - /// - /// This method should be called when a C-RNTI and PCell are assigned to a UE. - /// \param req Request to setup a new UE RRC context. - /// \return Response to whether the request was successful or failed. - ue_rrc_context_creation_outcome - handle_ue_rrc_context_creation_request(const ue_rrc_context_creation_request& req) override; + size_t get_nof_ues() const { return ue_mng.get_nof_du_ues(cfg.du_index); }; // du_processor_mobility_manager_interface std::optional get_cgi(pci_t pci) override; @@ -74,9 +62,7 @@ class du_processor_impl : public du_processor, metrics_report::du_info handle_du_metrics_report_request() const override; - du_processor_f1ap_interface& get_f1ap_interface() override { return *this; } du_processor_paging_handler& get_paging_handler() override { return *this; } - du_processor_statistics_handler& get_statistics_handler() override { return *this; } du_processor_mobility_handler& get_mobility_handler() override { return *this; } du_processor_f1ap_ue_context_notifier& get_f1ap_ue_context_notifier() override { return f1ap_ue_context_notifier; } du_metrics_handler& get_metrics_handler() override { return *this; } @@ -84,6 +70,13 @@ class du_processor_impl : public du_processor, private: class f1ap_du_processor_adapter; + /// \brief Request to create a new UE RRC context. + /// + /// This method should be called when a C-RNTI and PCell are assigned to a UE. + /// \param req Request to setup a new UE RRC context. + /// \return Response to whether the request was successful or failed. + ue_rrc_context_creation_outcome handle_ue_rrc_context_creation_request(const ue_rrc_context_creation_request& req); + du_setup_result handle_du_setup_request(const du_setup_request& req); /// \brief Handle the reception of a F1AP UE Context Release Request and notify NGAP. diff --git a/lib/cu_cp/ue_manager/ue_manager_impl.h b/lib/cu_cp/ue_manager/ue_manager_impl.h index e7639f41f9..97f7ee7b2a 100644 --- a/lib/cu_cp/ue_manager/ue_manager_impl.h +++ b/lib/cu_cp/ue_manager/ue_manager_impl.h @@ -17,6 +17,7 @@ #include "cu_cp_ue_impl.h" #include "ue_metrics_handler.h" #include "ue_task_scheduler_impl.h" +#include "srsran/cu_cp/cu_cp_configuration.h" #include "srsran/cu_cp/security_manager_config.h" #include "srsran/cu_cp/ue_configuration.h" #include diff --git a/tests/unittests/cu_cp/du_processor/CMakeLists.txt b/tests/unittests/cu_cp/du_processor/CMakeLists.txt index 73b1f21dd9..7644716e6f 100644 --- a/tests/unittests/cu_cp/du_processor/CMakeLists.txt +++ b/tests/unittests/cu_cp/du_processor/CMakeLists.txt @@ -28,4 +28,5 @@ set(SOURCES add_executable(du_processor_test ${SOURCES}) target_include_directories(du_processor_test PRIVATE ${CMAKE_SOURCE_DIR}) target_link_libraries(du_processor_test du_processor_test_helpers srsran_support srslog gtest gtest_main) -gtest_discover_tests(du_processor_test PROPERTIES "LABELS;du_processor") +add_test(du_processor_test du_processor_test) +set_tests_properties(du_processor_test PROPERTIES LABELS "LABELS;du_processor") diff --git a/tests/unittests/cu_cp/du_processor/du_processor_test.cpp b/tests/unittests/cu_cp/du_processor/du_processor_test.cpp index f82370ff0f..93e7f70625 100644 --- a/tests/unittests/cu_cp/du_processor/du_processor_test.cpp +++ b/tests/unittests/cu_cp/du_processor/du_processor_test.cpp @@ -11,6 +11,7 @@ #include "../du_processor_test_messages.h" #include "du_processor_test_helpers.h" #include "lib/cu_cp/du_processor/du_processor.h" +#include "tests/test_doubles/f1ap/f1ap_test_messages.h" #include "tests/unittests/f1ap/common/f1ap_cu_test_messages.h" #include "srsran/asn1/f1ap/f1ap_pdu_contents.h" #include "srsran/cu_cp/cu_cp_types.h" @@ -91,110 +92,35 @@ TEST_F(du_processor_test, when_max_nof_du_cells_exeeded_then_f1setup_rejected) /* UE creation */ ////////////////////////////////////////////////////////////////////////////////////// -TEST_F(du_processor_test, when_ue_creation_msg_valid_then_ue_added) +class du_processor_ue_creation_test : public du_processor_test { - // Pass message to DU processor - du_processor_obj->get_f1ap_handler().get_f1ap_message_handler().handle_message( - test_helpers::generate_f1_setup_request()); - - // Generate ue_creation message - ue_rrc_context_creation_request req = generate_ue_rrc_context_creation_request( - ue_index_t::invalid, rnti_t::MIN_CRNTI, nr_cell_identity::create(gnb_id_t{411, 22}, 0).value()); - - // Pass message to DU processor - ue_rrc_context_creation_outcome outcome = - du_processor_obj->get_f1ap_interface().handle_ue_rrc_context_creation_request(req); - ASSERT_TRUE(outcome.has_value()); - - ASSERT_EQ(du_processor_obj->get_statistics_handler().get_nof_ues(), 1); -} - -TEST_F(du_processor_test, when_cell_id_invalid_then_ue_creation_fails) -{ - // Generate valid F1SetupRequest and pass it to DU processor - du_processor_obj->get_f1ap_handler().get_f1ap_message_handler().handle_message( - test_helpers::generate_f1_setup_request()); - - // Generate ue_creation message - ue_rrc_context_creation_request req = generate_ue_rrc_context_creation_request( - ue_index_t::invalid, rnti_t::MIN_CRNTI, nr_cell_identity::create(1).value()); +protected: + du_processor_ue_creation_test() + { + du_processor_obj->get_f1ap_handler().get_f1ap_message_handler().handle_message( + test_helpers::generate_f1_setup_request()); + } - // Pass message to DU processor - ue_rrc_context_creation_outcome outcome = - du_processor_obj->get_f1ap_interface().handle_ue_rrc_context_creation_request(req); - ASSERT_TRUE(not outcome.has_value()); -} + static f1ap_message create_valid_ue_creation_message() + { + return test_helpers::create_init_ul_rrc_message_transfer(gnb_du_ue_f1ap_id_t{0}, rnti_t::MIN_CRNTI); + } +}; -TEST_F(du_processor_test, when_ue_rrc_context_exists_then_new_ue_rrc_context_not_added) +TEST_F(du_processor_ue_creation_test, when_init_ul_rrc_message_is_valid_then_ue_added) { - // Generate valid F1SetupRequest - du_setup_request f1_setup_request; - generate_valid_f1_setup_request(f1_setup_request); - - // Pass message to DU processor du_processor_obj->get_f1ap_handler().get_f1ap_message_handler().handle_message( - test_helpers::generate_f1_setup_request()); - - // Generate ue_creation message - ue_rrc_context_creation_request req = generate_ue_rrc_context_creation_request( - ue_index_t::invalid, rnti_t::MIN_CRNTI, nr_cell_identity::create(gnb_id_t{411, 22}, 0).value()); - - // Pass message to DU processor - ue_rrc_context_creation_outcome outcome = - du_processor_obj->get_f1ap_interface().handle_ue_rrc_context_creation_request(req); - ASSERT_TRUE(outcome.has_value()); + this->create_valid_ue_creation_message()); - ASSERT_EQ(du_processor_obj->get_statistics_handler().get_nof_ues(), 1); - - // Pass same message to DU processor again - req.ue_index = outcome->ue_index; - ue_rrc_context_creation_outcome outcome2 = - du_processor_obj->get_f1ap_interface().handle_ue_rrc_context_creation_request(req); - ASSERT_TRUE(not outcome2.has_value()); - - ASSERT_EQ(du_processor_obj->get_statistics_handler().get_nof_ues(), 1); + ASSERT_EQ(ue_mng.get_nof_ues(), 1); } -TEST_F(du_processor_test, when_max_nof_ues_exceeded_then_ue_not_added) +TEST_F(du_processor_ue_creation_test, when_init_ul_rrc_message_is_invalid_then_ue_is_not_added) { - // Generate valid F1SetupRequest and pass it to DU processor - du_processor_obj->get_f1ap_handler().get_f1ap_message_handler().handle_message( - test_helpers::generate_f1_setup_request()); - - // Reduce logger loglevel to warning to reduce console output - srslog::fetch_basic_logger("CU-CP").set_level(srslog::basic_levels::warning); - srslog::fetch_basic_logger("RRC").set_level(srslog::basic_levels::warning); - srslog::fetch_basic_logger("CU-UEMNG").set_level(srslog::basic_levels::warning); - srslog::fetch_basic_logger("TEST").set_level(srslog::basic_levels::warning); - - // Add the maximum number of UEs - for (unsigned it = 0; it < cu_cp_cfg.admission.max_nof_ues; it++) { - // Generate ue_creation message - rnti_t c_rnti = to_rnti(it + 1); // 0 is not a valid RNTI - ue_rrc_context_creation_request req = generate_ue_rrc_context_creation_request( - ue_index_t::invalid, c_rnti, nr_cell_identity::create(gnb_id_t{411, 22}, 0).value()); - - // Pass message to DU processor - ue_rrc_context_creation_outcome outcome = - du_processor_obj->get_f1ap_interface().handle_ue_rrc_context_creation_request(req); - ASSERT_TRUE(outcome.has_value()); - } - - // Reset logger loglevel - srslog::fetch_basic_logger("CU-CP").set_level(srslog::basic_levels::debug); - srslog::fetch_basic_logger("RRC").set_level(srslog::basic_levels::debug); - srslog::fetch_basic_logger("CU-UEMNG").set_level(srslog::basic_levels::debug); - srslog::fetch_basic_logger("TEST").set_level(srslog::basic_levels::debug); - - ASSERT_EQ(du_processor_obj->get_statistics_handler().get_nof_ues(), cu_cp_cfg.admission.max_nof_ues); + f1ap_message msg = this->create_valid_ue_creation_message(); + msg.pdu.init_msg().value.init_ul_rrc_msg_transfer()->nr_cgi.nr_cell_id.from_number(1); - // Try to add additional UE - rnti_t c_rnti = to_rnti(cu_cp_cfg.admission.max_nof_ues + 1); - ue_rrc_context_creation_request req = generate_ue_rrc_context_creation_request( - ue_index_t::invalid, c_rnti, nr_cell_identity::create(gnb_id_t{411, 22}, 0).value()); - ue_rrc_context_creation_outcome outcome = - du_processor_obj->get_f1ap_interface().handle_ue_rrc_context_creation_request(req); - ASSERT_TRUE(not outcome.has_value()); + du_processor_obj->get_f1ap_handler().get_f1ap_message_handler().handle_message(msg); - ASSERT_EQ(du_processor_obj->get_statistics_handler().get_nof_ues(), cu_cp_cfg.admission.max_nof_ues); + ASSERT_EQ(ue_mng.get_nof_ues(), 0); } diff --git a/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.cpp b/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.cpp index 1d34e1d287..bc30b78554 100644 --- a/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.cpp +++ b/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.cpp @@ -30,6 +30,82 @@ class dummy_task_sched final : public common_task_scheduler fifo_async_task_scheduler task_sched{32}; }; +struct dummy_cu_cp_ue_admission_controller : public cu_cp_ue_admission_controller { + bool request_ue_setup() const override { return true; } +}; + +struct dummy_cu_cp_measurement_handler : public cu_cp_measurement_handler { + std::optional + handle_measurement_config_request(ue_index_t ue_index, + nr_cell_identity nci, + std::optional current_meas_config = {}) override + { + return std::nullopt; + }; + void handle_measurement_report(const ue_index_t ue_index, const rrc_meas_results& meas_results) override {} +}; + +struct dummy_cu_cp_ue_removal_handler : public cu_cp_ue_removal_handler { + async_task handle_ue_removal_request(ue_index_t ue_index) override { return launch_no_op_task(); } + void handle_pending_ue_task_cancellation(ue_index_t ue_index) override {} +}; + +struct dummy_cu_cp_rrc_ue_interface : public cu_cp_rrc_ue_interface { + rrc_ue_reestablishment_context_response + handle_rrc_reestablishment_request(pci_t old_pci, rnti_t old_c_rnti, ue_index_t ue_index) override + { + return {}; + } + async_task handle_rrc_reestablishment_context_modification_required(ue_index_t ue_index) override + { + return launch_no_op_task(true); + } + void handle_rrc_reestablishment_failure(const cu_cp_ue_context_release_request& request) override {} + void handle_rrc_reestablishment_complete(ue_index_t old_ue_index) override {} + async_task handle_ue_context_transfer(ue_index_t ue_index, ue_index_t old_ue_index) override + { + return launch_no_op_task(true); + } + async_task handle_ue_context_release(const cu_cp_ue_context_release_request& request) override + { + return launch_no_op_task(); + } +}; + +struct dummy_cu_cp_du_event_handler : public cu_cp_du_event_handler { +public: + dummy_cu_cp_du_event_handler(ue_manager& ue_mng_) : ue_mng(ue_mng_) {} + + void handle_du_processor_creation(du_index_t du_index, + f1ap_ue_context_removal_handler& f1ap_handler, + f1ap_statistics_handler& f1ap_statistic_handler, + rrc_ue_handler& rrc_handler, + rrc_du_statistics_handler& rrc_statistic_handler) override + { + } + void handle_du_processor_removal(du_index_t du_index) override {} + void handle_rrc_ue_creation(ue_index_t ue_index, rrc_ue_interface& rrc_ue) override + { + ue_mng.get_rrc_ue_cu_cp_adapter(ue_index).connect_cu_cp(rrc_ue_handler, + ue_rem_handler, + ue_admission_handler, + ue_mng.find_ue(ue_index)->get_up_resource_manager(), + meas_handler); + } + byte_buffer handle_target_cell_sib1_required(du_index_t du_index, nr_cell_global_id_t cgi) override { return {}; } + async_task handle_transaction_info_loss(const f1_ue_transaction_info_loss_event& ev) override + { + return launch_no_op_task(); + } + +private: + ue_manager& ue_mng; + dummy_cu_cp_ue_admission_controller ue_admission_handler; + dummy_cu_cp_measurement_handler meas_handler; + dummy_cu_cp_ue_removal_handler ue_rem_handler; + dummy_cu_cp_rrc_ue_interface rrc_ue_handler; +}; + } // namespace du_processor_test::du_processor_test() : @@ -60,6 +136,9 @@ du_processor_test::du_processor_test() : rrc_du_cu_cp_notifier, *common_task_sched, ue_mng); + + cu_cp_event_handler = std::make_unique(ue_mng); + cu_cp_notifier.attach_handler(&*cu_cp_event_handler, nullptr); } du_processor_test::~du_processor_test() @@ -67,23 +146,3 @@ du_processor_test::~du_processor_test() // flush logger after each test srslog::flush(); } - -void du_processor_test::attach_ue() -{ - // Generate valid F1SetupRequest - f1ap_message f1_setup_req = test_helpers::generate_f1_setup_request(); - // Pass message to DU processor - du_processor_obj->get_f1ap_handler().get_f1ap_message_handler().handle_message(f1_setup_req); - - // Generate ue_creation message - ue_index_t ue_index = ue_index_t::min; - ue_rrc_context_creation_request req = generate_ue_rrc_context_creation_request( - ue_index, rnti_t::MIN_CRNTI, nr_cell_identity::create(cu_cp_cfg.node.gnb_id, 0).value()); - // Pass message to DU processor - du_processor_obj->get_f1ap_interface().handle_ue_rrc_context_creation_request(req); -} - -void du_processor_test::receive_rrc_reconfig_complete() -{ - // inject RRC Reconfiguration complete into UE object -} diff --git a/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.h b/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.h index 00370efe8b..df3c81dab0 100644 --- a/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.h +++ b/tests/unittests/cu_cp/du_processor/du_processor_test_helpers.h @@ -12,6 +12,7 @@ #include "../test_helpers.h" #include "du_processor_test_helpers.h" +#include "lib/cu_cp/cu_cp_controller/cu_cp_ue_admission_controller.h" #include "lib/cu_cp/du_processor/du_configuration_manager.h" #include "lib/cu_cp/du_processor/du_processor.h" #include "lib/cu_cp/du_processor/du_processor_factory.h" @@ -33,10 +34,6 @@ class du_processor_test : public ::testing::Test du_processor_test(); ~du_processor_test() override; - void attach_ue(); - - void receive_rrc_reconfig_complete(); - srslog::basic_logger& test_logger = srslog::fetch_basic_logger("TEST"); srslog::basic_logger& cu_cp_logger = srslog::fetch_basic_logger("CU-CP"); @@ -44,17 +41,18 @@ class du_processor_test : public ::testing::Test manual_task_worker ctrl_worker{128}; cu_cp_configuration cu_cp_cfg; - ue_manager ue_mng{cu_cp_cfg}; - dummy_ngap_ue_context_removal_handler ngap_ue_removal_handler; - dummy_du_processor_cu_cp_notifier cu_cp_notifier{&ue_mng}; - dummy_du_connection_notifier du_conn_notifier; - dummy_f1ap_pdu_notifier f1ap_pdu_notifier; - dummy_rrc_ue_ngap_adapter rrc_ue_ngap_notifier; - dummy_rrc_ue_cu_cp_adapter rrc_ue_cu_cp_notifier; - dummy_rrc_du_cu_cp_adapter rrc_du_cu_cp_notifier; - std::unique_ptr common_task_sched; - du_configuration_manager du_cfg_mgr; - std::unique_ptr du_processor_obj; + ue_manager ue_mng{cu_cp_cfg}; + dummy_ngap_ue_context_removal_handler ngap_ue_removal_handler; + dummy_du_processor_cu_cp_notifier cu_cp_notifier{&ue_mng}; + dummy_du_connection_notifier du_conn_notifier; + dummy_f1ap_pdu_notifier f1ap_pdu_notifier; + dummy_rrc_ue_ngap_adapter rrc_ue_ngap_notifier; + dummy_rrc_ue_cu_cp_adapter rrc_ue_cu_cp_notifier; + dummy_rrc_du_cu_cp_adapter rrc_du_cu_cp_notifier; + std::unique_ptr cu_cp_event_handler; + std::unique_ptr common_task_sched; + du_configuration_manager du_cfg_mgr; + std::unique_ptr du_processor_obj; async_task t; std::optional> t_launcher; From 6d453855a565b98e4c3de208e3df7169ab6e4e18 Mon Sep 17 00:00:00 2001 From: Fabian Eckermann Date: Fri, 19 Jul 2024 13:03:24 +0200 Subject: [PATCH 22/54] cu_cp,ngap: improve error indication error message --- lib/ngap/ngap_impl.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/ngap/ngap_impl.cpp b/lib/ngap/ngap_impl.cpp index 2f79589e2d..e8fb231fff 100644 --- a/lib/ngap/ngap_impl.cpp +++ b/lib/ngap/ngap_impl.cpp @@ -364,7 +364,7 @@ void ngap_impl::handle_dl_nas_transport_message(const asn1::ngap::dl_nas_transpo if (ue_ctxt.release_scheduled) { ue_ctxt.logger.log_info("Dropping DlNasTransportMessage. UE is already scheduled for release"); stored_error_indications.emplace(ue_ctxt.ue_ids.ue_index, - error_indication_request_t{ngap_cause_radio_network_t::unknown_local_ue_ngap_id, + error_indication_request_t{ngap_cause_radio_network_t::interaction_with_other_proc, ue_ctxt.ue_ids.ran_ue_id, uint_to_amf_ue_id(msg->amf_ue_ngap_id)}); return; @@ -410,7 +410,7 @@ void ngap_impl::handle_initial_context_setup_request(const asn1::ngap::init_cont if (ue_ctxt.release_scheduled) { ue_ctxt.logger.log_info("Dropping InitialContextSetup. UE is already scheduled for release"); stored_error_indications.emplace(ue_ctxt.ue_ids.ue_index, - error_indication_request_t{ngap_cause_radio_network_t::unknown_local_ue_ngap_id, + error_indication_request_t{ngap_cause_radio_network_t::interaction_with_other_proc, ue_ctxt.ue_ids.ran_ue_id, uint_to_amf_ue_id(request->amf_ue_ngap_id)}); return; @@ -474,7 +474,7 @@ void ngap_impl::handle_pdu_session_resource_setup_request(const asn1::ngap::pdu_ if (ue_ctxt.release_scheduled) { ue_ctxt.logger.log_info("Dropping PduSessionResourceSetupRequest. UE is already scheduled for release"); stored_error_indications.emplace(ue_ctxt.ue_ids.ue_index, - error_indication_request_t{ngap_cause_radio_network_t::unknown_local_ue_ngap_id, + error_indication_request_t{ngap_cause_radio_network_t::interaction_with_other_proc, ue_ctxt.ue_ids.ran_ue_id, uint_to_amf_ue_id(request->amf_ue_ngap_id)}); return; @@ -531,7 +531,7 @@ void ngap_impl::handle_pdu_session_resource_modify_request(const asn1::ngap::pdu if (ue_ctxt.release_scheduled) { ue_ctxt.logger.log_info("Dropping PduSessionResourceModifyRequest. UE is already scheduled for release"); stored_error_indications.emplace(ue_ctxt.ue_ids.ue_index, - error_indication_request_t{ngap_cause_radio_network_t::unknown_local_ue_ngap_id, + error_indication_request_t{ngap_cause_radio_network_t::interaction_with_other_proc, ue_ctxt.ue_ids.ran_ue_id, uint_to_amf_ue_id(request->amf_ue_ngap_id)}); return; @@ -593,7 +593,7 @@ void ngap_impl::handle_pdu_session_resource_release_command(const asn1::ngap::pd if (ue_ctxt.release_scheduled) { ue_ctxt.logger.log_info("Dropping PduSessionResourceReleaseCommand. UE is already scheduled for release"); stored_error_indications.emplace(ue_ctxt.ue_ids.ue_index, - error_indication_request_t{ngap_cause_radio_network_t::unknown_local_ue_ngap_id, + error_indication_request_t{ngap_cause_radio_network_t::interaction_with_other_proc, ue_ctxt.ue_ids.ran_ue_id, uint_to_amf_ue_id(command->amf_ue_ngap_id)}); return; @@ -660,7 +660,7 @@ void ngap_impl::handle_ue_context_release_command(const asn1::ngap::ue_context_r if (ue_ctxt.release_scheduled) { ue_ctxt.logger.log_info("Dropping UeContextReleaseCommand. UE is already scheduled for release"); stored_error_indications.emplace(ue_ctxt.ue_ids.ue_index, - error_indication_request_t{ngap_cause_radio_network_t::unknown_local_ue_ngap_id, + error_indication_request_t{ngap_cause_radio_network_t::interaction_with_other_proc, ue_ctxt.ue_ids.ran_ue_id, amf_ue_id}); return; From 21986e36fc39fe01d9506075d42f5844ee84a297 Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 19 Jul 2024 12:36:00 +0200 Subject: [PATCH 23/54] phy: initial transform precoding component phy: review transform precoding related --- .../transform_precoding/transform_precoder.h | 46 +++++++++ .../transform_precoding_factories.h | 39 ++++++++ .../transform_precoding_helpers.h | 55 +++++++++++ lib/phy/generic_functions/CMakeLists.txt | 1 + .../transform_precoding/CMakeLists.txt | 15 +++ .../tansform_precoding_factories.cpp | 63 ++++++++++++ .../transform_precoder_dft_impl.cpp | 45 +++++++++ .../transform_precoder_dft_impl.h | 57 +++++++++++ tests/unittests/CMakeLists.txt | 1 + .../phy/generic_functions/CMakeLists.txt | 1 + .../transform_precoding/CMakeLists.txt | 24 +++++ .../transform_precoder_test_data.h | 86 ++++++++++++++++ .../transform_precoder_test_data.tar.gz | 3 + .../transform_precoder_vectortest.cpp | 97 +++++++++++++++++++ 14 files changed, 533 insertions(+) create mode 100644 include/srsran/phy/generic_functions/transform_precoding/transform_precoder.h create mode 100644 include/srsran/phy/generic_functions/transform_precoding/transform_precoding_factories.h create mode 100644 include/srsran/ran/transform_precoding/transform_precoding_helpers.h create mode 100644 lib/phy/generic_functions/transform_precoding/CMakeLists.txt create mode 100644 lib/phy/generic_functions/transform_precoding/tansform_precoding_factories.cpp create mode 100644 lib/phy/generic_functions/transform_precoding/transform_precoder_dft_impl.cpp create mode 100644 lib/phy/generic_functions/transform_precoding/transform_precoder_dft_impl.h create mode 100644 tests/unittests/phy/generic_functions/transform_precoding/CMakeLists.txt create mode 100644 tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_test_data.h create mode 100644 tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_test_data.tar.gz create mode 100644 tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_vectortest.cpp diff --git a/include/srsran/phy/generic_functions/transform_precoding/transform_precoder.h b/include/srsran/phy/generic_functions/transform_precoding/transform_precoder.h new file mode 100644 index 0000000000..bea47c040c --- /dev/null +++ b/include/srsran/phy/generic_functions/transform_precoding/transform_precoder.h @@ -0,0 +1,46 @@ +/* + * + * 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. + * + */ + +/// \file +/// \brief Transform precoding interfaces. + +#pragma once + +#include "srsran/adt/complex.h" +#include "srsran/adt/span.h" + +namespace srsran { + +/// \brief Transform precoder interface. +/// +/// The transform precoding process is described in TS38.211 Section 6.3.1.4 for PUSCH and Section 6.3.2.6.4 for PUCCH. +/// +class transform_precoder +{ +public: + /// Default destructor. + virtual ~transform_precoder() = default; + + /// \brief Reverts the transform precoding for a single OFDM symbol. + /// + /// The number of elements to deprecode \f$M_{sc}\f$ determines the number of resource blocks + /// \f$M_{RB} = \frac{M_{sc}}{N_{sc}^{RB}}\f$. + /// + /// The function \ref is_transform_precoding_nof_prb_valid determines whether a number of resource blocks is valid. + /// + /// \param[out] out Transform deprecoding output. + /// \param[in] in Transform deprecoding input. + /// \remark An assertion is triggered if the size of \c in and \c out are not equal. + /// \remark An assertion is triggered if the number of RB to deprecode is invalid. + /// \remark An assertion is triggered if the number of RB exceeds the maximum initialized number of RB. + virtual void deprecode_ofdm_symbol(span out, span in) = 0; +}; + +} // namespace srsran diff --git a/include/srsran/phy/generic_functions/transform_precoding/transform_precoding_factories.h b/include/srsran/phy/generic_functions/transform_precoding/transform_precoding_factories.h new file mode 100644 index 0000000000..4ced367b36 --- /dev/null +++ b/include/srsran/phy/generic_functions/transform_precoding/transform_precoding_factories.h @@ -0,0 +1,39 @@ +/* + * + * 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. + * + */ + +/// \file +/// \brief Transform precoding factories. + +#pragma once + +#include "srsran/phy/generic_functions/generic_functions_factories.h" +#include "srsran/phy/generic_functions/transform_precoding/transform_precoder.h" +#include + +namespace srsran { + +/// Factory that builds transform precoder objects. +class transform_precoder_factory +{ +public: + /// Default destructor. + virtual ~transform_precoder_factory() = default; + + /// Creates and returns a transform precoder object. + virtual std::unique_ptr create() = 0; +}; + +/// \brief Creates and returns a transform precoder factory based on the DFT algorithm. +/// +/// \return A transform precoder factory. +std::shared_ptr +create_dft_transform_precoder_factory(std::shared_ptr, unsigned max_nof_prb); + +} // namespace srsran diff --git a/include/srsran/ran/transform_precoding/transform_precoding_helpers.h b/include/srsran/ran/transform_precoding/transform_precoding_helpers.h new file mode 100644 index 0000000000..173d4666b3 --- /dev/null +++ b/include/srsran/ran/transform_precoding/transform_precoding_helpers.h @@ -0,0 +1,55 @@ +/* + * + * 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. + * + */ + +/// \file +/// \brief Transform precoding valid sizes. +/// +/// A number of physical blocs for transform precoding is valid if satisfies \f$M_{RB} = 2^{\alpha _2}\cdot 3^{\alpha +/// _3}\cdot 5^{\alpha _5}\f$ where \f$\alpha _2\f$, \f$\alpha _3\f$ and \f$\alpha _3\f$ are non-negative integers. + +#pragma once + +#include "srsran/adt/span.h" +#include "srsran/ran/resource_block.h" + +namespace srsran { + +/// Gets a boolean span where each position indicates if it is a valid number of RB for transform precoding. +inline span get_transform_precoding_valid_nof_prb() +{ + static constexpr std::array mask = { + false, true, true, true, true, true, true, false, true, true, true, false, true, false, false, true, + true, false, true, false, true, false, false, false, true, true, false, true, false, false, true, false, + true, false, false, false, true, false, false, false, true, false, false, false, false, true, false, false, + true, false, true, false, false, false, true, false, false, false, false, false, true, false, false, false, + true, false, false, false, false, false, false, false, true, false, false, true, false, false, false, false, + true, true, false, false, false, false, false, false, false, false, true, false, false, false, false, false, + true, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false, + false, false, false, false, false, false, false, false, true, false, false, false, false, true, false, false, + true, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, + true, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, + true, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, + true, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, + false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, + true, false, false, true, false, false, false, false, false, false, true, false, false, false, false, false, + true, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, + false, false, false}; + return mask; +} + +/// Determines whether a number of PRB is valid. +inline bool is_transform_precoding_nof_prb_valid(unsigned nof_prb) +{ + return get_transform_precoding_valid_nof_prb()[nof_prb]; +} + +} // namespace srsran diff --git a/lib/phy/generic_functions/CMakeLists.txt b/lib/phy/generic_functions/CMakeLists.txt index a84830dc47..0ad51b1bb9 100644 --- a/lib/phy/generic_functions/CMakeLists.txt +++ b/lib/phy/generic_functions/CMakeLists.txt @@ -7,6 +7,7 @@ # add_subdirectory(precoding) +add_subdirectory(transform_precoding) # Initialise DFT sources and definitions for DFT libraries. set(SRSRAN_DFT_SOURCES dft_processor_generic_impl.cpp) diff --git a/lib/phy/generic_functions/transform_precoding/CMakeLists.txt b/lib/phy/generic_functions/transform_precoding/CMakeLists.txt new file mode 100644 index 0000000000..028c97b0a2 --- /dev/null +++ b/lib/phy/generic_functions/transform_precoding/CMakeLists.txt @@ -0,0 +1,15 @@ +# +# 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. +# + +set(transform_precoding_sources + transform_precoder_dft_impl.cpp + tansform_precoding_factories.cpp) + +add_library(srsran_transform_precoding STATIC ${transform_precoding_sources}) + +add_to_exported_libs(srsran_transform_precoding) diff --git a/lib/phy/generic_functions/transform_precoding/tansform_precoding_factories.cpp b/lib/phy/generic_functions/transform_precoding/tansform_precoding_factories.cpp new file mode 100644 index 0000000000..a3450e6489 --- /dev/null +++ b/lib/phy/generic_functions/transform_precoding/tansform_precoding_factories.cpp @@ -0,0 +1,63 @@ +/* + * + * 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 "transform_precoder_dft_impl.h" +#include "srsran/phy/generic_functions/transform_precoding/transform_precoding_factories.h" +#include "srsran/ran/transform_precoding/transform_precoding_helpers.h" + +#include + +using namespace srsran; + +namespace { + +/// Implements a transform precoder factory based on DFT algorithm. +class transform_precoder_dft_factory : public transform_precoder_factory +{ +public: + transform_precoder_dft_factory(std::shared_ptr dft_factory_, unsigned max_nof_prb_) : + dft_factory(std::move(dft_factory_)), max_nof_prb(max_nof_prb_) + { + srsran_assert(dft_factory, "Invalid DFt factory."); + } + + // See interface for documentation. + std::unique_ptr create() override + { + // Create DFT processors for each valid number of PRBs within the limit. + transform_precoder_dft_impl::collection_dft_processors dft_processors; + for (unsigned nof_prb = 0; nof_prb != max_nof_prb; ++nof_prb) { + if (is_transform_precoding_nof_prb_valid(nof_prb)) { + // Prepare DFT size. + dft_processor::configuration dft_config; + dft_config.dir = dft_processor::direction::INVERSE; + dft_config.size = NRE * nof_prb; + + dft_processors.emplace(nof_prb, dft_factory->create(dft_config)); + } + } + + return std::make_unique(std::move(dft_processors)); + } + +private: + /// DFT processor factory. + std::shared_ptr dft_factory; + /// Maximum number of PRB. + unsigned max_nof_prb; +}; + +} // namespace + +std::shared_ptr +srsran::create_dft_transform_precoder_factory(std::shared_ptr dft_factory, unsigned max_nof_prb) +{ + return std::make_shared(std::move(dft_factory), max_nof_prb); +} diff --git a/lib/phy/generic_functions/transform_precoding/transform_precoder_dft_impl.cpp b/lib/phy/generic_functions/transform_precoding/transform_precoder_dft_impl.cpp new file mode 100644 index 0000000000..1a6d2c1b47 --- /dev/null +++ b/lib/phy/generic_functions/transform_precoding/transform_precoder_dft_impl.cpp @@ -0,0 +1,45 @@ +/* + * + * 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 "transform_precoder_dft_impl.h" +#include "srsran/phy/constants.h" +#include "srsran/ran/transform_precoding/transform_precoding_helpers.h" +#include "srsran/srsvec/copy.h" +#include "srsran/srsvec/sc_prod.h" + +using namespace srsran; + +void transform_precoder_dft_impl::deprecode_ofdm_symbol(span x, span y) +{ + // Extract number of subcarriers. + unsigned M_sc = x.size(); + srsran_assert(x.size() == y.size(), "Input and output sizes must be equal."); + srsran_assert(M_sc % NRE == 0, "The number of subcarriers (i.e., {}) must be muliple of {}.", M_sc, NRE); + + // Calculate number of resource blocks. + unsigned M_rb = M_sc / NRE; + srsran_assert(is_transform_precoding_nof_prb_valid(M_rb), "The number of PRB (i.e., {}) is not valid.", M_rb); + srsran_assert(dft_processors.count(M_rb), "No DFT processor available for the number of PRB (i.e., {}).", M_rb); + + // Calculate scaling factor. + float scaling_factor = 1.0F / std::sqrt(static_cast(M_sc)); + + // Select DFT processor. + dft_processor& dft = *dft_processors.at(M_rb); + + // Convert input data in the DFT input. + srsvec::copy(dft.get_input(), y); + + // Run DFT. + span out = dft.run(); + + // Convert DFT output to DFT output data. + srsvec::sc_prod(out, scaling_factor, x); +} diff --git a/lib/phy/generic_functions/transform_precoding/transform_precoder_dft_impl.h b/lib/phy/generic_functions/transform_precoding/transform_precoder_dft_impl.h new file mode 100644 index 0000000000..0fa9db8501 --- /dev/null +++ b/lib/phy/generic_functions/transform_precoding/transform_precoder_dft_impl.h @@ -0,0 +1,57 @@ +/* + * + * 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/phy/constants.h" +#include "srsran/phy/generic_functions/dft_processor.h" +#include "srsran/phy/generic_functions/transform_precoding/transform_precoder.h" +#include "srsran/ran/transform_precoding/transform_precoding_helpers.h" +#include + +namespace srsran { + +/// Implements a transform precoder based on the DFT algorithm. +class transform_precoder_dft_impl : public transform_precoder +{ +public: + /// Collection of DFT processors type. + using collection_dft_processors = std::unordered_map>; + + /// Implementation. + transform_precoder_dft_impl(collection_dft_processors dft_processors_) : dft_processors(std::move(dft_processors_)) + { +#ifdef ASSERTS_ENABLED + for (const auto& entry : dft_processors) { + unsigned M_rb = entry.first; + unsigned M_sc = M_rb * NRE; + unsigned dft_size = entry.second->get_size(); + srsran_assert( + is_transform_precoding_nof_prb_valid(M_rb), "Invalid number of resource elements (i.e., {}).", M_rb); + srsran_assert(M_sc == dft_size, + "The DFT size (i.e., {}) is not consistent with the number of subcarriers (i.e., {}).", + dft_size, + M_sc); + srsran_assert(entry.second->get_direction() == dft_processor::direction::INVERSE, + "Invalid DFT direction (i.e., {}).", + dft_processor::direction_to_string(entry.second->get_direction())); + } +#endif // ASSERTS_ENABLED + } + + // See interface for documentation. + void deprecode_ofdm_symbol(span out, span in) override; + +private: + /// Collection of valid DFT processors. + collection_dft_processors dft_processors; +}; + +} // namespace srsran diff --git a/tests/unittests/CMakeLists.txt b/tests/unittests/CMakeLists.txt index 626d87d82d..189681af39 100644 --- a/tests/unittests/CMakeLists.txt +++ b/tests/unittests/CMakeLists.txt @@ -22,6 +22,7 @@ add_custom_target(all_vector_tests) macro(ADD_TEST_VECTOR TARGET VECTOR_FILE TEST_ARGS) if (NOT (${VECTOR_FILE} STREQUAL none)) if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${VECTOR_FILE}) + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test_data) add_custom_command( TARGET ${TARGET} POST_BUILD diff --git a/tests/unittests/phy/generic_functions/CMakeLists.txt b/tests/unittests/phy/generic_functions/CMakeLists.txt index 17ac0d1af8..380f267a61 100644 --- a/tests/unittests/phy/generic_functions/CMakeLists.txt +++ b/tests/unittests/phy/generic_functions/CMakeLists.txt @@ -12,6 +12,7 @@ set(TEST_DATA_DIR ${CMAKE_CURRENT_BINARY_DIR}/test_data) set_directory_properties(PROPERTIES LABELS "phy") add_subdirectory(precoding) +add_subdirectory(transform_precoding) add_executable(dft_processor_test dft_processor_test.cpp) target_link_libraries(dft_processor_test srslog srsran_generic_funcs) diff --git a/tests/unittests/phy/generic_functions/transform_precoding/CMakeLists.txt b/tests/unittests/phy/generic_functions/transform_precoding/CMakeLists.txt new file mode 100644 index 0000000000..0a866e267e --- /dev/null +++ b/tests/unittests/phy/generic_functions/transform_precoding/CMakeLists.txt @@ -0,0 +1,24 @@ +# +# 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. +# + +set_directory_properties(PROPERTIES LABELS "phy") + +if (USE_PHY_TESTVECTORS) + add_executable(transform_precoder_vectortest transform_precoder_vectortest.cpp) + + target_link_libraries( + transform_precoder_vectortest + srsran_transform_precoding + srsran_generic_funcs + srslog + srsvec + gtest + gtest_main) + + add_test_vector(transform_precoder_vectortest transform_precoder_test_data.tar.gz "") +endif (USE_PHY_TESTVECTORS) diff --git a/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_test_data.h b/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_test_data.h new file mode 100644 index 0000000000..247b798a02 --- /dev/null +++ b/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_test_data.h @@ -0,0 +1,86 @@ +/* + * + * 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 + +// This file was generated using the following MATLAB class on 19-07-2024 (seed 0): +// + "srsTransformPrecoderUnittest.m" + +#include "srsran/adt/complex.h" +#include "srsran/support/file_vector.h" + +namespace srsran { + +struct test_case_t { + unsigned M_rb; + file_vector deprecode_input; + file_vector deprecode_output; +}; + +static const std::vector transform_precoder_test_data = { +// clang-format off + {1, {"test_data/transform_precoder_test_input0.dat"}, {"test_data/transform_precoder_test_output0.dat"}}, + {2, {"test_data/transform_precoder_test_input1.dat"}, {"test_data/transform_precoder_test_output1.dat"}}, + {3, {"test_data/transform_precoder_test_input2.dat"}, {"test_data/transform_precoder_test_output2.dat"}}, + {4, {"test_data/transform_precoder_test_input3.dat"}, {"test_data/transform_precoder_test_output3.dat"}}, + {5, {"test_data/transform_precoder_test_input4.dat"}, {"test_data/transform_precoder_test_output4.dat"}}, + {6, {"test_data/transform_precoder_test_input5.dat"}, {"test_data/transform_precoder_test_output5.dat"}}, + {8, {"test_data/transform_precoder_test_input6.dat"}, {"test_data/transform_precoder_test_output6.dat"}}, + {9, {"test_data/transform_precoder_test_input7.dat"}, {"test_data/transform_precoder_test_output7.dat"}}, + {10, {"test_data/transform_precoder_test_input8.dat"}, {"test_data/transform_precoder_test_output8.dat"}}, + {12, {"test_data/transform_precoder_test_input9.dat"}, {"test_data/transform_precoder_test_output9.dat"}}, + {15, {"test_data/transform_precoder_test_input10.dat"}, {"test_data/transform_precoder_test_output10.dat"}}, + {16, {"test_data/transform_precoder_test_input11.dat"}, {"test_data/transform_precoder_test_output11.dat"}}, + {18, {"test_data/transform_precoder_test_input12.dat"}, {"test_data/transform_precoder_test_output12.dat"}}, + {20, {"test_data/transform_precoder_test_input13.dat"}, {"test_data/transform_precoder_test_output13.dat"}}, + {24, {"test_data/transform_precoder_test_input14.dat"}, {"test_data/transform_precoder_test_output14.dat"}}, + {25, {"test_data/transform_precoder_test_input15.dat"}, {"test_data/transform_precoder_test_output15.dat"}}, + {27, {"test_data/transform_precoder_test_input16.dat"}, {"test_data/transform_precoder_test_output16.dat"}}, + {30, {"test_data/transform_precoder_test_input17.dat"}, {"test_data/transform_precoder_test_output17.dat"}}, + {32, {"test_data/transform_precoder_test_input18.dat"}, {"test_data/transform_precoder_test_output18.dat"}}, + {36, {"test_data/transform_precoder_test_input19.dat"}, {"test_data/transform_precoder_test_output19.dat"}}, + {40, {"test_data/transform_precoder_test_input20.dat"}, {"test_data/transform_precoder_test_output20.dat"}}, + {45, {"test_data/transform_precoder_test_input21.dat"}, {"test_data/transform_precoder_test_output21.dat"}}, + {48, {"test_data/transform_precoder_test_input22.dat"}, {"test_data/transform_precoder_test_output22.dat"}}, + {50, {"test_data/transform_precoder_test_input23.dat"}, {"test_data/transform_precoder_test_output23.dat"}}, + {54, {"test_data/transform_precoder_test_input24.dat"}, {"test_data/transform_precoder_test_output24.dat"}}, + {60, {"test_data/transform_precoder_test_input25.dat"}, {"test_data/transform_precoder_test_output25.dat"}}, + {64, {"test_data/transform_precoder_test_input26.dat"}, {"test_data/transform_precoder_test_output26.dat"}}, + {72, {"test_data/transform_precoder_test_input27.dat"}, {"test_data/transform_precoder_test_output27.dat"}}, + {75, {"test_data/transform_precoder_test_input28.dat"}, {"test_data/transform_precoder_test_output28.dat"}}, + {80, {"test_data/transform_precoder_test_input29.dat"}, {"test_data/transform_precoder_test_output29.dat"}}, + {81, {"test_data/transform_precoder_test_input30.dat"}, {"test_data/transform_precoder_test_output30.dat"}}, + {90, {"test_data/transform_precoder_test_input31.dat"}, {"test_data/transform_precoder_test_output31.dat"}}, + {96, {"test_data/transform_precoder_test_input32.dat"}, {"test_data/transform_precoder_test_output32.dat"}}, + {100, {"test_data/transform_precoder_test_input33.dat"}, {"test_data/transform_precoder_test_output33.dat"}}, + {108, {"test_data/transform_precoder_test_input34.dat"}, {"test_data/transform_precoder_test_output34.dat"}}, + {120, {"test_data/transform_precoder_test_input35.dat"}, {"test_data/transform_precoder_test_output35.dat"}}, + {125, {"test_data/transform_precoder_test_input36.dat"}, {"test_data/transform_precoder_test_output36.dat"}}, + {128, {"test_data/transform_precoder_test_input37.dat"}, {"test_data/transform_precoder_test_output37.dat"}}, + {135, {"test_data/transform_precoder_test_input38.dat"}, {"test_data/transform_precoder_test_output38.dat"}}, + {144, {"test_data/transform_precoder_test_input39.dat"}, {"test_data/transform_precoder_test_output39.dat"}}, + {150, {"test_data/transform_precoder_test_input40.dat"}, {"test_data/transform_precoder_test_output40.dat"}}, + {160, {"test_data/transform_precoder_test_input41.dat"}, {"test_data/transform_precoder_test_output41.dat"}}, + {162, {"test_data/transform_precoder_test_input42.dat"}, {"test_data/transform_precoder_test_output42.dat"}}, + {180, {"test_data/transform_precoder_test_input43.dat"}, {"test_data/transform_precoder_test_output43.dat"}}, + {192, {"test_data/transform_precoder_test_input44.dat"}, {"test_data/transform_precoder_test_output44.dat"}}, + {200, {"test_data/transform_precoder_test_input45.dat"}, {"test_data/transform_precoder_test_output45.dat"}}, + {216, {"test_data/transform_precoder_test_input46.dat"}, {"test_data/transform_precoder_test_output46.dat"}}, + {225, {"test_data/transform_precoder_test_input47.dat"}, {"test_data/transform_precoder_test_output47.dat"}}, + {240, {"test_data/transform_precoder_test_input48.dat"}, {"test_data/transform_precoder_test_output48.dat"}}, + {243, {"test_data/transform_precoder_test_input49.dat"}, {"test_data/transform_precoder_test_output49.dat"}}, + {250, {"test_data/transform_precoder_test_input50.dat"}, {"test_data/transform_precoder_test_output50.dat"}}, + {256, {"test_data/transform_precoder_test_input51.dat"}, {"test_data/transform_precoder_test_output51.dat"}}, + {270, {"test_data/transform_precoder_test_input52.dat"}, {"test_data/transform_precoder_test_output52.dat"}}, +// clang-format on +}; + +} // srsran + diff --git a/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_test_data.tar.gz b/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_test_data.tar.gz new file mode 100644 index 0000000000..91886a3368 --- /dev/null +++ b/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_test_data.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3bf66f2746922753afc2a12265adef9b4e715ea94fe4d7d715eb53e5facb3b7b +size 3658539 diff --git a/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_vectortest.cpp b/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_vectortest.cpp new file mode 100644 index 0000000000..3c9c230e2f --- /dev/null +++ b/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_vectortest.cpp @@ -0,0 +1,97 @@ +/* + * + * 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 "transform_precoder_test_data.h" +#include "srsran/phy/generic_functions/generic_functions_factories.h" +#include "srsran/phy/generic_functions/transform_precoding/transform_precoder.h" +#include "srsran/phy/generic_functions/transform_precoding/transform_precoding_factories.h" +#include +#include + +using namespace srsran; + +namespace srsran { + +bool operator==(span lhs, span rhs) +{ + return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](cf_t left, cf_t right) { + return std::abs(left - right) < 1e-6; + }); +} + +std::ostream& operator<<(std::ostream& os, span data) +{ + return os << fmt::format("{}", data); +} + +std::ostream& operator<<(std::ostream& os, const test_case_t& test_case) +{ + return os << fmt::format("{} {} {}", + test_case.M_rb, + test_case.deprecode_input.get_file_name(), + test_case.deprecode_output.get_file_name()); +} + +} // namespace srsran + +namespace { + +class TransformPrecodingFixture : public ::testing::TestWithParam +{ +protected: + void SetUp() override + { + if (!precoder) { + std::shared_ptr dft_proc_factory = create_dft_processor_factory_fftw_slow(); + ASSERT_TRUE(dft_proc_factory); + + std::shared_ptr precoder_factory = + create_dft_transform_precoder_factory(std::move(dft_proc_factory), MAX_RB); + ASSERT_TRUE(precoder_factory); + + precoder = precoder_factory->create(); + ASSERT_TRUE(precoder); + } + } + + static std::unique_ptr precoder; +}; + +std::unique_ptr TransformPrecodingFixture::precoder = nullptr; + +} // namespace + +TEST_P(TransformPrecodingFixture, FromVector) +{ + const test_case_t& test_case = GetParam(); + + // Extract number of resource blocks. + unsigned M_rb = test_case.M_rb; + unsigned M_sc = M_rb * NRE; + + // Read precoder inputs and outputs. + std::vector deprecode_input = test_case.deprecode_input.read(); + std::vector deprecode_expected = test_case.deprecode_output.read(); + ASSERT_EQ(deprecode_input.size(), deprecode_expected.size()); + + std::vector deprecode_output(M_sc); + + unsigned nof_ofdm_symbols = deprecode_input.size() / M_sc; + for (unsigned i_ofdm_symbol = 0; i_ofdm_symbol != nof_ofdm_symbols; ++i_ofdm_symbol) { + span expected = span(deprecode_expected).subspan(i_ofdm_symbol * M_sc, M_sc); + span input = span(deprecode_input).subspan(i_ofdm_symbol * M_sc, M_sc); + span output = span(deprecode_output); + precoder->deprecode_ofdm_symbol(output, input); + + ASSERT_EQ(expected, span(output)); + } +} + +INSTANTIATE_TEST_SUITE_P(FromVector, TransformPrecodingFixture, ::testing::ValuesIn(transform_precoder_test_data)); From ad1edadec713b81483c33cdea0ccb09b84a96aac Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 19 Jul 2024 15:33:23 +0200 Subject: [PATCH 24/54] phy: apply clang-format --- .../transform_precoding/transform_precoder_test_data.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_test_data.h b/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_test_data.h index 247b798a02..d54d153cae 100644 --- a/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_test_data.h +++ b/tests/unittests/phy/generic_functions/transform_precoding/transform_precoder_test_data.h @@ -25,7 +25,7 @@ struct test_case_t { }; static const std::vector transform_precoder_test_data = { -// clang-format off + // clang-format off {1, {"test_data/transform_precoder_test_input0.dat"}, {"test_data/transform_precoder_test_output0.dat"}}, {2, {"test_data/transform_precoder_test_input1.dat"}, {"test_data/transform_precoder_test_output1.dat"}}, {3, {"test_data/transform_precoder_test_input2.dat"}, {"test_data/transform_precoder_test_output2.dat"}}, @@ -79,8 +79,7 @@ static const std::vector transform_precoder_test_data = { {250, {"test_data/transform_precoder_test_input50.dat"}, {"test_data/transform_precoder_test_output50.dat"}}, {256, {"test_data/transform_precoder_test_input51.dat"}, {"test_data/transform_precoder_test_output51.dat"}}, {270, {"test_data/transform_precoder_test_input52.dat"}, {"test_data/transform_precoder_test_output52.dat"}}, -// clang-format on + // clang-format on }; -} // srsran - +} // namespace srsran From 6993632d4f8f56e52c826311650b2bf123b0d1dc Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 2 Jul 2024 14:00:27 +0200 Subject: [PATCH 25/54] sched: maintain list of UEs in each slice --- lib/scheduler/slicing/ran_slice_instance.cpp | 42 ++++++++++++------- lib/scheduler/slicing/ran_slice_instance.h | 19 ++++++--- lib/scheduler/slicing/slice_scheduler.cpp | 14 ++++--- lib/scheduler/slicing/slice_scheduler.h | 4 +- .../slicing/slice_scheduler_test.cpp | 8 +++- 5 files changed, 60 insertions(+), 27 deletions(-) diff --git a/lib/scheduler/slicing/ran_slice_instance.cpp b/lib/scheduler/slicing/ran_slice_instance.cpp index 9be101722b..6aebd65615 100644 --- a/lib/scheduler/slicing/ran_slice_instance.cpp +++ b/lib/scheduler/slicing/ran_slice_instance.cpp @@ -25,26 +25,40 @@ void ran_slice_instance::slot_indication() pusch_rb_count = 0; } -void ran_slice_instance::add_logical_channel(du_ue_index_t ue_idx, lcid_t lcid) +void ran_slice_instance::rem_ue(du_ue_index_t ue_idx, lcid_t lcid) { - if (not bearers.contains(ue_idx)) { - bearers.emplace(ue_idx, MAX_NOF_RB_LCIDS); - } - bearers[ue_idx].set(lcid); -} - -void ran_slice_instance::rem_logical_channel(du_ue_index_t ue_idx, lcid_t lcid) -{ - if (not bearers.contains(ue_idx)) { + if (lcid < MAX_NOF_RB_LCIDS) { + if (bearers.contains(ue_idx)) { + bearers[ue_idx].reset(lcid); + if (bearers[ue_idx].none()) { + bearers.erase(ue_idx); + if (ues.contains(ue_idx)) { + ues.erase(ue_idx); + } + } + } return; } - bearers[ue_idx].reset(lcid); - if (bearers[ue_idx].none()) { + if (bearers.contains(ue_idx)) { bearers.erase(ue_idx); } + if (ues.contains(ue_idx)) { + ues.erase(ue_idx); + } } -void ran_slice_instance::rem_ue(du_ue_index_t ue_idx) +const slice_ue_repository& ran_slice_instance::get_ues() { - bearers.erase(ue_idx); + return ues; +} + +void ran_slice_instance::add_ue(const ue* u, lcid_t lcid) +{ + if (not ues.contains(u->ue_index)) { + ues.emplace(u->ue_index, u); + } + if (not bearers.contains(u->ue_index)) { + bearers.emplace(u->ue_index, MAX_NOF_RB_LCIDS); + } + bearers[u->ue_index].set(lcid); } diff --git a/lib/scheduler/slicing/ran_slice_instance.h b/lib/scheduler/slicing/ran_slice_instance.h index 0bec3bd0ff..4759b393cb 100644 --- a/lib/scheduler/slicing/ran_slice_instance.h +++ b/lib/scheduler/slicing/ran_slice_instance.h @@ -17,6 +17,9 @@ namespace srsran { +/// Container that store all UEs belonging to a slice. +using slice_ue_repository = slotted_id_table; + /// This class stores all the internal information relative to a RAN slice instantiation. class ran_slice_instance { @@ -39,14 +42,15 @@ class ran_slice_instance /// Determine if a (UE, LCID) tuple are managed by this slice. bool contains(du_ue_index_t ue_idx, lcid_t lcid) const { return contains(ue_idx) and bearers[ue_idx].test(lcid); } - /// Add a new (UE, LCID) to the list of bearers managed by this slice. - void add_logical_channel(du_ue_index_t ue_idx, lcid_t lcid); + /// Add a new UE to list of UEs (if not exists) and a new (UE, LCID) to the list of bearers managed by this slice. + void add_ue(const ue* u, lcid_t lcid); - /// Remove a (UE, LCID) from the list of bearers managed by this slice. - void rem_logical_channel(du_ue_index_t ue_idx, lcid_t lcid); + /// Remove a UE and all associated LCIDs or only a (UE, LCID) from the list of bearers managed by this slice. + /// \remark UE is removed if all LCIDs of a UE are removed. + void rem_ue(du_ue_index_t ue_idx, lcid_t lcid = MAX_NOF_RB_LCIDS); - /// Remove a UE and all associated LCIDs from the list of bearers managed by this slice. - void rem_ue(du_ue_index_t ue_idx); + /// Returns UEs belonging to this slice. + const slice_ue_repository& get_ues(); ran_slice_id_t id; const cell_configuration* cell_cfg; @@ -60,6 +64,9 @@ class ran_slice_instance unsigned pdsch_rb_count = 0; /// Counter of how many RBs have been scheduled for PUSCH in the current slot for this slice. unsigned pusch_rb_count = 0; + +private: + slice_ue_repository ues; }; } // namespace srsran diff --git a/lib/scheduler/slicing/slice_scheduler.cpp b/lib/scheduler/slicing/slice_scheduler.cpp index adc13545cf..ef926eee82 100644 --- a/lib/scheduler/slicing/slice_scheduler.cpp +++ b/lib/scheduler/slicing/slice_scheduler.cpp @@ -14,8 +14,8 @@ using namespace srsran; -slice_scheduler::slice_scheduler(const cell_configuration& cell_cfg_) : - cell_cfg(cell_cfg_), logger(srslog::fetch_basic_logger("SCHED")) +slice_scheduler::slice_scheduler(const cell_configuration& cell_cfg_, const ue_repository& ues_) : + cell_cfg(cell_cfg_), logger(srslog::fetch_basic_logger("SCHED")), ues(ues_) { // Create a number of slices equal to the number of configured RRM Policy members + 1 (default slice). slices.reserve(cell_cfg.rrm_policy_members.size() + 1); @@ -57,7 +57,9 @@ void slice_scheduler::add_ue(const ue_configuration& ue_cfg) { for (const logical_channel_config& lc_cfg : ue_cfg.logical_channels()) { ran_slice_instance& sl_inst = get_slice(lc_cfg.rrm_policy); - sl_inst.add_logical_channel(ue_cfg.ue_index, lc_cfg.lcid); + if (ues.contains(ue_cfg.ue_index)) { + sl_inst.add_ue(&ues[ue_cfg.ue_index], lc_cfg.lcid); + } } } @@ -66,13 +68,15 @@ void slice_scheduler::reconf_ue(const ue_configuration& next_ue_cfg, const ue_co // Remove old bearers. for (const logical_channel_config& lc_cfg : prev_ue_cfg.logical_channels()) { ran_slice_instance& sl_inst = get_slice(lc_cfg.rrm_policy); - sl_inst.rem_logical_channel(prev_ue_cfg.ue_index, lc_cfg.lcid); + sl_inst.rem_ue(prev_ue_cfg.ue_index, lc_cfg.lcid); } // Add new bearers. for (const logical_channel_config& lc_cfg : next_ue_cfg.logical_channels()) { ran_slice_instance& sl_inst = get_slice(lc_cfg.rrm_policy); - sl_inst.add_logical_channel(prev_ue_cfg.ue_index, lc_cfg.lcid); + if (ues.contains(next_ue_cfg.ue_index)) { + sl_inst.add_ue(&ues[next_ue_cfg.ue_index], lc_cfg.lcid); + } } } diff --git a/lib/scheduler/slicing/slice_scheduler.h b/lib/scheduler/slicing/slice_scheduler.h index d18e101835..9e9098a089 100644 --- a/lib/scheduler/slicing/slice_scheduler.h +++ b/lib/scheduler/slicing/slice_scheduler.h @@ -25,7 +25,7 @@ class slice_scheduler constexpr static priority_type skip_prio = 0; public: - slice_scheduler(const cell_configuration& cell_cfg_); + slice_scheduler(const cell_configuration& cell_cfg_, const ue_repository& ues_); /// Reset the state of the slices. void slot_indication(); @@ -107,6 +107,8 @@ class slice_scheduler const cell_configuration& cell_cfg; srslog::basic_logger& logger; + const ue_repository& ues; + std::vector slices; // Queue of slice candidates sorted by priority. diff --git a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp index a80e66a645..5e1568dc0c 100644 --- a/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp +++ b/tests/unittests/scheduler/slicing/slice_scheduler_test.cpp @@ -10,6 +10,7 @@ #include "lib/scheduler/slicing/slice_scheduler.h" #include "tests/unittests/scheduler/test_utils/config_generators.h" +#include "tests/unittests/scheduler/test_utils/dummy_test_components.h" #include "srsran/srslog/srslog.h" #include @@ -44,6 +45,7 @@ class slice_scheduler_test const ue_configuration* add_ue(const sched_ue_creation_request_message& req) { const ue_configuration* ue_cfg = test_cfg.add_ue(req); + ues.add_ue(std::make_unique(ue_creation_command{*ue_cfg, req.starts_in_fallback, harq_timeout_handler})); slice_sched.add_ue(*ue_cfg); return ue_cfg; } @@ -52,7 +54,11 @@ class slice_scheduler_test test_helpers::test_sched_config_manager test_cfg; const cell_configuration& cell_cfg; - slice_scheduler slice_sched{cell_cfg}; + scheduler_harq_timeout_dummy_handler harq_timeout_handler; + + ue_repository ues; + + slice_scheduler slice_sched{cell_cfg, ues}; }; class default_slice_scheduler_test : public slice_scheduler_test, public ::testing::Test From 5df98e3750e080fb0051027d826855c708043daf Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Mon, 15 Jul 2024 09:20:38 +0200 Subject: [PATCH 26/54] sched: return nof. RBs allocated if the PDSCH/PUSCH allocation is successful --- lib/scheduler/policy/ue_allocator.h | 2 ++ lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/scheduler/policy/ue_allocator.h b/lib/scheduler/policy/ue_allocator.h index 71d7ad5381..378002d1ea 100644 --- a/lib/scheduler/policy/ue_allocator.h +++ b/lib/scheduler/policy/ue_allocator.h @@ -54,6 +54,8 @@ struct alloc_result { alloc_status status; /// Nof. of bytes allocated if allocation was successful. unsigned alloc_bytes{0}; + /// Nof. of resource blocks allocated if allocation was successful. + unsigned alloc_nof_rbs{0}; }; /// Allocator of PDSCH grants for UEs. diff --git a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp index a5937ceabe..6e2f8bb049 100644 --- a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp @@ -483,7 +483,7 @@ alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& gra h_dl.save_alloc_params(pdsch_sched_ctx, msg.pdsch_cfg, contains_srb_data); - return {alloc_status::success, h_dl.last_alloc_params().tb[0]->tbs_bytes}; + return {alloc_status::success, h_dl.last_alloc_params().tb[0]->tbs_bytes, crbs.length()}; } // No candidates for PDSCH allocation. @@ -981,7 +981,7 @@ alloc_result ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& gra // In case there is a SR pending. Reset it. u.reset_sr_indication(); - return {alloc_status::success, h_ul.last_tx_params().tbs_bytes}; + return {alloc_status::success, h_ul.last_tx_params().tbs_bytes, crbs.length()}; } // No candidates for PUSCH allocation. From 438703425bc6571033ef0d6888545f73ed4d736a Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 16 Jul 2024 10:11:37 +0200 Subject: [PATCH 27/54] sched: add method to fetch slice UEs in ran slice candidate --- lib/scheduler/slicing/ran_slice_candidate.h | 3 +++ lib/scheduler/slicing/slice_ue_repository.h | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 lib/scheduler/slicing/slice_ue_repository.h diff --git a/lib/scheduler/slicing/ran_slice_candidate.h b/lib/scheduler/slicing/ran_slice_candidate.h index 8d50af243d..4ceaa5a0f6 100644 --- a/lib/scheduler/slicing/ran_slice_candidate.h +++ b/lib/scheduler/slicing/ran_slice_candidate.h @@ -32,6 +32,9 @@ class common_ran_slice_candidate bool is_candidate(du_ue_index_t ue_idx) const { return inst->contains(ue_idx); } bool is_candidate(du_ue_index_t ue_idx, lcid_t lcid) const { return inst->contains(ue_idx, lcid); } + /// Get UEs belonging to a slice. + const slice_ue_repository& get_slice_ues() const { return inst->get_ues(); } + /// Register that a new grant was allocated for a given UE. void store_grant(unsigned nof_rbs) { diff --git a/lib/scheduler/slicing/slice_ue_repository.h b/lib/scheduler/slicing/slice_ue_repository.h new file mode 100644 index 0000000000..86c2c9e79b --- /dev/null +++ b/lib/scheduler/slicing/slice_ue_repository.h @@ -0,0 +1,20 @@ +/* + * + * 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 "../ue_scheduling/ue.h" + +namespace srsran { + +/// Container that store all UEs belonging to a slice. +using slice_ue_repository = slotted_id_table; + +} // namespace srsran From 7c7c6151d0948b7382c2a5de36e5943187b3f069 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 16 Jul 2024 10:15:26 +0200 Subject: [PATCH 28/54] sched: add method to fetch UE dedicated configuration --- lib/scheduler/ue_scheduling/ue.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/scheduler/ue_scheduling/ue.h b/lib/scheduler/ue_scheduling/ue.h index 69f98b1245..861fbef8ca 100644 --- a/lib/scheduler/ue_scheduling/ue.h +++ b/lib/scheduler/ue_scheduling/ue.h @@ -77,6 +77,9 @@ class ue /// \brief Number of cells configured for the UE. unsigned nof_cells() const { return ue_cells.size(); } + /// \brief Returns dedicated configuration for the UE. + const ue_configuration* ue_cfg_dedicated() const { return ue_ded_cfg; } + bool is_ca_enabled() const { return ue_cells.size() > 1; } void activate_cells(bounded_bitset activ_bitmap) {} From 35608befd62b8a63d41b6ead68337cda730e852c Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Tue, 16 Jul 2024 10:34:32 +0200 Subject: [PATCH 29/54] sched: integrate slice scheduler as part of UE scheduling process --- lib/scheduler/policy/scheduler_policy.h | 19 ++--- lib/scheduler/policy/scheduler_time_pf.cpp | 38 ++++++---- lib/scheduler/policy/scheduler_time_pf.h | 21 +++--- lib/scheduler/policy/scheduler_time_rr.cpp | 50 ++++++++----- lib/scheduler/policy/scheduler_time_rr.h | 10 +-- lib/scheduler/slicing/ran_slice_candidate.h | 1 - lib/scheduler/slicing/ran_slice_instance.cpp | 35 +++++----- lib/scheduler/slicing/ran_slice_instance.h | 17 ++--- lib/scheduler/slicing/slice_scheduler.cpp | 14 ++-- lib/scheduler/slicing/slice_scheduler.h | 4 +- .../ue_scheduling/ue_cell_grid_allocator.h | 49 +++++++++++++ .../ue_scheduling/ue_event_manager.cpp | 22 ++++-- .../ue_scheduling/ue_event_manager.h | 9 ++- .../ue_scheduling/ue_scheduler_impl.cpp | 24 +++++-- .../ue_scheduling/ue_scheduler_impl.h | 14 ++-- .../policy/scheduler_policy_test.cpp | 70 +++++++++++-------- 16 files changed, 265 insertions(+), 132 deletions(-) diff --git a/lib/scheduler/policy/scheduler_policy.h b/lib/scheduler/policy/scheduler_policy.h index faa5e5b790..fad18da323 100644 --- a/lib/scheduler/policy/scheduler_policy.h +++ b/lib/scheduler/policy/scheduler_policy.h @@ -10,6 +10,7 @@ #pragma once +#include "../slicing/ran_slice_candidate.h" #include "ue_allocator.h" namespace srsran { @@ -106,18 +107,20 @@ class scheduler_policy /// Schedule UE DL grants for a given slot and one or more cells. /// \param[out] pdsch_alloc PDSCH grant allocator. This object provides a handle to allocate PDSCH grants in the /// gNB resource grid. - /// \param[in] res_grid view of the current resource grid occupancy state for all gnb cells. - /// \param[in] ues List of eligible UEs to be scheduled in the given slot. - virtual void - dl_sched(ue_pdsch_allocator& pdsch_alloc, const ue_resource_grid_view& res_grid, const ue_repository& ues) = 0; + /// \param[in] res_grid View of the current resource grid occupancy state for all gnb cells. + /// \param[in] slice_candidate Slice candidate to be scheduled in the given slot. + virtual void dl_sched(ue_pdsch_allocator& pdsch_alloc, + const ue_resource_grid_view& res_grid, + dl_ran_slice_candidate& slice_candidate) = 0; /// Schedule UE UL grants for a given {slot, cell}. /// \param[out] pusch_alloc PUSCH grant allocator. This object provides a handle to allocate PUSCH grants in the /// gNB resource grid. - /// \param[in] res_grid view of the current resource grid occupancy state for all gnb cells. - /// \param[in] ues List of eligible UEs to be scheduled in the given slot. - virtual void - ul_sched(ue_pusch_allocator& pusch_alloc, const ue_resource_grid_view& res_grid, const ue_repository& ues) = 0; + /// \param[in] res_grid View of the current resource grid occupancy state for all gnb cells. + /// \param[in] slice_candidate Slice candidate to be scheduled in the given slot. + virtual void ul_sched(ue_pusch_allocator& pusch_alloc, + const ue_resource_grid_view& res_grid, + ul_ran_slice_candidate& slice_candidate) = 0; }; } // namespace srsran diff --git a/lib/scheduler/policy/scheduler_time_pf.cpp b/lib/scheduler/policy/scheduler_time_pf.cpp index cceea9198c..a5681209bc 100644 --- a/lib/scheduler/policy/scheduler_time_pf.cpp +++ b/lib/scheduler/policy/scheduler_time_pf.cpp @@ -19,11 +19,12 @@ scheduler_time_pf::scheduler_time_pf(const scheduler_ue_expert_config& expert_cf void scheduler_time_pf::dl_sched(ue_pdsch_allocator& pdsch_alloc, const ue_resource_grid_view& res_grid, - const ue_repository& ues) + dl_ran_slice_candidate& slice_candidate) { // Clear the existing contents of the queue. dl_queue.clear(); + const slice_ue_repository& ues = slice_candidate.get_slice_ues(); // Remove deleted users from history. for (auto it = ue_history_db.begin(); it != ue_history_db.end();) { if (not ues.contains(it->ue_index)) { @@ -44,10 +45,11 @@ void scheduler_time_pf::dl_sched(ue_pdsch_allocator& pdsch_alloc, } alloc_result alloc_result = {alloc_status::invalid_params}; - while (not dl_queue.empty()) { + unsigned rem_rbs = slice_candidate.remaining_rbs(); + while (not dl_queue.empty() and rem_rbs > 0) { ue_ctxt& ue = *dl_queue.top(); if (alloc_result.status != alloc_status::skip_slot) { - alloc_result = try_dl_alloc(ue, ues, pdsch_alloc); + alloc_result = try_dl_alloc(ue, ues, pdsch_alloc, rem_rbs); } ue.save_dl_alloc(alloc_result.alloc_bytes); // Re-add the UE to the queue if scheduling of re-transmission fails so that scheduling of retransmission are @@ -56,16 +58,18 @@ void scheduler_time_pf::dl_sched(ue_pdsch_allocator& pdsch_alloc, dl_queue.push(&ue); } dl_queue.pop(); + rem_rbs = slice_candidate.remaining_rbs(); } } void scheduler_time_pf::ul_sched(ue_pusch_allocator& pusch_alloc, const ue_resource_grid_view& res_grid, - const ue_repository& ues) + ul_ran_slice_candidate& slice_candidate) { // Clear the existing contents of the queue. ul_queue.clear(); + const slice_ue_repository& ues = slice_candidate.get_slice_ues(); // Remove deleted users from history. for (auto it = ue_history_db.begin(); it != ue_history_db.end();) { if (not ues.contains(it->ue_index)) { @@ -86,10 +90,11 @@ void scheduler_time_pf::ul_sched(ue_pusch_allocator& pusch_alloc, } alloc_result alloc_result = {alloc_status::invalid_params}; - while (not ul_queue.empty()) { + unsigned rem_rbs = slice_candidate.remaining_rbs(); + while (not ul_queue.empty() and rem_rbs > 0) { ue_ctxt& ue = *ul_queue.top(); if (alloc_result.status != alloc_status::skip_slot) { - alloc_result = try_ul_alloc(ue, ues, pusch_alloc); + alloc_result = try_ul_alloc(ue, ues, pusch_alloc, rem_rbs); } ue.save_ul_alloc(alloc_result.alloc_bytes); // Re-add the UE to the queue if scheduling of re-transmission fails so that scheduling of retransmission are @@ -98,13 +103,17 @@ void scheduler_time_pf::ul_sched(ue_pusch_allocator& pusch_alloc, ul_queue.push(&ue); } ul_queue.pop(); + rem_rbs = slice_candidate.remaining_rbs(); } } -alloc_result scheduler_time_pf::try_dl_alloc(ue_ctxt& ctxt, const ue_repository& ues, ue_pdsch_allocator& pdsch_alloc) +alloc_result scheduler_time_pf::try_dl_alloc(ue_ctxt& ctxt, + const slice_ue_repository& ues, + ue_pdsch_allocator& pdsch_alloc, + unsigned max_rbs) { alloc_result alloc_result = {alloc_status::invalid_params}; - ue_pdsch_grant grant{&ues[ctxt.ue_index], ctxt.cell_index}; + ue_pdsch_grant grant{ues[ctxt.ue_index], ctxt.cell_index}; // Prioritize reTx over newTx. if (ctxt.dl_retx_h != nullptr) { grant.h_id = ctxt.dl_retx_h->id; @@ -120,7 +129,8 @@ alloc_result scheduler_time_pf::try_dl_alloc(ue_ctxt& ctxt, const ue_repository& if (ctxt.dl_newtx_h != nullptr) { grant.h_id = ctxt.dl_newtx_h->id; grant.recommended_nof_bytes = ctxt.dl_newtx_srb_pending_bytes > 0 ? ctxt.dl_newtx_srb_pending_bytes - : ues[ctxt.ue_index].pending_dl_newtx_bytes(); + : ues[ctxt.ue_index]->pending_dl_newtx_bytes(); + grant.max_nof_rbs = max_rbs; alloc_result = pdsch_alloc.allocate_dl_grant(grant); if (alloc_result.status == alloc_status::success) { ctxt.dl_newtx_h = nullptr; @@ -131,10 +141,13 @@ alloc_result scheduler_time_pf::try_dl_alloc(ue_ctxt& ctxt, const ue_repository& return {alloc_status::skip_ue}; } -alloc_result scheduler_time_pf::try_ul_alloc(ue_ctxt& ctxt, const ue_repository& ues, ue_pusch_allocator& pusch_alloc) +alloc_result scheduler_time_pf::try_ul_alloc(ue_ctxt& ctxt, + const slice_ue_repository& ues, + ue_pusch_allocator& pusch_alloc, + unsigned max_rbs) { alloc_result alloc_result = {alloc_status::invalid_params}; - ue_pusch_grant grant{&ues[ctxt.ue_index], ctxt.cell_index}; + ue_pusch_grant grant{ues[ctxt.ue_index], ctxt.cell_index}; // Prioritize reTx over newTx. if (ctxt.ul_retx_h != nullptr) { grant.h_id = ctxt.ul_retx_h->id; @@ -150,7 +163,8 @@ alloc_result scheduler_time_pf::try_ul_alloc(ue_ctxt& ctxt, const ue_repository& if (ctxt.ul_newtx_h != nullptr) { grant.h_id = ctxt.ul_newtx_h->id; grant.recommended_nof_bytes = ctxt.ul_newtx_srb_pending_bytes > 0 ? ctxt.ul_newtx_srb_pending_bytes - : ues[ctxt.ue_index].pending_ul_newtx_bytes(); + : ues[ctxt.ue_index]->pending_ul_newtx_bytes(); + grant.max_nof_rbs = max_rbs; alloc_result = pusch_alloc.allocate_ul_grant(grant); if (alloc_result.status == alloc_status::success) { ctxt.ul_newtx_h = nullptr; diff --git a/lib/scheduler/policy/scheduler_time_pf.h b/lib/scheduler/policy/scheduler_time_pf.h index cacffbb982..3a09acfd13 100644 --- a/lib/scheduler/policy/scheduler_time_pf.h +++ b/lib/scheduler/policy/scheduler_time_pf.h @@ -9,6 +9,7 @@ #pragma once +#include "../slicing/slice_ue_repository.h" #include "scheduler_policy.h" namespace srsran { @@ -18,11 +19,13 @@ class scheduler_time_pf : public scheduler_policy public: scheduler_time_pf(const scheduler_ue_expert_config& expert_cfg_); - void - dl_sched(ue_pdsch_allocator& pdsch_alloc, const ue_resource_grid_view& res_grid, const ue_repository& ues) override; + void dl_sched(ue_pdsch_allocator& pdsch_alloc, + const ue_resource_grid_view& res_grid, + dl_ran_slice_candidate& slice_candidate) override; - void - ul_sched(ue_pusch_allocator& pusch_alloc, const ue_resource_grid_view& res_grid, const ue_repository& ues) override; + void ul_sched(ue_pusch_allocator& pusch_alloc, + const ue_resource_grid_view& res_grid, + ul_ran_slice_candidate& slice_candidate) override; private: /// Fairness parameters. @@ -79,11 +82,13 @@ class scheduler_time_pf : public scheduler_policy }; /// \brief Attempts to allocate PDSCH for a UE. - /// \return Returns allocation status and nof. allocated bytes. - alloc_result try_dl_alloc(ue_ctxt& ctxt, const ue_repository& ues, ue_pdsch_allocator& pdsch_alloc); + /// \return Returns allocation status, nof. allocated bytes and nof. allocated RBs. + alloc_result + try_dl_alloc(ue_ctxt& ctxt, const slice_ue_repository& ues, ue_pdsch_allocator& pdsch_alloc, unsigned max_rbs); /// \brief Attempts to allocate PUSCH for a UE. - /// \return Returns allocation status and nof. allocated bytes. - alloc_result try_ul_alloc(ue_ctxt& ctxt, const ue_repository& ues, ue_pusch_allocator& pusch_alloc); + /// \return Returns allocation status, nof. allocated bytes and nof. allocated RBs. + alloc_result + try_ul_alloc(ue_ctxt& ctxt, const slice_ue_repository& ues, ue_pusch_allocator& pusch_alloc, unsigned max_rbs); slotted_id_table ue_history_db; diff --git a/lib/scheduler/policy/scheduler_time_rr.cpp b/lib/scheduler/policy/scheduler_time_rr.cpp index 03ef3141a7..46582377ad 100644 --- a/lib/scheduler/policy/scheduler_time_rr.cpp +++ b/lib/scheduler/policy/scheduler_time_rr.cpp @@ -31,13 +31,17 @@ static const std::vector scheduler_alloc_limits_lookup = }; /// \brief Computes maximum nof. RBs to allocate per UE per slot for newTx. -/// \param[in] ue_db map of ues. +/// \param[in] ues Map of UEs belonging to a slice. /// \param[in] is_dl Flag indicating whether the computation is DL or UL. +/// \param[in] res_grid View of the resource grid. +/// \param[in] expert_cfg Scheduler UE expert configuration. +/// \param[in] slice_max_rbs Maximum nof. RBs to allocate to a slice. /// \return Maximum nof. RBs to allocate per UE per slot for newTx. -static unsigned compute_max_nof_rbs_per_ue_per_slot(const ue_repository& ues, +static unsigned compute_max_nof_rbs_per_ue_per_slot(const slice_ue_repository& ues, bool is_dl, const ue_resource_grid_view& res_grid, - const scheduler_ue_expert_config& expert_cfg) + const scheduler_ue_expert_config& expert_cfg, + unsigned slice_max_rbs) { if (ues.empty()) { return 0; @@ -110,7 +114,7 @@ static unsigned compute_max_nof_rbs_per_ue_per_slot(const ue_repository& return 0; } - return (bwp_crb_limits.length() / nof_ues_to_be_scheduled_per_slot); + return (std::min(bwp_crb_limits.length(), slice_max_rbs) / nof_ues_to_be_scheduled_per_slot); } /// \brief Fetches list of DL HARQ candidates to schedule. @@ -222,12 +226,13 @@ get_ue_ul_harq_candidates(const ue& ue_ref, ue_cell_index_t cell_index, bool is_ } /// \brief Algorithm to select next UE to allocate in a time-domain RR fashion -/// \param[in] ue_db map of "slot_ue" +/// \param[in] ue_db Map of UEs belonging to a slice. /// \param[in] next_ue_index UE index with the highest priority to be allocated. /// \param[in] alloc_ue callable with signature "bool(ue&)" that returns true if UE allocation was successful. /// \return Index of next UE to allocate. template -du_ue_index_t round_robin_apply(const ue_repository& ue_db, du_ue_index_t next_ue_index, const AllocUEFunc& alloc_ue) +du_ue_index_t +round_robin_apply(const slice_ue_repository& ue_db, du_ue_index_t next_ue_index, const AllocUEFunc& alloc_ue) { if (ue_db.empty()) { return next_ue_index; @@ -269,10 +274,10 @@ static alloc_result alloc_dl_ue(const ue& u, std::optional dl_new_tx_max_nof_rbs_per_ue_per_slot = {}) { if (not is_retx) { - if (not u.has_pending_dl_newtx_bytes()) { + if (ue_with_srb_data_only and not u.has_pending_dl_srb_newtx_bytes()) { return {alloc_status::skip_ue}; } - if (ue_with_srb_data_only and not u.has_pending_dl_srb_newtx_bytes()) { + if (not u.has_pending_dl_newtx_bytes()) { return {alloc_status::skip_ue}; } } @@ -389,8 +394,16 @@ scheduler_time_rr::scheduler_time_rr(const scheduler_ue_expert_config& expert_cf void scheduler_time_rr::dl_sched(ue_pdsch_allocator& pdsch_alloc, const ue_resource_grid_view& res_grid, - const ue_repository& ues) + dl_ran_slice_candidate& slice_candidate) { + 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. + return; + } + // First, schedule UEs with SRB data re-transmissions. auto srb_retx_ue_function = [this, &res_grid, &pdsch_alloc](const ue& u) { return alloc_dl_ue(u, res_grid, pdsch_alloc, true, true, logger, expert_cfg); @@ -398,7 +411,7 @@ void scheduler_time_rr::dl_sched(ue_pdsch_allocator& pdsch_alloc, next_dl_ue_index = round_robin_apply(ues, next_dl_ue_index, srb_retx_ue_function); const unsigned dl_new_tx_max_nof_rbs_per_ue_per_slot = - compute_max_nof_rbs_per_ue_per_slot(ues, true, res_grid, expert_cfg); + compute_max_nof_rbs_per_ue_per_slot(ues, true, res_grid, expert_cfg, max_rbs); if (dl_new_tx_max_nof_rbs_per_ue_per_slot > 0) { // Second, schedule UEs with SRB data new transmission. auto srb_newtx_ue_function = [this, &res_grid, &pdsch_alloc, dl_new_tx_max_nof_rbs_per_ue_per_slot](const ue& u) { @@ -426,21 +439,24 @@ void scheduler_time_rr::dl_sched(ue_pdsch_allocator& pdsch_alloc, void scheduler_time_rr::ul_sched(ue_pusch_allocator& pusch_alloc, const ue_resource_grid_view& res_grid, - const ue_repository& ues) + ul_ran_slice_candidate& slice_candidate) { - if (ues.empty()) { - // No UEs to be scheduled. + 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. return; } + const unsigned ul_new_tx_max_nof_rbs_per_ue_per_slot = + compute_max_nof_rbs_per_ue_per_slot(ues, false, res_grid, expert_cfg, max_rbs); // First, schedule UEs with pending SR. - auto sr_ue_function = [this, &res_grid, &pusch_alloc](const ue& u) { - return alloc_ul_ue(u, res_grid, pusch_alloc, false, true, false, logger); + auto sr_ue_function = [this, &res_grid, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot](const ue& u) { + return alloc_ul_ue(u, res_grid, pusch_alloc, false, true, false, logger, ul_new_tx_max_nof_rbs_per_ue_per_slot); }; next_ul_ue_index = round_robin_apply(ues, next_ul_ue_index, sr_ue_function); - const unsigned ul_new_tx_max_nof_rbs_per_ue_per_slot = - compute_max_nof_rbs_per_ue_per_slot(ues, false, res_grid, expert_cfg); if (ul_new_tx_max_nof_rbs_per_ue_per_slot > 0) { // Second, schedule UEs with SRB data new transmissions. auto srb_newtx_ue_function = [this, &res_grid, &pusch_alloc, ul_new_tx_max_nof_rbs_per_ue_per_slot](const ue& u) { diff --git a/lib/scheduler/policy/scheduler_time_rr.h b/lib/scheduler/policy/scheduler_time_rr.h index 26a73de88f..e77fe866c7 100644 --- a/lib/scheduler/policy/scheduler_time_rr.h +++ b/lib/scheduler/policy/scheduler_time_rr.h @@ -18,11 +18,13 @@ class scheduler_time_rr : public scheduler_policy public: scheduler_time_rr(const scheduler_ue_expert_config& expert_cfg_); - void - dl_sched(ue_pdsch_allocator& pdsch_alloc, const ue_resource_grid_view& res_grid, const ue_repository& ues) override; + void dl_sched(ue_pdsch_allocator& pdsch_alloc, + const ue_resource_grid_view& res_grid, + dl_ran_slice_candidate& slice_candidate) override; - void - ul_sched(ue_pusch_allocator& pusch_alloc, const ue_resource_grid_view& res_grid, const ue_repository& ues) override; + void ul_sched(ue_pusch_allocator& pusch_alloc, + const ue_resource_grid_view& res_grid, + ul_ran_slice_candidate& slice_candidate) override; private: srslog::basic_logger& logger; diff --git a/lib/scheduler/slicing/ran_slice_candidate.h b/lib/scheduler/slicing/ran_slice_candidate.h index 4ceaa5a0f6..e75e436b09 100644 --- a/lib/scheduler/slicing/ran_slice_candidate.h +++ b/lib/scheduler/slicing/ran_slice_candidate.h @@ -27,7 +27,6 @@ class common_ran_slice_candidate ran_slice_id_t id() const { return inst->id; } [[nodiscard]] const slice_rrm_policy_config& cfg() const { return inst->cfg; } - scheduler_policy& policy() { return *inst->policy; } bool is_candidate(du_ue_index_t ue_idx) const { return inst->contains(ue_idx); } bool is_candidate(du_ue_index_t ue_idx, lcid_t lcid) const { return inst->contains(ue_idx, lcid); } diff --git a/lib/scheduler/slicing/ran_slice_instance.cpp b/lib/scheduler/slicing/ran_slice_instance.cpp index 6aebd65615..c388a0cdc9 100644 --- a/lib/scheduler/slicing/ran_slice_instance.cpp +++ b/lib/scheduler/slicing/ran_slice_instance.cpp @@ -19,43 +19,46 @@ ran_slice_instance::ran_slice_instance(ran_slice_id_t id_, { } -void ran_slice_instance::slot_indication() +void ran_slice_instance::slot_indication(const ue_repository& cell_ues) { pdsch_rb_count = 0; pusch_rb_count = 0; + // Remove UEs from slice UEs list if it's removed from UE repository. + auto* ue_to_rem_it = slice_ues_to_rem.begin(); + while (ue_to_rem_it != slice_ues_to_rem.end()) { + if (not cell_ues.contains(*ue_to_rem_it)) { + slice_ues.erase(*ue_to_rem_it); + bearers.erase(*ue_to_rem_it); + ue_to_rem_it = slice_ues_to_rem.erase(ue_to_rem_it); + continue; + } + ++ue_to_rem_it; + } } -void ran_slice_instance::rem_ue(du_ue_index_t ue_idx, lcid_t lcid) +void ran_slice_instance::rem_logical_channel(du_ue_index_t ue_idx, lcid_t lcid) { if (lcid < MAX_NOF_RB_LCIDS) { if (bearers.contains(ue_idx)) { bearers[ue_idx].reset(lcid); if (bearers[ue_idx].none()) { - bearers.erase(ue_idx); - if (ues.contains(ue_idx)) { - ues.erase(ue_idx); - } + slice_ues_to_rem.push_back(ue_idx); } } return; } - if (bearers.contains(ue_idx)) { - bearers.erase(ue_idx); - } - if (ues.contains(ue_idx)) { - ues.erase(ue_idx); - } + slice_ues_to_rem.push_back(ue_idx); } const slice_ue_repository& ran_slice_instance::get_ues() { - return ues; + return slice_ues; } -void ran_slice_instance::add_ue(const ue* u, lcid_t lcid) +void ran_slice_instance::add_logical_channel(const ue* u, lcid_t lcid) { - if (not ues.contains(u->ue_index)) { - ues.emplace(u->ue_index, u); + if (not slice_ues.contains(u->ue_index)) { + slice_ues.emplace(u->ue_index, u); } if (not bearers.contains(u->ue_index)) { bearers.emplace(u->ue_index, MAX_NOF_RB_LCIDS); diff --git a/lib/scheduler/slicing/ran_slice_instance.h b/lib/scheduler/slicing/ran_slice_instance.h index 4759b393cb..40e21ee7d3 100644 --- a/lib/scheduler/slicing/ran_slice_instance.h +++ b/lib/scheduler/slicing/ran_slice_instance.h @@ -11,22 +11,20 @@ #pragma once #include "../config/cell_configuration.h" -#include "../policy/scheduler_policy.h" +#include "../ue_scheduling/ue_repository.h" #include "ran_slice_id.h" +#include "slice_ue_repository.h" #include "srsran/scheduler/config/slice_rrm_policy_config.h" namespace srsran { -/// Container that store all UEs belonging to a slice. -using slice_ue_repository = slotted_id_table; - /// This class stores all the internal information relative to a RAN slice instantiation. class ran_slice_instance { public: ran_slice_instance(ran_slice_id_t id_, const cell_configuration& cell_cfg_, const slice_rrm_policy_config& cfg_); - void slot_indication(); + void slot_indication(const ue_repository& cell_ues); bool active() const { return not bearers.empty(); } @@ -43,11 +41,11 @@ class ran_slice_instance bool contains(du_ue_index_t ue_idx, lcid_t lcid) const { return contains(ue_idx) and bearers[ue_idx].test(lcid); } /// Add a new UE to list of UEs (if not exists) and a new (UE, LCID) to the list of bearers managed by this slice. - void add_ue(const ue* u, lcid_t lcid); + void add_logical_channel(const ue* u, lcid_t lcid); /// Remove a UE and all associated LCIDs or only a (UE, LCID) from the list of bearers managed by this slice. /// \remark UE is removed if all LCIDs of a UE are removed. - void rem_ue(du_ue_index_t ue_idx, lcid_t lcid = MAX_NOF_RB_LCIDS); + void rem_logical_channel(du_ue_index_t ue_idx, lcid_t lcid = MAX_NOF_RB_LCIDS); /// Returns UEs belonging to this slice. const slice_ue_repository& get_ues(); @@ -56,8 +54,6 @@ class ran_slice_instance const cell_configuration* cell_cfg; slice_rrm_policy_config cfg; - std::unique_ptr policy; - slotted_id_table, MAX_NOF_DU_UES> bearers; /// Counter of how many RBs have been scheduled for PDSCH in the current slot for this slice. @@ -66,7 +62,8 @@ class ran_slice_instance unsigned pusch_rb_count = 0; private: - slice_ue_repository ues; + slice_ue_repository slice_ues; + static_vector slice_ues_to_rem; }; } // namespace srsran diff --git a/lib/scheduler/slicing/slice_scheduler.cpp b/lib/scheduler/slicing/slice_scheduler.cpp index ef926eee82..36d50c6c77 100644 --- a/lib/scheduler/slicing/slice_scheduler.cpp +++ b/lib/scheduler/slicing/slice_scheduler.cpp @@ -24,12 +24,12 @@ slice_scheduler::slice_scheduler(const cell_configuration& cell_cfg_, const ue_r ran_slice_id_t id_count{0}; // Default slice. slices.emplace_back(id_count, cell_cfg, slice_rrm_policy_config{}); - slices.back().inst.policy = create_scheduler_strategy(cell_cfg.expert_cfg.ue); + slices.back().policy = create_scheduler_strategy(cell_cfg.expert_cfg.ue); ++id_count; // Configured RRM policy members. for (const slice_rrm_policy_config& rrm : cell_cfg.rrm_policy_members) { slices.emplace_back(id_count, cell_cfg, rrm); - slices.back().inst.policy = create_scheduler_strategy(cell_cfg.expert_cfg.ue); + slices.back().policy = create_scheduler_strategy(cell_cfg.expert_cfg.ue); ++id_count; } } @@ -40,7 +40,7 @@ void slice_scheduler::slot_indication() // Update the context of each slice. for (auto& slice : slices) { - slice.inst.slot_indication(); + slice.inst.slot_indication(ues); } // Recompute the priority queues. @@ -58,7 +58,7 @@ void slice_scheduler::add_ue(const ue_configuration& ue_cfg) for (const logical_channel_config& lc_cfg : ue_cfg.logical_channels()) { ran_slice_instance& sl_inst = get_slice(lc_cfg.rrm_policy); if (ues.contains(ue_cfg.ue_index)) { - sl_inst.add_ue(&ues[ue_cfg.ue_index], lc_cfg.lcid); + sl_inst.add_logical_channel(&ues[ue_cfg.ue_index], lc_cfg.lcid); } } } @@ -68,14 +68,14 @@ void slice_scheduler::reconf_ue(const ue_configuration& next_ue_cfg, const ue_co // Remove old bearers. for (const logical_channel_config& lc_cfg : prev_ue_cfg.logical_channels()) { ran_slice_instance& sl_inst = get_slice(lc_cfg.rrm_policy); - sl_inst.rem_ue(prev_ue_cfg.ue_index, lc_cfg.lcid); + sl_inst.rem_logical_channel(prev_ue_cfg.ue_index, lc_cfg.lcid); } // Add new bearers. for (const logical_channel_config& lc_cfg : next_ue_cfg.logical_channels()) { ran_slice_instance& sl_inst = get_slice(lc_cfg.rrm_policy); if (ues.contains(next_ue_cfg.ue_index)) { - sl_inst.add_ue(&ues[next_ue_cfg.ue_index], lc_cfg.lcid); + sl_inst.add_logical_channel(&ues[next_ue_cfg.ue_index], lc_cfg.lcid); } } } @@ -83,7 +83,7 @@ void slice_scheduler::reconf_ue(const ue_configuration& next_ue_cfg, const ue_co void slice_scheduler::rem_ue(du_ue_index_t ue_idx) { for (auto& slice : slices) { - slice.inst.rem_ue(ue_idx); + slice.inst.rem_logical_channel(ue_idx); } } diff --git a/lib/scheduler/slicing/slice_scheduler.h b/lib/scheduler/slicing/slice_scheduler.h index 9e9098a089..235e439ad0 100644 --- a/lib/scheduler/slicing/slice_scheduler.h +++ b/lib/scheduler/slicing/slice_scheduler.h @@ -43,11 +43,13 @@ class slice_scheduler size_t nof_slices() const { return slices.size(); } const slice_rrm_policy_config& slice_config(ran_slice_id_t id) const { return slices[id.value()].inst.cfg; } + scheduler_policy& get_policy(ran_slice_id_t id) { return *slices[id.value()].policy; } private: /// Class responsible for tracking the scheduling context of each RAN slice instance. struct ran_slice_sched_context { - ran_slice_instance inst; + ran_slice_instance inst; + std::unique_ptr policy; // Counter tracking the last time this slice was scheduled as a candidate. slot_count_type last_dl_slot = 0; slot_count_type last_ul_slot = 0; diff --git a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.h b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.h index 6ea962eb37..39bf24b3f3 100644 --- a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.h +++ b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.h @@ -12,6 +12,7 @@ #include "../cell/resource_grid.h" #include "../pdcch_scheduling/pdcch_resource_allocator.h" #include "../policy/ue_allocator.h" +#include "../slicing/ran_slice_candidate.h" #include "../uci_scheduling/uci_scheduler.h" #include "ue_repository.h" #include "srsran/scheduler/config/scheduler_expert_config.h" @@ -77,4 +78,52 @@ class ue_cell_grid_allocator : public ue_pdsch_allocator, public ue_pusch_alloca unsigned dl_attempts_count = 0, ul_attempts_count = 0; }; +/// This class implements the ue_pdsch_allocator interface and updates a DL slice candidate with the allocated RBs if +/// the PDSCH grant allocation is successful. +class dl_slice_ue_cell_grid_allocator : public ue_pdsch_allocator +{ +public: + dl_slice_ue_cell_grid_allocator(ue_pdsch_allocator& pdsch_alloc_, dl_ran_slice_candidate& slice_candidate_) : + pdsch_alloc(pdsch_alloc_), slice_candidate(slice_candidate_) + { + } + + alloc_result allocate_dl_grant(const ue_pdsch_grant& grant) override + { + const alloc_result result = pdsch_alloc.allocate_dl_grant(grant); + if (result.status == alloc_status::success) { + slice_candidate.store_grant(result.alloc_nof_rbs); + } + return result; + } + +private: + ue_pdsch_allocator& pdsch_alloc; + dl_ran_slice_candidate& slice_candidate; +}; + +/// This class implements the ue_pusch_allocator interface and updates a UL slice candidate with the allocated RBs if +/// the PUSCH grant allocation is successful. +class ul_slice_ue_cell_grid_allocator : public ue_pusch_allocator +{ +public: + ul_slice_ue_cell_grid_allocator(ue_pusch_allocator& pusch_alloc_, ul_ran_slice_candidate& slice_candidate_) : + pusch_alloc(pusch_alloc_), slice_candidate(slice_candidate_) + { + } + + alloc_result allocate_ul_grant(const ue_pusch_grant& grant) override + { + const alloc_result result = pusch_alloc.allocate_ul_grant(grant); + if (result.status == alloc_status::success) { + slice_candidate.store_grant(result.alloc_nof_rbs); + } + return result; + } + +private: + ue_pusch_allocator& pusch_alloc; + ul_ran_slice_candidate& slice_candidate; +}; + } // namespace srsran diff --git a/lib/scheduler/ue_scheduling/ue_event_manager.cpp b/lib/scheduler/ue_scheduling/ue_event_manager.cpp index a8f38bb189..b0eb161b6d 100644 --- a/lib/scheduler/ue_scheduling/ue_event_manager.cpp +++ b/lib/scheduler/ue_scheduling/ue_event_manager.cpp @@ -142,10 +142,12 @@ void ue_event_manager::handle_ue_creation(ue_config_update_event ev) du_cell_index_t pcell_index = u->get_pcell().cell_index; ue_db.add_ue(std::move(u)); - // Update UCI scheduler with new UE UCI resources. const auto& added_ue = ue_db[ueidx]; for (unsigned i = 0, e = added_ue.nof_cells(); i != e; ++i) { + // Update UCI scheduler with new UE UCI resources. du_cells[pcell_index].uci_sched->add_ue(added_ue.get_cell(to_ue_cell_index(i)).cfg()); + // Add UE to a slice. + du_cells[pcell_index].slice_sched->add_ue(*added_ue.ue_cfg_dedicated()); } // Log Event. @@ -165,15 +167,19 @@ void ue_event_manager::handle_ue_reconfiguration(ue_config_update_event ev) } auto& u = ue_db[ue_idx]; - // Update UE UCI resources in UCI scheduler. for (unsigned i = 0, e = u.nof_cells(); i != e; ++i) { auto& ue_cc = u.get_cell(to_ue_cell_index(i)); if (not ev.next_config().contains(ue_cc.cell_index)) { // UE carrier is being removed. + // Update UE UCI resources in UCI scheduler. du_cells[ue_cc.cell_index].uci_sched->rem_ue(ue_cc.cfg()); + // Schedule removal of UE in slice scheduler. + du_cells[ue_cc.cell_index].slice_sched->rem_ue(ue_idx); } else { // UE carrier is being reconfigured. du_cells[ue_cc.cell_index].uci_sched->reconf_ue(ev.next_config().ue_cell_cfg(ue_cc.cell_index), ue_cc.cfg()); + // Reconfigure UE in slice scheduler. + du_cells[ue_cc.cell_index].slice_sched->reconf_ue(ev.next_config(), *u.ue_cfg_dedicated()); } } for (unsigned i = 0, e = ev.next_config().nof_cells(); i != e; ++i) { @@ -182,6 +188,8 @@ void ue_event_manager::handle_ue_reconfiguration(ue_config_update_event ev) if (ue_cc == nullptr) { // New UE carrier is being added. du_cells[new_ue_cc_cfg.cell_cfg_common.cell_index].uci_sched->add_ue(new_ue_cc_cfg); + // Add UE to a slice. + du_cells[new_ue_cc_cfg.cell_cfg_common.cell_index].slice_sched->add_ue(ev.next_config()); } } @@ -206,12 +214,14 @@ void ue_event_manager::handle_ue_deletion(ue_config_delete_event ev) const rnti_t rnti = u.crnti; du_cell_index_t pcell_idx = u.get_pcell().cell_index; - // Update UCI scheduling by removing existing UE UCI resources. for (unsigned i = 0, e = u.nof_cells(); i != e; ++i) { + // Update UCI scheduling by removing existing UE UCI resources. du_cells[u.get_cell(to_ue_cell_index(i)).cell_index].uci_sched->rem_ue(u.get_pcell().cfg()); + // Schedule removal of UE from slice scheduler. + du_cells[u.get_cell(to_ue_cell_index(i)).cell_index].slice_sched->rem_ue(ue_idx); } - // Scheduler UE removal from repository. + // Schedule UE removal from repository. ue_db.schedule_ue_rem(std::move(ev)); // Log UE removal event. @@ -673,7 +683,8 @@ void ue_event_manager::run(slot_point sl, du_cell_index_t cell_index) void ue_event_manager::add_cell(cell_resource_allocator& cell_res_grid, ue_fallback_scheduler& fallback_sched, uci_scheduler_impl& uci_sched, - scheduler_event_logger& ev_logger) + scheduler_event_logger& ev_logger, + slice_scheduler& slice_sched) { const du_cell_index_t cell_index = cell_res_grid.cell_index(); srsran_assert(not cell_exists(cell_index), "Overwriting cell configurations not supported"); @@ -683,6 +694,7 @@ void ue_event_manager::add_cell(cell_resource_allocator& cell_res_grid, du_cells[cell_index].fallback_sched = &fallback_sched; du_cells[cell_index].uci_sched = &uci_sched; du_cells[cell_index].ev_logger = &ev_logger; + du_cells[cell_index].slice_sched = &slice_sched; } bool ue_event_manager::cell_exists(du_cell_index_t cell_index) const diff --git a/lib/scheduler/ue_scheduling/ue_event_manager.h b/lib/scheduler/ue_scheduling/ue_event_manager.h index 90b36b71cc..ba5003d5a1 100644 --- a/lib/scheduler/ue_scheduling/ue_event_manager.h +++ b/lib/scheduler/ue_scheduling/ue_event_manager.h @@ -11,13 +11,12 @@ #pragma once #include "../config/sched_config_manager.h" -#include "../policy/scheduler_policy.h" +#include "../slicing/slice_scheduler.h" #include "../support/slot_event_list.h" #include "ue.h" #include "ue_fallback_scheduler.h" #include "srsran/adt/unique_function.h" #include "srsran/ran/du_types.h" -#include "srsran/ran/uci/uci_constants.h" namespace srsran { @@ -39,7 +38,8 @@ class ue_event_manager final : public sched_ue_configuration_handler, void add_cell(cell_resource_allocator& cell_res_grid, ue_fallback_scheduler& fallback_sched, uci_scheduler_impl& uci_sched, - scheduler_event_logger& ev_logger); + scheduler_event_logger& ev_logger, + slice_scheduler& slice_sched); /// UE Add/Mod/Remove interface. void handle_ue_creation(ue_config_update_event ev) override; @@ -121,6 +121,9 @@ class ue_event_manager final : public sched_ue_configuration_handler, // Reference to the CSI and SR UCI scheduler. uci_scheduler_impl* uci_sched = nullptr; + // Reference to the slice scheduler. + slice_scheduler* slice_sched = nullptr; + scheduler_event_logger* ev_logger = nullptr; }; std::array du_cells{}; diff --git a/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp b/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp index 933cfc0677..dbc19a2302 100644 --- a/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp +++ b/lib/scheduler/ue_scheduling/ue_scheduler_impl.cpp @@ -17,7 +17,6 @@ ue_scheduler_impl::ue_scheduler_impl(const scheduler_ue_expert_config& expert_cf sched_configuration_notifier& mac_notif, scheduler_metrics_handler& metric_handler) : expert_cfg(expert_cfg_), - sched_strategy(create_scheduler_strategy(expert_cfg)), ue_alloc(expert_cfg, ue_db, srslog::fetch_basic_logger("SCHED")), event_mng(ue_db, metric_handler), logger(srslog::fetch_basic_logger("SCHED")) @@ -31,7 +30,8 @@ void ue_scheduler_impl::add_cell(const ue_scheduler_cell_params& params) event_mng.add_cell(*params.cell_res_alloc, cells[params.cell_index]->fallback_sched, cells[params.cell_index]->uci_sched, - *params.ev_logger); + *params.ev_logger, + cells[params.cell_index]->slice_sched); ue_alloc.add_cell(params.cell_index, *params.pdcch_sched, *params.uci_alloc, *params.cell_res_alloc); } @@ -47,15 +47,31 @@ void ue_scheduler_impl::run_sched_strategy(slot_point slot_tx, du_cell_index_t c return; } + // Update slice context and compute slice priorities. + cells[cell_index]->slice_sched.slot_indication(); + // Perform round-robin prioritization of UL and DL scheduling. This gives unfair preference to DL over UL. This is // done to avoid the issue of sending wrong DAI value in DCI format 0_1 to UE while the PDSCH is allocated // right after allocating PUSCH in the same slot, resulting in gNB expecting 1 HARQ ACK bit to be multiplexed in // UCI in PUSCH and UE sending 4 HARQ ACK bits (DAI = 3). // Example: K1==K2=4 and PUSCH is allocated before PDSCH. if (expert_cfg.enable_csi_rs_pdsch_multiplexing or (*cells[cell_index]->cell_res_alloc)[0].result.dl.csi_rs.empty()) { - sched_strategy->dl_sched(ue_alloc, ue_res_grid_view, ue_db); + auto dl_slice_candidate = cells[cell_index]->slice_sched.get_next_dl_candidate(); + while (dl_slice_candidate.has_value()) { + auto& policy = cells[cell_index]->slice_sched.get_policy(dl_slice_candidate->id()); + dl_slice_ue_cell_grid_allocator slice_pdsch_alloc{ue_alloc, *dl_slice_candidate}; + policy.dl_sched(slice_pdsch_alloc, ue_res_grid_view, *dl_slice_candidate); + dl_slice_candidate = cells[cell_index]->slice_sched.get_next_dl_candidate(); + } + } + + auto ul_slice_candidate = cells[cell_index]->slice_sched.get_next_ul_candidate(); + while (ul_slice_candidate.has_value()) { + auto& policy = cells[cell_index]->slice_sched.get_policy(ul_slice_candidate->id()); + ul_slice_ue_cell_grid_allocator slice_pusch_alloc{ue_alloc, *ul_slice_candidate}; + policy.ul_sched(slice_pusch_alloc, ue_res_grid_view, *ul_slice_candidate); + ul_slice_candidate = cells[cell_index]->slice_sched.get_next_ul_candidate(); } - sched_strategy->ul_sched(ue_alloc, ue_res_grid_view, ue_db); } void ue_scheduler_impl::update_harq_pucch_counter(cell_resource_allocator& cell_alloc) diff --git a/lib/scheduler/ue_scheduling/ue_scheduler_impl.h b/lib/scheduler/ue_scheduling/ue_scheduler_impl.h index 9047d3e497..60e2107191 100644 --- a/lib/scheduler/ue_scheduling/ue_scheduler_impl.h +++ b/lib/scheduler/ue_scheduling/ue_scheduler_impl.h @@ -13,7 +13,7 @@ #include "../logging/scheduler_event_logger.h" #include "../policy/scheduler_policy.h" #include "../pucch_scheduling/pucch_guardbands_scheduler.h" -#include "../support/slot_event_list.h" +#include "../slicing/slice_scheduler.h" #include "../support/slot_sync_point.h" #include "../uci_scheduling/uci_scheduler_impl.h" #include "ue_cell_grid_allocator.h" @@ -21,10 +21,7 @@ #include "ue_fallback_scheduler.h" #include "ue_repository.h" #include "ue_scheduler.h" -#include "srsran/adt/slotted_array.h" -#include "srsran/adt/unique_function.h" #include "srsran/scheduler/config/scheduler_expert_config.h" -#include "srsran/scheduler/config/serving_cell_config_factory.h" namespace srsran { @@ -70,10 +67,14 @@ class ue_scheduler_impl final : public ue_scheduler /// Fallback scheduler. ue_fallback_scheduler fallback_sched; + /// Slice scheduler. + slice_scheduler slice_sched; + cell(const scheduler_ue_expert_config& expert_cfg, const ue_scheduler_cell_params& params, ue_repository& ues) : cell_res_alloc(params.cell_res_alloc), uci_sched(params.cell_res_alloc->cfg, *params.uci_alloc, ues), - fallback_sched(expert_cfg, params.cell_res_alloc->cfg, *params.pdcch_sched, *params.pucch_alloc, ues) + fallback_sched(expert_cfg, params.cell_res_alloc->cfg, *params.pdcch_sched, *params.pucch_alloc, ues), + slice_sched(params.cell_res_alloc->cfg, ues) { } }; @@ -87,8 +88,7 @@ class ue_scheduler_impl final : public ue_scheduler std::array, MAX_NOF_DU_CELLS> cells; /// Scheduling Strategy. - ue_resource_grid_view ue_res_grid_view; - std::unique_ptr sched_strategy; + ue_resource_grid_view ue_res_grid_view; /// Repository of created UEs. ue_repository ue_db; diff --git a/tests/unittests/scheduler/policy/scheduler_policy_test.cpp b/tests/unittests/scheduler/policy/scheduler_policy_test.cpp index c32805f1e3..9ce0e7fd85 100644 --- a/tests/unittests/scheduler/policy/scheduler_policy_test.cpp +++ b/tests/unittests/scheduler/policy/scheduler_policy_test.cpp @@ -42,10 +42,16 @@ class base_scheduler_policy_test test_helpers::make_default_sched_cell_configuration_request()) : logger(srslog::fetch_basic_logger("SCHED", true)), res_logger(false, msg.pci), - sched_cfg(sched_cfg_), + sched_cfg([&sched_cfg_, policy]() { + if (policy == policy_scheduler_type::time_pf) { + sched_cfg_.ue.strategy_cfg = time_pf_scheduler_expert_config{}; + } + return sched_cfg_; + }()), cell_cfg(*[this, &msg]() { return cell_cfg_list.emplace(to_du_cell_index(0), std::make_unique(sched_cfg, msg)).get(); - }()) + }()), + slice_instance(ran_slice_id_t{0}, cell_cfg, slice_rrm_policy_config{}) { logger.set_level(srslog::basic_levels::debug); srslog::init(); @@ -53,13 +59,9 @@ class base_scheduler_policy_test grid_alloc.add_cell(to_du_cell_index(0), pdcch_alloc, uci_alloc, res_grid); ue_res_grid.add_cell(res_grid); - if (policy == policy_scheduler_type::time_pf) { - sched_cfg.ue.strategy_cfg = time_pf_scheduler_expert_config{}; - } sched = create_scheduler_strategy(sched_cfg.ue); - if (sched == nullptr) { - report_fatal_error("Invalid policy"); + report_fatal_error("Failed to initialize slice scheduler"); } } @@ -70,6 +72,7 @@ class base_scheduler_policy_test logger.set_context(next_slot.sfn(), next_slot.slot_index()); grid_alloc.slot_indication(next_slot); + slice_instance.slot_indication(ues); res_grid.slot_indication(next_slot); pdcch_alloc.slot_indication(next_slot); @@ -77,8 +80,8 @@ class base_scheduler_policy_test uci_alloc.slot_indication(next_slot); if (cell_cfg.is_dl_enabled(next_slot)) { - sched->dl_sched(grid_alloc, ue_res_grid, ues); - sched->ul_sched(grid_alloc, ue_res_grid, ues); + sched->dl_sched(slice_pdsch_alloc, ue_res_grid, dl_slice_candidate); + sched->ul_sched(slice_pusch_alloc, ue_res_grid, ul_slice_candidate); } // Log scheduler results. @@ -111,6 +114,9 @@ class base_scheduler_policy_test std::make_unique(ue_req.ue_index, ue_req.crnti, cell_cfg_list, ue_req.cfg)); ues.add_ue(std::make_unique( ue_creation_command{*ue_ded_cell_cfg_list.back(), ue_req.starts_in_fallback, harq_timeout_handler})); + for (const auto& lc_cfg : *ue_req.cfg.lc_config_list) { + slice_instance.add_logical_channel(&ues[ue_req.ue_index], lc_cfg.lcid); + } return ues[ue_req.ue_index]; } @@ -172,7 +178,15 @@ class base_scheduler_policy_test ue_repository ues; ue_cell_grid_allocator grid_alloc{sched_cfg.ue, ues, logger}; std::unique_ptr sched; - slot_point next_slot{0, test_rgen::uniform_int(0, 10239)}; + + // Default RAN slice instance. + ran_slice_instance slice_instance; + dl_ran_slice_candidate dl_slice_candidate{slice_instance}; + ul_ran_slice_candidate ul_slice_candidate{slice_instance}; + dl_slice_ue_cell_grid_allocator slice_pdsch_alloc{grid_alloc, dl_slice_candidate}; + ul_slice_ue_cell_grid_allocator slice_pusch_alloc{grid_alloc, ul_slice_candidate}; + + slot_point next_slot{0, test_rgen::uniform_int(0, 10239)}; }; class scheduler_policy_test : public base_scheduler_policy_test, public ::testing::TestWithParam @@ -473,17 +487,15 @@ TEST_F(scheduler_round_robin_test, round_robin_does_not_account_ues_with_empty_b push_dl_bs(u1.ue_index, uint_to_lcid(5), 1000000); push_dl_bs(u3.ue_index, uint_to_lcid(5), 1000000); - std::array rr_ues = {u1.ue_index, u3.ue_index}; - unsigned offset = 0; for (unsigned i = 0; i != 10; ++i) { - run_slot(); - ASSERT_GE(this->res_grid[0].result.dl.ue_grants.size(), 1); - if (i == 0) { - offset = this->res_grid[0].result.dl.ue_grants[0].context.ue_index == u1.ue_index ? 0 : 1; - ASSERT_NE(this->res_grid[0].result.dl.ue_grants[0].context.ue_index, u2.ue_index); - } else { - ASSERT_EQ(this->res_grid[0].result.dl.ue_grants[0].context.ue_index, rr_ues[(i + offset) % rr_ues.size()]); + const bool pdsch_scheduled = run_until([this]() { return not this->res_grid[0].result.dl.ue_grants.empty(); }); + ASSERT_TRUE(pdsch_scheduled); + for (const auto& grant : this->res_grid[0].result.dl.ue_grants) { + ASSERT_NE(grant.context.ue_index, u2.ue_index); } + // Run once to move to next slot. If not /c (not this->res_grid[0].result.dl.ue_grants.empty()) will keep returning + // true. + run_slot(); } } @@ -559,16 +571,6 @@ TEST_F(scheduler_pf_test, pf_ensures_fairness_in_dl_when_ues_have_different_chan ue& u2 = add_ue(make_ue_create_req(to_du_ue_index(1), to_rnti(0x4602), {uint_to_lcid(5)}, lcg_id)); ue& u3 = add_ue(make_ue_create_req(to_du_ue_index(2), to_rnti(0x4603), {uint_to_lcid(5)}, lcg_id)); - // Report different CQIs for different UEs. - // Best channel condition. - u1.get_pcell().handle_csi_report( - csi_report_data{std::nullopt, std::nullopt, std::nullopt, std::nullopt, cqi_value{15U}}); - // Worst channel condition. - u2.get_pcell().handle_csi_report( - csi_report_data{std::nullopt, std::nullopt, std::nullopt, std::nullopt, cqi_value{10U}}); - u3.get_pcell().handle_csi_report( - csi_report_data{std::nullopt, std::nullopt, std::nullopt, std::nullopt, cqi_value{12U}}); - // Push high enough DL buffer status to ensure UEs occupy entire BWP CRBs when scheduled. push_dl_bs(u1.ue_index, uint_to_lcid(5), 1000000); push_dl_bs(u2.ue_index, uint_to_lcid(5), 1000000); @@ -580,6 +582,16 @@ TEST_F(scheduler_pf_test, pf_ensures_fairness_in_dl_when_ues_have_different_chan ue_pdsch_scheduled_count[u3.ue_index] = 0; for (unsigned i = 0; i != 100; ++i) { + // Report different CQIs for different UEs. + // Best channel condition. + u1.get_pcell().handle_csi_report( + csi_report_data{std::nullopt, std::nullopt, std::nullopt, std::nullopt, cqi_value{15U}}); + // Worst channel condition. + u2.get_pcell().handle_csi_report( + csi_report_data{std::nullopt, std::nullopt, std::nullopt, std::nullopt, cqi_value{10U}}); + u3.get_pcell().handle_csi_report( + csi_report_data{std::nullopt, std::nullopt, std::nullopt, std::nullopt, cqi_value{12U}}); + run_slot(); const slot_point current_slot = next_slot - 1; for (const auto& grant : this->res_grid[0].result.dl.ue_grants) { From 5f47ffd2b8741911c0114b67869a15decdf8a2ea Mon Sep 17 00:00:00 2001 From: yagoda Date: Fri, 12 Jul 2024 15:25:23 +0200 Subject: [PATCH 30/54] e2sm_kpm: refactoring the management of RLC metrics arriving at the e2sm_kpm --- .../e2sm_kpm_du_meas_provider_impl.cpp | 238 +++++++++++------- .../e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h | 3 +- .../e2/e2sm_kpm_meas_provider_test.cpp | 9 +- 3 files changed, 152 insertions(+), 98 deletions(-) diff --git a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp index 1579b23331..2c13a125ba 100644 --- a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp +++ b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.cpp @@ -130,60 +130,11 @@ void e2sm_kpm_du_meas_provider_impl::report_metrics(const scheduler_cell_metrics void e2sm_kpm_du_meas_provider_impl::report_metrics(const rlc_metrics& metrics) { logger.debug("Received RLC metrics: ue={} {}.", metrics.ue_index, metrics.rb_id.get_drb_id()); - ue_aggr_rlc_metrics[metrics.ue_index].ue_index = metrics.ue_index; - if (metrics.rb_id.get_drb_id() == drb_id_t::drb1) { - // Reset aggregated RLC metrics when metrics for drb1 are received. - ue_aggr_rlc_metrics[metrics.ue_index].rx = metrics.rx; - ue_aggr_rlc_metrics[metrics.ue_index].tx = metrics.tx; - ue_aggr_rlc_metrics[metrics.ue_index].counter = 1; - } else { - // Otherwise, aggregate RLC metrics for each UE. - ue_aggr_rlc_metrics[metrics.ue_index].rx.num_lost_pdus += metrics.rx.num_lost_pdus; - ue_aggr_rlc_metrics[metrics.ue_index].rx.num_malformed_pdus += metrics.rx.num_malformed_pdus; - ue_aggr_rlc_metrics[metrics.ue_index].rx.num_sdus += metrics.rx.num_sdus; - ue_aggr_rlc_metrics[metrics.ue_index].rx.num_sdu_bytes += metrics.rx.num_sdu_bytes; - ue_aggr_rlc_metrics[metrics.ue_index].rx.num_pdus += metrics.rx.num_pdus; - ue_aggr_rlc_metrics[metrics.ue_index].rx.num_pdu_bytes += metrics.rx.num_pdu_bytes; - ue_aggr_rlc_metrics[metrics.ue_index].rx.sdu_latency_us += metrics.rx.sdu_latency_us; - ue_aggr_rlc_metrics[metrics.ue_index].tx.num_sdus += metrics.tx.num_sdus; - ue_aggr_rlc_metrics[metrics.ue_index].tx.num_of_pulled_sdus += metrics.tx.num_of_pulled_sdus; - ue_aggr_rlc_metrics[metrics.ue_index].tx.num_sdu_bytes += metrics.tx.num_sdu_bytes; - ue_aggr_rlc_metrics[metrics.ue_index].tx.num_dropped_sdus += metrics.tx.num_dropped_sdus; - ue_aggr_rlc_metrics[metrics.ue_index].tx.num_discarded_sdus += metrics.tx.num_discarded_sdus; - ue_aggr_rlc_metrics[metrics.ue_index].tx.num_discard_failures += metrics.tx.num_discard_failures; - ue_aggr_rlc_metrics[metrics.ue_index].tx.num_pdus_no_segmentation += metrics.tx.num_pdus_no_segmentation; - ue_aggr_rlc_metrics[metrics.ue_index].tx.num_pdu_bytes_no_segmentation += metrics.tx.num_pdu_bytes_no_segmentation; - ue_aggr_rlc_metrics[metrics.ue_index].tx.sum_sdu_latency_us += metrics.tx.sum_sdu_latency_us; - switch (ue_aggr_rlc_metrics[metrics.ue_index].tx.mode) { - case rlc_mode::um_bidir: - case rlc_mode::um_unidir_dl: - ue_aggr_rlc_metrics[metrics.ue_index].tx.mode_specific.um.num_pdus_with_segmentation += - metrics.tx.mode_specific.um.num_pdus_with_segmentation; - ue_aggr_rlc_metrics[metrics.ue_index].tx.mode_specific.um.num_pdu_bytes_with_segmentation += - metrics.tx.mode_specific.um.num_pdu_bytes_with_segmentation; - break; - case rlc_mode::am: - ue_aggr_rlc_metrics[metrics.ue_index].tx.mode_specific.am.num_pdus_with_segmentation += - metrics.tx.mode_specific.am.num_pdus_with_segmentation; - ue_aggr_rlc_metrics[metrics.ue_index].tx.mode_specific.am.num_pdu_bytes_with_segmentation += - metrics.tx.mode_specific.am.num_pdu_bytes_with_segmentation; - ue_aggr_rlc_metrics[metrics.ue_index].tx.mode_specific.am.num_retx_pdus += - metrics.tx.mode_specific.am.num_retx_pdus; - ue_aggr_rlc_metrics[metrics.ue_index].tx.mode_specific.am.num_retx_pdu_bytes += - metrics.tx.mode_specific.am.num_retx_pdu_bytes; - ue_aggr_rlc_metrics[metrics.ue_index].tx.mode_specific.am.num_ctrl_pdus += - metrics.tx.mode_specific.am.num_ctrl_pdus; - ue_aggr_rlc_metrics[metrics.ue_index].tx.mode_specific.am.num_ctrl_pdu_bytes += - metrics.tx.mode_specific.am.num_ctrl_pdu_bytes; - break; - default: - // nothing to do here - break; - } - ue_aggr_rlc_metrics[metrics.ue_index].counter++; + ue_aggr_rlc_metrics[metrics.ue_index].push_back(metrics); + if (ue_aggr_rlc_metrics[metrics.ue_index].size() > max_rlc_metrics) { + ue_aggr_rlc_metrics[metrics.ue_index].pop_front(); } } - std::vector e2sm_kpm_du_meas_provider_impl::get_supported_metric_names(e2sm_kpm_metric_level_enum level) { std::vector metrics; @@ -479,28 +430,41 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_dl_mean_throughput(const asn1::e2sm logger.debug("Metric: DRB.UEThpDl supports only NO_LABEL label."); return meas_collected; } - unsigned seconds = 1; + double seconds = 1; std::map ue_throughput; if (ue_aggr_rlc_metrics.size() == 0) { return meas_collected; } for (auto& ue : ue_aggr_rlc_metrics) { size_t num_pdu_bytes_with_segmentation; - switch (ue.second.tx.mode) { + switch (ue.second.front().tx.mode) { case rlc_mode::um_bidir: case rlc_mode::um_unidir_dl: - num_pdu_bytes_with_segmentation = ue.second.tx.mode_specific.um.num_pdu_bytes_with_segmentation; + // get average from queue + num_pdu_bytes_with_segmentation = + std::accumulate(ue.second.begin(), ue.second.end(), 0, [](size_t sum, const rlc_metrics& metric) { + return sum + metric.tx.mode_specific.um.num_pdu_bytes_with_segmentation; + }); + num_pdu_bytes_with_segmentation /= ue.second.size(); break; case rlc_mode::am: - num_pdu_bytes_with_segmentation = ue.second.tx.mode_specific.am.num_pdu_bytes_with_segmentation; + num_pdu_bytes_with_segmentation = + std::accumulate(ue.second.begin(), ue.second.end(), 0, [](size_t sum, const rlc_metrics& metric) { + return sum + metric.tx.mode_specific.am.num_pdu_bytes_with_segmentation; + }); + num_pdu_bytes_with_segmentation /= ue.second.size(); break; default: num_pdu_bytes_with_segmentation = 0; } - ue_throughput[ue.first] = - bytes_to_kbits((ue.second.tx.num_pdu_bytes_no_segmentation + num_pdu_bytes_with_segmentation) / - ue.second.counter) / - seconds; // unit is kbps + auto num_pdu_bytes_no_segmentation = + std::accumulate(ue.second.begin(), ue.second.end(), 0, [](size_t sum, const rlc_metrics& metric) { + return sum + metric.tx.num_pdu_bytes_no_segmentation; + }); + num_pdu_bytes_no_segmentation /= ue.second.size(); + seconds = (float)std::chrono::duration_cast(ue.second.back().metrics_period).count() / + (float)1000; + ue_throughput[ue.first] = bytes_to_kbits(num_pdu_bytes_no_segmentation + num_pdu_bytes_with_segmentation) / seconds; } if (ues.size() == 0) { meas_record_item_c meas_record_item; @@ -541,13 +505,20 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_ul_mean_throughput(const asn1::e2sm logger.debug("Metric: DRB.UEThpUl supports only NO_LABEL label."); return meas_collected; } - unsigned seconds = 1; + double seconds = 1; std::map ue_throughput; if (ue_aggr_rlc_metrics.size() == 0) { return meas_collected; } for (auto& ue : ue_aggr_rlc_metrics) { - ue_throughput[ue.first] = bytes_to_kbits(ue.second.rx.num_pdu_bytes / ue.second.counter) / seconds; // unit is kbps + auto num_pdu_bytes = + std::accumulate(ue.second.begin(), ue.second.end(), 0, [](size_t sum, const rlc_metrics& metric) { + return sum + metric.rx.num_pdu_bytes; + }); + num_pdu_bytes /= ue.second.size(); + seconds = (float)std::chrono::duration_cast(ue.second.back().metrics_period).count() / + (float)1000; + ue_throughput[ue.first] = bytes_to_kbits(num_pdu_bytes) / seconds; // unit is kbps } if (ues.size() == 0) { meas_record_item_c meas_record_item; @@ -599,9 +570,15 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_ul_success_rate(const asn1::e2sm::l uint32_t total_lost_pdus = 0; uint32_t total_pdus = 0; for (auto& ue_metric : ue_aggr_rlc_metrics) { - rlc_metrics& rlc_metric = ue_metric.second; - total_lost_pdus += rlc_metric.rx.num_lost_pdus; - total_pdus += rlc_metric.rx.num_pdus; + // rlc_metrics& rlc_metric = ue_metric.second; + total_lost_pdus += std::accumulate( + ue_metric.second.begin(), ue_metric.second.end(), 0, [](size_t sum, const rlc_metrics& metric) { + return sum + metric.rx.num_lost_pdus; + }); + total_pdus += std::accumulate(ue_metric.second.begin(), + ue_metric.second.end(), + 0, + [](size_t sum, const rlc_metrics& metric) { return sum + metric.rx.num_pdus; }); } if (total_pdus) { success_rate = 1.0 * (total_pdus - total_lost_pdus) / total_pdus; @@ -622,10 +599,20 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_ul_success_rate(const asn1::e2sm::l meas_collected = true; continue; } - float success_rate = 0; - if (ue_aggr_rlc_metrics[ue_idx].rx.num_pdus) { - success_rate = 1.0 * (ue_aggr_rlc_metrics[ue_idx].rx.num_pdus - ue_aggr_rlc_metrics[ue_idx].rx.num_lost_pdus) / - ue_aggr_rlc_metrics[ue_idx].rx.num_pdus; + float success_rate = 0; + float total_lost_pdus = 0; + float total_pdus = 0; + auto ue_metric = ue_aggr_rlc_metrics[ue_idx]; + total_lost_pdus += + std::accumulate(ue_metric.begin(), ue_metric.end(), 0, [](size_t sum, const rlc_metrics& metric) { + return sum + metric.rx.num_lost_pdus; + }); + total_pdus += std::accumulate(ue_metric.begin(), ue_metric.end(), 0, [](size_t sum, const rlc_metrics& metric) { + return sum + metric.rx.num_pdus; + }); + + if (total_pdus) { + success_rate = 1.0 * (total_pdus - total_lost_pdus) / total_pdus; } uint32_t success_rate_int = success_rate * 100; meas_record_item.set_integer() = success_rate_int; @@ -660,8 +647,14 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_rlc_packet_drop_rate_dl( uint32_t total_dropped_sdus = 0; uint32_t total_tx_num_sdus = 0; for (auto& rlc_metric : ue_aggr_rlc_metrics) { - total_dropped_sdus += rlc_metric.second.tx.num_dropped_sdus + rlc_metric.second.tx.num_discarded_sdus; - total_tx_num_sdus += rlc_metric.second.tx.num_sdus; + total_dropped_sdus += std::accumulate( + rlc_metric.second.begin(), rlc_metric.second.end(), 0, [](size_t sum, const rlc_metrics& metric) { + return sum + metric.tx.num_dropped_sdus + metric.tx.num_discarded_sdus; + }); + total_tx_num_sdus += std::accumulate( + rlc_metric.second.begin(), rlc_metric.second.end(), 0, [](size_t sum, const rlc_metrics& metric) { + return sum + metric.tx.num_sdus; + }); } if (total_tx_num_sdus) { drop_rate = 1.0 * total_dropped_sdus / total_tx_num_sdus; @@ -682,11 +675,21 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_rlc_packet_drop_rate_dl( meas_collected = true; continue; } - float drop_rate = 0; - if (ue_aggr_rlc_metrics[ue_idx].tx.num_sdus) { - uint32_t dropped_sdus = - ue_aggr_rlc_metrics[ue_idx].tx.num_dropped_sdus + ue_aggr_rlc_metrics[ue_idx].tx.num_discarded_sdus; - drop_rate = 1.0 * dropped_sdus / ue_aggr_rlc_metrics[ue_idx].tx.num_sdus; + float drop_rate = 0; + uint32_t total_dropped_sdus = + std::accumulate(ue_aggr_rlc_metrics[ue_idx].begin(), + ue_aggr_rlc_metrics[ue_idx].end(), + 0, + [](size_t sum, const rlc_metrics& metric) { + return sum + metric.tx.num_dropped_sdus + metric.tx.num_discarded_sdus; + }); + uint32_t total_tx_num_sdus = + std::accumulate(ue_aggr_rlc_metrics[ue_idx].begin(), + ue_aggr_rlc_metrics[ue_idx].end(), + 0, + [](size_t sum, const rlc_metrics& metric) { return sum + metric.tx.num_sdus; }); + if (total_tx_num_sdus) { + drop_rate = 1.0 * total_dropped_sdus / total_tx_num_sdus; } uint32_t drop_rate_int = drop_rate * 100; meas_record_item.set_integer() = drop_rate_int; @@ -720,7 +723,10 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_rlc_sdu_transmitted_volume_dl( meas_record_item_c meas_record_item; size_t total_tx_num_sdu_bytes = 0; for (auto& rlc_metric : ue_aggr_rlc_metrics) { - total_tx_num_sdu_bytes += rlc_metric.second.tx.num_sdu_bytes; + total_tx_num_sdu_bytes += std::accumulate( + rlc_metric.second.begin(), rlc_metric.second.end(), 0, [](size_t sum, const rlc_metrics& metric) { + return sum + metric.tx.num_sdu_bytes; + }); } meas_record_item.set_integer() = total_tx_num_sdu_bytes * 8 / 1000; // unit is kbit items.push_back(meas_record_item); @@ -737,7 +743,12 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_rlc_sdu_transmitted_volume_dl( meas_collected = true; continue; } - meas_record_item.set_integer() = ue_aggr_rlc_metrics[ue_idx].tx.num_sdu_bytes * 8 / 1000; // unit is kbit + int num_sdu_bytes = + std::accumulate(ue_aggr_rlc_metrics[ue_idx].begin(), + ue_aggr_rlc_metrics[ue_idx].end(), + 0, + [](size_t sum, const rlc_metrics& metric) { return sum + metric.tx.num_sdu_bytes; }); + meas_record_item.set_integer() = num_sdu_bytes * 8 / 1000; // unit is kbit items.push_back(meas_record_item); meas_collected = true; } @@ -768,7 +779,10 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_rlc_sdu_transmitted_volume_ul( meas_record_item_c meas_record_item; size_t total_rx_num_sdu_bytes = 0; for (auto& rlc_metric : ue_aggr_rlc_metrics) { - total_rx_num_sdu_bytes += rlc_metric.second.rx.num_sdu_bytes; + total_rx_num_sdu_bytes += std::accumulate( + rlc_metric.second.begin(), rlc_metric.second.end(), 0, [](size_t sum, const rlc_metrics& metric) { + return sum + metric.rx.num_sdu_bytes; + }); } meas_record_item.set_integer() = total_rx_num_sdu_bytes * 8 / 1000; // unit is kbit items.push_back(meas_record_item); @@ -785,7 +799,12 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_rlc_sdu_transmitted_volume_ul( meas_collected = true; continue; } - meas_record_item.set_integer() = ue_aggr_rlc_metrics[ue_idx].rx.num_sdu_bytes * 8 / 1000; // unit is kbit + int num_sdu_bytes = + std::accumulate(ue_aggr_rlc_metrics[ue_idx].begin(), + ue_aggr_rlc_metrics[ue_idx].end(), + 0, + [](size_t sum, const rlc_metrics& metric) { return sum + metric.rx.num_sdu_bytes; }); + meas_record_item.set_integer() = num_sdu_bytes * 8 / 1000; // unit is kbit items.push_back(meas_record_item); meas_collected = true; } @@ -808,9 +827,16 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_dl_rlc_sdu_latency(const asn1::e2sm meas_record_item_c meas_record_item; float av_ue_sdu_latency_us = 0; for (auto& rlc_metric : ue_aggr_rlc_metrics) { - if (rlc_metric.second.tx.num_of_pulled_sdus && rlc_metric.second.tx.sum_sdu_latency_us) { - av_ue_sdu_latency_us += - (float)rlc_metric.second.tx.sum_sdu_latency_us / (float)rlc_metric.second.tx.num_of_pulled_sdus; + int tot_num_of_pulled_sdus = std::accumulate( + rlc_metric.second.begin(), rlc_metric.second.end(), 0, [](size_t sum, const rlc_metrics& metric) { + return sum + metric.tx.num_of_pulled_sdus; + }); + int tot_sum_sdu_latency_us = std::accumulate( + rlc_metric.second.begin(), rlc_metric.second.end(), 0, [](size_t sum, const rlc_metrics& metric) { + return sum + metric.tx.sum_sdu_latency_us; + }); + if (tot_num_of_pulled_sdus && tot_sum_sdu_latency_us) { + av_ue_sdu_latency_us += (float)tot_sum_sdu_latency_us / (float)tot_num_of_pulled_sdus; } } if (av_ue_sdu_latency_us) { @@ -833,10 +859,19 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_dl_rlc_sdu_latency(const asn1::e2sm meas_collected = true; continue; } - if (ue_aggr_rlc_metrics[ue_idx].tx.sum_sdu_latency_us) { + int tot_sdu_latency_us = + std::accumulate(ue_aggr_rlc_metrics[ue_idx].begin(), + ue_aggr_rlc_metrics[ue_idx].end(), + 0, + [](size_t sum, const rlc_metrics& metric) { return sum + metric.tx.sum_sdu_latency_us; }); + int tot_num_sdus = + std::accumulate(ue_aggr_rlc_metrics[ue_idx].begin(), + ue_aggr_rlc_metrics[ue_idx].end(), + 0, + [](size_t sum, const rlc_metrics& metric) { return sum + metric.tx.num_sdus; }); + if (tot_sdu_latency_us) { meas_record_item.set_real(); - meas_record_item.real().value = - ue_aggr_rlc_metrics[ue_idx].tx.sum_sdu_latency_us / ue_aggr_rlc_metrics[ue_idx].tx.num_sdus; + meas_record_item.real().value = tot_sdu_latency_us / tot_num_sdus; items.push_back(meas_record_item); meas_collected = true; } else { @@ -862,13 +897,21 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_ul_rlc_sdu_latency(const asn1::e2sm meas_record_item_c meas_record_item; float av_ue_sdu_latency_us = 0; for (auto& rlc_metric : ue_aggr_rlc_metrics) { - if (rlc_metric.second.rx.num_sdus && rlc_metric.second.rx.sdu_latency_us) { - av_ue_sdu_latency_us += (float)rlc_metric.second.rx.sdu_latency_us / (float)rlc_metric.second.rx.sdu_latency_us; + int tot_num_sdus = std::accumulate( + rlc_metric.second.begin(), rlc_metric.second.end(), 0, [](size_t sum, const rlc_metrics& metric) { + return sum + metric.rx.num_sdus; + }); + int tot_sdu_latency_us = std::accumulate( + rlc_metric.second.begin(), rlc_metric.second.end(), 0, [](size_t sum, const rlc_metrics& metric) { + return sum + metric.rx.sdu_latency_us; + }); + if (tot_num_sdus && tot_sdu_latency_us) { + av_ue_sdu_latency_us += (float)tot_sdu_latency_us / (float)tot_num_sdus; } } if (av_ue_sdu_latency_us) { meas_record_item.set_real(); - meas_record_item.real().value = av_ue_sdu_latency_us / ue_aggr_rlc_metrics.size(); + meas_record_item.real().value = (float)av_ue_sdu_latency_us / ue_aggr_rlc_metrics.size(); items.push_back(meas_record_item); meas_collected = true; } else { @@ -886,10 +929,19 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_ul_rlc_sdu_latency(const asn1::e2sm meas_collected = true; continue; } - if (ue_aggr_rlc_metrics[ue_idx].rx.sdu_latency_us) { + int tot_sdu_latency = + std::accumulate(ue_aggr_rlc_metrics[ue_idx].begin(), + ue_aggr_rlc_metrics[ue_idx].end(), + 0, + [](size_t sum, const rlc_metrics& metric) { return sum + metric.rx.sdu_latency_us; }); + int tot_num_sdus = + std::accumulate(ue_aggr_rlc_metrics[ue_idx].begin(), + ue_aggr_rlc_metrics[ue_idx].end(), + 0, + [](size_t sum, const rlc_metrics& metric) { return sum + metric.rx.num_sdus; }); + if (tot_sdu_latency) { meas_record_item.set_real(); - meas_record_item.real().value = - ue_aggr_rlc_metrics[ue_idx].rx.sdu_latency_us / ue_aggr_rlc_metrics[ue_idx].rx.num_sdus; + meas_record_item.real().value = tot_sdu_latency / tot_num_sdus; items.push_back(meas_record_item); meas_collected = true; } else { @@ -898,4 +950,4 @@ bool e2sm_kpm_du_meas_provider_impl::get_drb_ul_rlc_sdu_latency(const asn1::e2sm } } return meas_collected; -} \ No newline at end of file +} diff --git a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h index 746abdf026..f1518aef16 100644 --- a/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h +++ b/lib/e2/e2sm/e2sm_kpm/e2sm_kpm_du_meas_provider_impl.h @@ -103,7 +103,8 @@ class e2sm_kpm_du_meas_provider_impl : public e2sm_kpm_meas_provider, public e2_ srslog::basic_logger& logger; srs_du::f1ap_ue_id_translator& f1ap_ue_id_provider; std::vector last_ue_metrics; - std::map ue_aggr_rlc_metrics; + std::map> ue_aggr_rlc_metrics; + const size_t max_rlc_metrics = 30; std::map supported_metrics; }; diff --git a/tests/unittests/e2/e2sm_kpm_meas_provider_test.cpp b/tests/unittests/e2/e2sm_kpm_meas_provider_test.cpp index ec6c27d65e..72746c44da 100644 --- a/tests/unittests/e2/e2sm_kpm_meas_provider_test.cpp +++ b/tests/unittests/e2/e2sm_kpm_meas_provider_test.cpp @@ -115,6 +115,7 @@ class e2sm_kpm_meas_provider_test : public ::testing::Test rlc_metrics generate_rlc_metrics(uint32_t ue_idx, uint32_t bearer_id) { rlc_metrics rlc_metric; + rlc_metric.metrics_period = std::chrono::milliseconds(1000); rlc_metric.ue_index = static_cast(ue_idx); rlc_metric.rb_id = rb_id_t(drb_id_t(bearer_id)); rlc_metric.rx.mode = rlc_mode::am; @@ -271,10 +272,10 @@ TEST_F(e2sm_kpm_meas_provider_test, e2sm_kpm_ind_three_drb_rlc_metrics) TESTASSERT_EQ(nof_records, meas_record.size()); TESTASSERT_EQ(expected_drop_rate, meas_record[0].integer()); if (nof_records >= 2) { - TESTASSERT_EQ(expected_dl_vol[ue_idx], meas_record[1].integer()); + TESTASSERT_EQ((i + 1) * expected_dl_vol[ue_idx], meas_record[1].integer()); } if (nof_records >= 3) { - TESTASSERT_EQ(expected_ul_vol[ue_idx], meas_record[2].integer()); + TESTASSERT_EQ((i + 1) * expected_ul_vol[ue_idx], meas_record[2].integer()); } if (nof_records >= 4) { TESTASSERT_EQ(expected_ul_success_rate, meas_record[3].integer()); @@ -375,8 +376,8 @@ TEST_F(e2sm_kpm_meas_provider_test, e2sm_kpm_ind_e2_level_rlc_metrics) auto& meas_record = ric_ind_msg.ind_msg_formats.ind_msg_format1().meas_data[i].meas_record; TESTASSERT_EQ(nof_records, meas_record.size()); TESTASSERT_EQ(expected_drop_rate, meas_record[0].integer()); - TESTASSERT_EQ(expected_dl_vol, meas_record[1].integer()); - TESTASSERT_EQ(expected_ul_vol, meas_record[2].integer()); + TESTASSERT_EQ((i + 1) * expected_dl_vol, meas_record[1].integer()); + TESTASSERT_EQ((i + 1) * expected_ul_vol, meas_record[2].integer()); } #if PCAP_OUTPUT From 8b48b38f23b2d89169b428ef5e6436110e79db1a Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Fri, 19 Jul 2024 12:18:32 +0200 Subject: [PATCH 31/54] sched: fix failing unittests for PUCCH F0 Signed-off-by: Carlo Galiotto --- .../uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp | 8 ++++++++ .../unittests/scheduler/uci_and_pucch/uci_test_utils.cpp | 6 ++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp b/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp index 91bb7c63b2..badce03ce5 100644 --- a/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp +++ b/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp @@ -1665,6 +1665,7 @@ TEST_F(test_pucch_allocator_format_0, test_harq_allocation_3_bits_over_sr) pucch_expected_f2.format_2.harq_ack_nof_bits = 3U; pucch_expected_f2.format_2.sr_bits = srsran::sr_nof_bits::no_sr; + pucch_expected_f2.format_2.csi_part1_bits = 0U; // Change PRBs and symbol, as for Format 0 we use a different set of resources: // - 4 PUCCH format 0 aligned on PRBs [0..1), 3 resources for HARQ with symbols [0..6), 1 for SR with symbols [6..8). // - 6 PUCCH format 2 aligned on PRBs [1..2), 6 resources for HARQ with symbols [0..12), 1 for CSI with @@ -1697,6 +1698,7 @@ TEST_F(test_pucch_allocator_format_0, test_harq_allocation_4_bits_over_sr) pucch_expected_f2.format_2.harq_ack_nof_bits = 4U; pucch_expected_f2.format_2.sr_bits = srsran::sr_nof_bits::no_sr; + pucch_expected_f2.format_2.csi_part1_bits = 0U; // Change PRBs and symbol, as for Format 0 we use a different set of resources: // - 4 PUCCH format 0 aligned on PRBs [0..1), 3 resources for HARQ with symbols [0..6), 1 for SR with symbols [6..8). // - 6 PUCCH format 2 aligned on PRBs [1..2), 6 resources for HARQ with symbols [0..12), 1 for CSI with @@ -1735,6 +1737,7 @@ TEST_F(test_pucch_allocator_format_0, test_harq_allocation_over_csi) pucch_expected_csi.resources.prbs.set(1, 2); pucch_expected_csi.resources.symbols.set(12, 14); pucch_expected_csi.format_2.harq_ack_nof_bits = 0U; + pucch_expected_csi.format_2.sr_bits = sr_nof_bits::no_sr; pucch_expected_csi.format_2.csi_part1_bits = csi_part1_bits; ASSERT_TRUE(test_pucch_res_indicator.has_value()); ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); @@ -1768,6 +1771,7 @@ TEST_F(test_pucch_allocator_format_0, test_harq_allocation_2_bits_over_csi) pucch_expected_csi.resources.prbs.set(1, 2); pucch_expected_csi.resources.symbols.set(12, 14); pucch_expected_csi.format_2.harq_ack_nof_bits = 0U; + pucch_expected_csi.format_2.sr_bits = sr_nof_bits::no_sr; pucch_expected_csi.format_2.csi_part1_bits = csi_part1_bits; ASSERT_TRUE(test_pucch_res_indicator.has_value()); ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); @@ -1797,6 +1801,7 @@ TEST_F(test_pucch_allocator_format_0, test_harq_allocation_3_bits_over_csi) pucch_expected_f2.format_2.harq_ack_nof_bits = 3U; pucch_expected_f2.format_2.sr_bits = srsran::sr_nof_bits::no_sr; + pucch_expected_f2.format_2.csi_part1_bits = 0U; // Change PRBs and symbol, as for Format 0 we use a different set of resources: // - 4 PUCCH format 0 aligned on PRBs [0..1), 3 resources for HARQ with symbols [0..6), 1 for SR with symbols [6..8). // - 6 PUCCH format 2 aligned on PRBs [1..2), 6 resources for HARQ with symbols [0..12), 1 for CSI with @@ -1806,6 +1811,7 @@ TEST_F(test_pucch_allocator_format_0, test_harq_allocation_3_bits_over_csi) pucch_expected_csi.resources.prbs.set(1, 2); pucch_expected_csi.resources.symbols.set(12, 14); pucch_expected_csi.format_2.harq_ack_nof_bits = 0U; + pucch_expected_csi.format_2.sr_bits = sr_nof_bits::no_sr; pucch_expected_csi.format_2.csi_part1_bits = csi_part1_bits; ASSERT_TRUE(test_pucch_res_indicator.has_value()); ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); @@ -1832,6 +1838,7 @@ TEST_F(test_pucch_allocator_format_0, test_harq_allocation_4_bits_over_csi) pucch_expected_f2.format_2.harq_ack_nof_bits = 4U; pucch_expected_f2.format_2.sr_bits = srsran::sr_nof_bits::no_sr; + pucch_expected_f2.format_2.csi_part1_bits = 0U; // Change PRBs and symbol, as for Format 0 we use a different set of resources: // - 4 PUCCH format 0 aligned on PRBs [0..1), 3 resources for HARQ with symbols [0..6), 1 for SR with symbols [6..8). // - 6 PUCCH format 2 aligned on PRBs [1..2), 6 resources for HARQ with symbols [0..12), 1 for CSI with @@ -1841,6 +1848,7 @@ TEST_F(test_pucch_allocator_format_0, test_harq_allocation_4_bits_over_csi) pucch_expected_csi.resources.prbs.set(1, 2); pucch_expected_csi.resources.symbols.set(12, 14); pucch_expected_csi.format_2.harq_ack_nof_bits = 0U; + pucch_expected_csi.format_2.sr_bits = sr_nof_bits::no_sr; pucch_expected_csi.format_2.csi_part1_bits = csi_part1_bits; ASSERT_TRUE(test_pucch_res_indicator.has_value()); ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator); diff --git a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp index 8daad73aa0..178fe76e3d 100644 --- a/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp +++ b/tests/unittests/scheduler/uci_and_pucch/uci_test_utils.cpp @@ -196,8 +196,10 @@ test_bench::test_bench(const test_bench_params& params, pucch_params.f0_or_f1_params.emplace(); pucch_builder.setup( cell_cfg.ul_cfg_common.init_ul_bwp, params.is_tdd ? cell_cfg.tdd_cfg_common : std::nullopt, pucch_params); - srsran_assert(pucch_builder.add_build_new_ue_pucch_cfg(ue_req.cfg.cells.value().back().serv_cell_cfg), - "UE PUCCH configuration couldn't be built"); + bool new_ue_added = pucch_builder.add_build_new_ue_pucch_cfg(ue_req.cfg.cells.value().back().serv_cell_cfg); + if (not new_ue_added) { + srsran_terminate("UE PUCCH configuration couldn't be built"); + } } ue_ded_cfgs.push_back(std::make_unique(ue_req.ue_index, ue_req.crnti, cell_cfg_list, ue_req.cfg)); From 73dd8bf94d227ea3baec055e946dbcc65c9983e9 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Thu, 18 Jul 2024 18:58:52 +0200 Subject: [PATCH 32/54] sched: fix applying of nof. RBs to allocate configured for PDSCH/PUSCH --- lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp index 6e2f8bb049..aa13d67aad 100644 --- a/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp +++ b/lib/scheduler/ue_scheduling/ue_cell_grid_allocator.cpp @@ -222,6 +222,9 @@ alloc_result ue_cell_grid_allocator::allocate_dl_grant(const ue_pdsch_grant& gra if (grant.max_nof_rbs.has_value()) { mcs_prbs.n_prbs = std::min(mcs_prbs.n_prbs, grant.max_nof_rbs.value()); } + // Re-apply nof. PDSCH RBs to allocate limits. + mcs_prbs.n_prbs = std::max(mcs_prbs.n_prbs, expert_cfg.pdsch_nof_rbs.start()); + mcs_prbs.n_prbs = std::min(mcs_prbs.n_prbs, expert_cfg.pdsch_nof_rbs.stop()); } if (mcs_prbs.n_prbs == 0) { @@ -718,6 +721,9 @@ alloc_result ue_cell_grid_allocator::allocate_ul_grant(const ue_pusch_grant& gra if (grant.max_nof_rbs.has_value()) { mcs_prbs.n_prbs = std::min(mcs_prbs.n_prbs, grant.max_nof_rbs.value()); } + // Re-apply nof. PUSCH RBs to allocate limits. + mcs_prbs.n_prbs = std::max(mcs_prbs.n_prbs, expert_cfg.pusch_nof_rbs.start()); + mcs_prbs.n_prbs = std::min(mcs_prbs.n_prbs, expert_cfg.pusch_nof_rbs.stop()); } // NOTE: This should never happen, but it's safe not to proceed if we get n_prbs == 0. From 340670c627cfc8934dd39413acdd019b1da127e0 Mon Sep 17 00:00:00 2001 From: Supreeth Herle Date: Thu, 18 Jul 2024 20:01:56 +0200 Subject: [PATCH 33/54] unittest: extend ue cell grid allocator tests to test parameters configured in expert cfg --- .../ue_scheduling/ue_grid_allocator_test.cpp | 392 ++++++++++++++---- 1 file changed, 302 insertions(+), 90 deletions(-) diff --git a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp index 4e9d40f1f3..9d61caa05a 100644 --- a/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp +++ b/tests/unittests/scheduler/ue_scheduling/ue_grid_allocator_test.cpp @@ -28,13 +28,9 @@ using namespace srsran; class ue_grid_allocator_tester : public ::testing::TestWithParam { protected: - ue_grid_allocator_tester() : - expert_cfg([this]() { - auto ue_expert_cfg = sched_cfg.ue; - ue_expert_cfg.max_ul_grants_per_slot = 2; - ue_expert_cfg.max_pucchs_per_slot = 2; - return ue_expert_cfg; - }()), + ue_grid_allocator_tester( + scheduler_expert_config sched_cfg_ = config_helpers::make_default_scheduler_expert_config()) : + sched_cfg(sched_cfg_), cell_cfg(*[this]() { cfg_builder_params.dl_arfcn = GetParam() == duplex_mode::FDD ? 530000 : 520002; cfg_builder_params.scs_common = @@ -106,7 +102,7 @@ class ue_grid_allocator_tester : public ::testing::TestWithParam return ues[ue_creation_req.ue_index]; } - scheduler_expert_config sched_cfg = config_helpers::make_default_scheduler_expert_config(); + scheduler_expert_config sched_cfg; scheduler_ue_expert_config expert_cfg{sched_cfg.ue}; sched_cfg_dummy_notifier mac_notif; scheduler_ue_metrics_dummy_notifier metrics_notif; @@ -188,47 +184,6 @@ TEST_P(ue_grid_allocator_tester, when_using_non_fallback_dci_format_use_mcs_tabl srsran::pdsch_mcs_table::qam256); } -TEST_P(ue_grid_allocator_tester, remaining_dl_rbs_are_allocated_if_max_pucch_per_slot_is_reached) -{ - sched_ue_creation_request_message ue_creation_req = - test_helpers::create_default_sched_ue_creation_request(this->cfg_builder_params); - ue_creation_req.ue_index = to_du_ue_index(0); - ue_creation_req.crnti = to_rnti(0x4601); - const ue& u1 = add_ue(ue_creation_req); - ue_creation_req.ue_index = to_du_ue_index(1); - ue_creation_req.crnti = to_rnti(0x4602); - const ue& u2 = add_ue(ue_creation_req); - - static const unsigned sched_bytes = 20U; - const ue_pdsch_grant grant1{ - .user = &u1, .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = sched_bytes}; - - // Since UE dedicated SearchSpace is a UE specific SearchSpace (Not CSS). Entire BWP CRBs can be used for allocation. - const unsigned total_crbs = cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.crbs.length(); - const ue_pdsch_grant grant2{ - .user = &u2, .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = sched_bytes}; - - ASSERT_TRUE(run_until([&]() { - return alloc.allocate_dl_grant(grant1).status == alloc_status::success and - alloc.allocate_dl_grant(grant2).status == alloc_status::success; - })); - ASSERT_TRUE(run_until([&]() { - return find_ue_pdsch(u1.crnti, res_grid[0].result.dl.ue_grants) != nullptr and - find_ue_pdsch(u2.crnti, res_grid[0].result.dl.ue_grants) != nullptr; - })); - // Successfully allocates PDSCH corresponding to the grant. - ASSERT_GE(find_ue_pdsch(u1.crnti, res_grid[0].result.dl.ue_grants)->pdsch_cfg.codewords.back().tb_size_bytes, - sched_bytes); - - // Since UE dedicated SearchSpace is a UE specific SearchSpace (Not CSS). Entire BWP CRBs can be used for allocation. - const unsigned crbs_allocated = - find_ue_pdsch(u1.crnti, res_grid[0].result.dl.ue_grants)->pdsch_cfg.rbs.type1().length(); - - // Allocates all remaining RBs to UE2. - ASSERT_EQ(find_ue_pdsch(u2.crnti, res_grid[0].result.dl.ue_grants)->pdsch_cfg.rbs.type1().length(), - (total_crbs - crbs_allocated)); -} - TEST_P(ue_grid_allocator_tester, allocates_pdsch_restricted_to_recommended_max_nof_rbs) { sched_ue_creation_request_message ue_creation_req = @@ -253,47 +208,6 @@ TEST_P(ue_grid_allocator_tester, allocates_pdsch_restricted_to_recommended_max_n grant1.max_nof_rbs); } -TEST_P(ue_grid_allocator_tester, remaining_ul_rbs_are_allocated_if_max_ul_grant_per_slot_is_reached) -{ - sched_ue_creation_request_message ue_creation_req = - test_helpers::create_default_sched_ue_creation_request(this->cfg_builder_params); - ue_creation_req.ue_index = to_du_ue_index(0); - ue_creation_req.crnti = to_rnti(0x4601); - const ue& u1 = add_ue(ue_creation_req); - ue_creation_req.ue_index = to_du_ue_index(1); - ue_creation_req.crnti = to_rnti(0x4602); - const ue& u2 = add_ue(ue_creation_req); - - const unsigned recommended_nof_bytes_to_schedule = 200U; - - const crb_interval cell_crbs = {cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs.start(), - cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs.stop()}; - const ue_pusch_grant grant1{.user = &u1, - .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(0), - .recommended_nof_bytes = recommended_nof_bytes_to_schedule}; - const ue_pusch_grant grant2{.user = &u2, - .cell_index = to_du_cell_index(0), - .h_id = to_harq_id(0), - .recommended_nof_bytes = recommended_nof_bytes_to_schedule}; - - ASSERT_TRUE(run_until([&]() { - return alloc.allocate_ul_grant(grant1).status == alloc_status::success and - alloc.allocate_ul_grant(grant2).status == alloc_status::success; - })); - ASSERT_TRUE(run_until([&]() { - return find_ue_pusch(u1.crnti, res_grid[0].result.ul) != nullptr and find_ue_pusch(u2.crnti, res_grid[0].result.ul); - })); - // Successfully allocates PUSCH corresponding to the grant. - ASSERT_GE(find_ue_pusch(u1.crnti, res_grid[0].result.ul)->pusch_cfg.tb_size_bytes, grant1.recommended_nof_bytes); - - const unsigned remaining_crbs = - cell_crbs.length() - find_ue_pusch(u1.crnti, res_grid[0].result.ul)->pusch_cfg.rbs.type1().length(); - - // Allocates all remaining RBs to UE2. - ASSERT_EQ(find_ue_pusch(u2.crnti, res_grid[0].result.ul)->pusch_cfg.rbs.type1().length(), remaining_crbs); -} - TEST_P(ue_grid_allocator_tester, allocates_pusch_restricted_to_recommended_max_nof_rbs) { sched_ue_creation_request_message ue_creation_req = @@ -580,6 +494,304 @@ TEST_P(ue_grid_allocator_tester, successfully_allocated_pusch_even_with_large_ga nof_slot_until_pusch_is_allocated_threshold)); } +class ue_grid_allocator_remaining_rbs_alloc_tester : public ue_grid_allocator_tester +{ +public: + ue_grid_allocator_remaining_rbs_alloc_tester() : + ue_grid_allocator_tester(([]() { + scheduler_expert_config sched_cfg_ = config_helpers::make_default_scheduler_expert_config(); + sched_cfg_.ue.max_ul_grants_per_slot = 2; + sched_cfg_.ue.max_pucchs_per_slot = 2; + return sched_cfg_; + }())) + { + } +}; + +TEST_P(ue_grid_allocator_remaining_rbs_alloc_tester, remaining_dl_rbs_are_allocated_if_max_pucch_per_slot_is_reached) +{ + sched_ue_creation_request_message ue_creation_req = + test_helpers::create_default_sched_ue_creation_request(this->cfg_builder_params); + ue_creation_req.ue_index = to_du_ue_index(0); + ue_creation_req.crnti = to_rnti(0x4601); + const ue& u1 = add_ue(ue_creation_req); + ue_creation_req.ue_index = to_du_ue_index(1); + ue_creation_req.crnti = to_rnti(0x4602); + const ue& u2 = add_ue(ue_creation_req); + + static const unsigned sched_bytes = 20U; + const ue_pdsch_grant grant1{ + .user = &u1, .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = sched_bytes}; + + // Since UE dedicated SearchSpace is a UE specific SearchSpace (Not CSS). Entire BWP CRBs can be used for allocation. + const unsigned total_crbs = cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.crbs.length(); + const ue_pdsch_grant grant2{ + .user = &u2, .cell_index = to_du_cell_index(0), .h_id = to_harq_id(0), .recommended_nof_bytes = sched_bytes}; + + ASSERT_TRUE(run_until([&]() { + return alloc.allocate_dl_grant(grant1).status == alloc_status::success and + alloc.allocate_dl_grant(grant2).status == alloc_status::success; + })); + ASSERT_TRUE(run_until([&]() { + return find_ue_pdsch(u1.crnti, res_grid[0].result.dl.ue_grants) != nullptr and + find_ue_pdsch(u2.crnti, res_grid[0].result.dl.ue_grants) != nullptr; + })); + // Successfully allocates PDSCH corresponding to the grant. + ASSERT_GE(find_ue_pdsch(u1.crnti, res_grid[0].result.dl.ue_grants)->pdsch_cfg.codewords.back().tb_size_bytes, + sched_bytes); + + // Since UE dedicated SearchSpace is a UE specific SearchSpace (Not CSS). Entire BWP CRBs can be used for allocation. + const unsigned crbs_allocated = + find_ue_pdsch(u1.crnti, res_grid[0].result.dl.ue_grants)->pdsch_cfg.rbs.type1().length(); + + // Allocates all remaining RBs to UE2. + ASSERT_EQ(find_ue_pdsch(u2.crnti, res_grid[0].result.dl.ue_grants)->pdsch_cfg.rbs.type1().length(), + (total_crbs - crbs_allocated)); +} + +TEST_P(ue_grid_allocator_remaining_rbs_alloc_tester, remaining_ul_rbs_are_allocated_if_max_ul_grant_per_slot_is_reached) +{ + sched_ue_creation_request_message ue_creation_req = + test_helpers::create_default_sched_ue_creation_request(this->cfg_builder_params); + ue_creation_req.ue_index = to_du_ue_index(0); + ue_creation_req.crnti = to_rnti(0x4601); + const ue& u1 = add_ue(ue_creation_req); + ue_creation_req.ue_index = to_du_ue_index(1); + ue_creation_req.crnti = to_rnti(0x4602); + const ue& u2 = add_ue(ue_creation_req); + + const unsigned recommended_nof_bytes_to_schedule = 200U; + + const crb_interval cell_crbs = {cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs.start(), + cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs.stop()}; + const ue_pusch_grant grant1{.user = &u1, + .cell_index = to_du_cell_index(0), + .h_id = to_harq_id(0), + .recommended_nof_bytes = recommended_nof_bytes_to_schedule}; + const ue_pusch_grant grant2{.user = &u2, + .cell_index = to_du_cell_index(0), + .h_id = to_harq_id(0), + .recommended_nof_bytes = recommended_nof_bytes_to_schedule}; + + ASSERT_TRUE(run_until([&]() { + return alloc.allocate_ul_grant(grant1).status == alloc_status::success and + alloc.allocate_ul_grant(grant2).status == alloc_status::success; + })); + ASSERT_TRUE(run_until([&]() { + return find_ue_pusch(u1.crnti, res_grid[0].result.ul) != nullptr and find_ue_pusch(u2.crnti, res_grid[0].result.ul); + })); + // Successfully allocates PUSCH corresponding to the grant. + ASSERT_GE(find_ue_pusch(u1.crnti, res_grid[0].result.ul)->pusch_cfg.tb_size_bytes, grant1.recommended_nof_bytes); + + const unsigned remaining_crbs = + cell_crbs.length() - find_ue_pusch(u1.crnti, res_grid[0].result.ul)->pusch_cfg.rbs.type1().length(); + + // Allocates all remaining RBs to UE2. + ASSERT_EQ(find_ue_pusch(u2.crnti, res_grid[0].result.ul)->pusch_cfg.rbs.type1().length(), remaining_crbs); +} + +class ue_grid_allocator_expert_cfg_pxsch_nof_rbs_limits_tester : public ue_grid_allocator_tester +{ +public: + ue_grid_allocator_expert_cfg_pxsch_nof_rbs_limits_tester() : + ue_grid_allocator_tester(([]() { + scheduler_expert_config sched_cfg_ = config_helpers::make_default_scheduler_expert_config(); + sched_cfg_.ue.pdsch_nof_rbs = {20, 40}; + sched_cfg_.ue.pusch_nof_rbs = {20, 40}; + return sched_cfg_; + }())) + { + } +}; + +TEST_P(ue_grid_allocator_expert_cfg_pxsch_nof_rbs_limits_tester, + allocates_pdsch_with_expert_cfg_min_nof_rbs_even_if_rbs_required_to_schedule_is_low) +{ + sched_ue_creation_request_message ue_creation_req = + test_helpers::create_default_sched_ue_creation_request(this->cfg_builder_params); + ue_creation_req.ue_index = to_du_ue_index(0); + ue_creation_req.crnti = to_rnti(0x4601); + const ue& u1 = add_ue(ue_creation_req); + + // Ensure the buffer status is low enough such that < 20 RBs (configured in constructor) are required to schedule. + static const unsigned sched_bytes = 20U; + const unsigned max_nof_rbs_to_schedule = 10U; + + const ue_pdsch_grant grant1{.user = &u1, + .cell_index = to_du_cell_index(0), + .h_id = to_harq_id(0), + .recommended_nof_bytes = sched_bytes, + .max_nof_rbs = max_nof_rbs_to_schedule}; + + ASSERT_TRUE(run_until([&]() { return alloc.allocate_dl_grant(grant1).status == alloc_status::success; })); + ASSERT_TRUE(run_until([&]() { return find_ue_pdsch(u1.crnti, res_grid[0].result.dl.ue_grants) != nullptr; })); + // Successfully allocates PDSCH. + ASSERT_EQ(find_ue_pdsch(u1.crnti, res_grid[0].result.dl.ue_grants)->pdsch_cfg.rbs.type1().length(), + std::max(expert_cfg.pdsch_nof_rbs.start(), max_nof_rbs_to_schedule)); +} + +TEST_P(ue_grid_allocator_expert_cfg_pxsch_nof_rbs_limits_tester, + allocates_pdsch_with_expert_cfg_max_nof_rbs_even_if_rbs_required_to_schedule_is_high) +{ + sched_ue_creation_request_message ue_creation_req = + test_helpers::create_default_sched_ue_creation_request(this->cfg_builder_params); + ue_creation_req.ue_index = to_du_ue_index(0); + ue_creation_req.crnti = to_rnti(0x4601); + const ue& u1 = add_ue(ue_creation_req); + + // Ensure the buffer status is high enough such that > 40 RBs (configured in constructor) are required to schedule. + static const unsigned sched_bytes = 20000U; + const unsigned max_nof_rbs_to_schedule = 273U; + + const ue_pdsch_grant grant1{.user = &u1, + .cell_index = to_du_cell_index(0), + .h_id = to_harq_id(0), + .recommended_nof_bytes = sched_bytes, + .max_nof_rbs = max_nof_rbs_to_schedule}; + + ASSERT_TRUE(run_until([&]() { return alloc.allocate_dl_grant(grant1).status == alloc_status::success; })); + ASSERT_TRUE(run_until([&]() { return find_ue_pdsch(u1.crnti, res_grid[0].result.dl.ue_grants) != nullptr; })); + // Successfully allocates PDSCH. + ASSERT_EQ(find_ue_pdsch(u1.crnti, res_grid[0].result.dl.ue_grants)->pdsch_cfg.rbs.type1().length(), + std::min(expert_cfg.pdsch_nof_rbs.stop(), max_nof_rbs_to_schedule)); +} + +TEST_P(ue_grid_allocator_expert_cfg_pxsch_nof_rbs_limits_tester, + allocates_pusch_with_expert_cfg_min_nof_rbs_even_if_rbs_required_to_schedule_is_low) +{ + sched_ue_creation_request_message ue_creation_req = + test_helpers::create_default_sched_ue_creation_request(this->cfg_builder_params); + ue_creation_req.ue_index = to_du_ue_index(0); + ue_creation_req.crnti = to_rnti(0x4601); + const ue& u1 = add_ue(ue_creation_req); + + // Ensure the buffer status is low enough such that < 20 RBs (configured in constructor) are required to schedule. + const unsigned recommended_nof_bytes_to_schedule = 20U; + const unsigned max_nof_rbs_to_schedule = 10U; + + const ue_pusch_grant grant1{.user = &u1, + .cell_index = to_du_cell_index(0), + .h_id = to_harq_id(0), + .recommended_nof_bytes = recommended_nof_bytes_to_schedule, + .max_nof_rbs = max_nof_rbs_to_schedule}; + + ASSERT_TRUE(run_until([&]() { return alloc.allocate_ul_grant(grant1).status == alloc_status::success; })); + ASSERT_TRUE(run_until([&]() { return find_ue_pusch(u1.crnti, res_grid[0].result.ul) != nullptr; })); + // Successfully allocates PUSCH. + ASSERT_EQ(find_ue_pusch(u1.crnti, res_grid[0].result.ul)->pusch_cfg.rbs.type1().length(), + std::max(expert_cfg.pdsch_nof_rbs.start(), max_nof_rbs_to_schedule)); +} + +TEST_P(ue_grid_allocator_expert_cfg_pxsch_nof_rbs_limits_tester, + allocates_pusch_with_expert_cfg_max_nof_rbs_even_if_rbs_required_to_schedule_is_high) +{ + sched_ue_creation_request_message ue_creation_req = + test_helpers::create_default_sched_ue_creation_request(this->cfg_builder_params); + ue_creation_req.ue_index = to_du_ue_index(0); + ue_creation_req.crnti = to_rnti(0x4601); + const ue& u1 = add_ue(ue_creation_req); + + // Ensure the buffer status is high enough such that > 40 RBs (configured in constructor) are required to schedule. + const unsigned recommended_nof_bytes_to_schedule = 200000U; + const unsigned max_nof_rbs_to_schedule = 273U; + + const ue_pusch_grant grant1{.user = &u1, + .cell_index = to_du_cell_index(0), + .h_id = to_harq_id(0), + .recommended_nof_bytes = recommended_nof_bytes_to_schedule, + .max_nof_rbs = max_nof_rbs_to_schedule}; + + ASSERT_TRUE(run_until([&]() { return alloc.allocate_ul_grant(grant1).status == alloc_status::success; })); + ASSERT_TRUE(run_until([&]() { return find_ue_pusch(u1.crnti, res_grid[0].result.ul) != nullptr; })); + // Successfully allocates PUSCH. + ASSERT_EQ(find_ue_pusch(u1.crnti, res_grid[0].result.ul)->pusch_cfg.rbs.type1().length(), + std::min(expert_cfg.pdsch_nof_rbs.stop(), max_nof_rbs_to_schedule)); +} + +class ue_grid_allocator_expert_cfg_pxsch_crb_limits_tester : public ue_grid_allocator_tester +{ +public: + ue_grid_allocator_expert_cfg_pxsch_crb_limits_tester() : + ue_grid_allocator_tester(([]() { + scheduler_expert_config sched_cfg_ = config_helpers::make_default_scheduler_expert_config(); + sched_cfg_.ue.pdsch_crb_limits = {20, 40}; + sched_cfg_.ue.pusch_crb_limits = {20, 40}; + return sched_cfg_; + }())) + { + // Assume SS#2 is USS configured with DCI format 1_1/0_1 and is the only SS used for UE PDSCH/PUSCH scheduling. + const prb_interval pdsch_prbs = + crb_to_prb(cell_cfg.dl_cfg_common.init_dl_bwp.generic_params.crbs, sched_cfg.ue.pdsch_crb_limits); + pdsch_vrb_limits = vrb_interval{pdsch_prbs.start(), pdsch_prbs.stop()}; + pusch_vrb_limits = rb_helper::crb_to_vrb_ul_non_interleaved( + sched_cfg.ue.pusch_crb_limits, cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs.start()); + } + +protected: + vrb_interval pdsch_vrb_limits; + vrb_interval pusch_vrb_limits; +}; + +TEST_P(ue_grid_allocator_expert_cfg_pxsch_crb_limits_tester, allocates_pdsch_within_expert_cfg_pdsch_rb_limits) +{ + sched_ue_creation_request_message ue_creation_req = + test_helpers::create_default_sched_ue_creation_request(this->cfg_builder_params); + ue_creation_req.ue_index = to_du_ue_index(0); + ue_creation_req.crnti = to_rnti(0x4601); + const ue& u1 = add_ue(ue_creation_req); + + // Ensure the buffer status is high enough such that > 20 RBs (configured in constructor) are required to schedule. + static const unsigned sched_bytes = 20000U; + const unsigned max_nof_rbs_to_schedule = 273U; + + const ue_pdsch_grant grant1{.user = &u1, + .cell_index = to_du_cell_index(0), + .h_id = to_harq_id(0), + .recommended_nof_bytes = sched_bytes, + .max_nof_rbs = max_nof_rbs_to_schedule}; + + ASSERT_TRUE(run_until([&]() { return alloc.allocate_dl_grant(grant1).status == alloc_status::success; })); + ASSERT_TRUE(run_until([&]() { return find_ue_pdsch(u1.crnti, res_grid[0].result.dl.ue_grants) != nullptr; })); + // Successfully allocates PDSCH within RB limits. + ASSERT_EQ(find_ue_pdsch(u1.crnti, res_grid[0].result.dl.ue_grants)->pdsch_cfg.rbs.type1(), pdsch_vrb_limits); +} + +TEST_P(ue_grid_allocator_expert_cfg_pxsch_crb_limits_tester, allocates_pdsch_within_expert_cfg_pusch_rb_limits) +{ + sched_ue_creation_request_message ue_creation_req = + test_helpers::create_default_sched_ue_creation_request(this->cfg_builder_params); + ue_creation_req.ue_index = to_du_ue_index(0); + ue_creation_req.crnti = to_rnti(0x4601); + const ue& u1 = add_ue(ue_creation_req); + + // Ensure the buffer status is high enough such that > 20 RBs (configured in constructor) are required to schedule. + const unsigned recommended_nof_bytes_to_schedule = 200000U; + const unsigned max_nof_rbs_to_schedule = 273U; + + const ue_pusch_grant grant1{.user = &u1, + .cell_index = to_du_cell_index(0), + .h_id = to_harq_id(0), + .recommended_nof_bytes = recommended_nof_bytes_to_schedule, + .max_nof_rbs = max_nof_rbs_to_schedule}; + + ASSERT_TRUE(run_until([&]() { return alloc.allocate_ul_grant(grant1).status == alloc_status::success; })); + ASSERT_TRUE(run_until([&]() { return find_ue_pusch(u1.crnti, res_grid[0].result.ul) != nullptr; })); + // Successfully allocates PUSCH within RB limits. + ASSERT_EQ(find_ue_pusch(u1.crnti, res_grid[0].result.ul)->pusch_cfg.rbs.type1(), pusch_vrb_limits); +} + INSTANTIATE_TEST_SUITE_P(ue_grid_allocator_test, ue_grid_allocator_tester, testing::Values(duplex_mode::FDD, duplex_mode::TDD)); + +INSTANTIATE_TEST_SUITE_P(ue_grid_allocator_test, + ue_grid_allocator_remaining_rbs_alloc_tester, + testing::Values(duplex_mode::FDD, duplex_mode::TDD)); + +INSTANTIATE_TEST_SUITE_P(ue_grid_allocator_test, + ue_grid_allocator_expert_cfg_pxsch_nof_rbs_limits_tester, + testing::Values(duplex_mode::FDD, duplex_mode::TDD)); + +INSTANTIATE_TEST_SUITE_P(ue_grid_allocator_test, + ue_grid_allocator_expert_cfg_pxsch_crb_limits_tester, + testing::Values(duplex_mode::FDD, duplex_mode::TDD)); From 552c965460a2df8c9c11739e5660fd96c129d378 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Fri, 19 Jul 2024 19:31:42 +0200 Subject: [PATCH 34/54] sched: fix PUCCH mplexing for 2 bits HARQ + CSI Signed-off-by: Carlo Galiotto --- .../pucch_scheduling/pucch_allocator_impl.cpp | 10 +--- .../pucch_alloc_harq_sr_csi_test.cpp | 51 +++++++++++++++++++ 2 files changed, 52 insertions(+), 9 deletions(-) diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp index f14c37449b..a52a49120b 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp @@ -1400,6 +1400,7 @@ pucch_allocator_impl::multiplex_and_allocate_pucch(cell_slot_resource_allocator& // information bits, the UE determines a PUCCH resource set to be ...". const pucch_uci_bits current_uci_bits = current_grants.pucch_grants.get_uci_bits(); const bool is_multiplexing_needed = + new_bits.sr_bits != sr_nof_bits::no_sr or new_bits.csi_part1_nof_bits != 0U or not((current_uci_bits.harq_ack_nof_bits == 1U and new_bits.harq_ack_nof_bits == 2U) or (current_uci_bits.harq_ack_nof_bits == 3U and new_bits.harq_ack_nof_bits > 3U)); @@ -1573,17 +1574,8 @@ pucch_allocator_impl::update_grants_no_multiplexing(slot_point // Update the grants with the new UCI bits and PUCCH resource configurations (this is to prevent the pointers have // changed since the last allocation). - // NOTE: no need to update the CSI grant, because: (i) if the CSI grant exists, then it doesn't carry the HARQ-ACK - // bits (they are in the HARQ-ACK grangt); (ii) if it doesn't exist, then it's trivial. grants_to_tx.harq_resource.value().bits.harq_ack_nof_bits = harq_grant.bits.harq_ack_nof_bits; grants_to_tx.harq_resource.value().set_res_config(*harq_grant.pucch_res_cfg); - if (ue_current_grants.pucch_grants.sr_resource.has_value()) { - srsran_assert(candidate_grants.sr_resource.has_value(), "PUCCH SR resource must be present"); - grants_to_tx.sr_resource.value().set_res_config(*candidate_grants.sr_resource->pucch_res_cfg); - // For Format 0, if the SR and HARQ resources are separate, the SR resuorce doesn't carry the HARQ-ACK bits. - grants_to_tx.sr_resource.value().bits.harq_ack_nof_bits = - grants_to_tx.sr_resource.value().format == pucch_format::FORMAT_0 ? 0U : harq_grant.bits.harq_ack_nof_bits; - } return grants_to_tx; } diff --git a/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp b/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp index badce03ce5..f972f036fb 100644 --- a/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp +++ b/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp @@ -558,6 +558,57 @@ TEST_F(test_pucch_allocator_ded_resources, test_harq_alloc_3bits_over_sr) })); } +TEST_F(test_pucch_allocator_ded_resources, test_harq_alloc_1bit_over_csi) +{ + // With 1 HARQ-ACK bit, the F1 HARQ-ACK resource overlaps with the F2 resource for CSI, thus the 2 resource will be + // multiplexed into 1, which is the PUCCH HARQ resource from set 1 (Format 2). + pucch_expected_f2.format_2.harq_ack_nof_bits = 1; + pucch_expected_f2.format_2.sr_bits = sr_nof_bits::no_sr; + pucch_expected_f2.format_2.csi_part1_bits = 4; + + add_csi_grant(); + std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + + auto& slot_grid = t_bench.res_grid[t_bench.k0 + t_bench.k1]; + // Expect 1 HARQ and 1 SR. + ASSERT_TRUE(test_pucch_res_indicator.has_value()); + ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator.value()); + ASSERT_EQ(1, slot_grid.result.ul.pucchs.size()); + + const auto& pucch_pdus = slot_grid.result.ul.pucchs; + ASSERT_TRUE(find_pucch_pdu(pucch_pdus, [](const auto& pdu) { return pdu.csi_rep_cfg.has_value(); })); + + ASSERT_TRUE(find_pucch_pdu( + pucch_pdus, [&expected = pucch_expected_f2](const auto& pdu) { return pucch_info_match(expected, pdu); })); +} + +TEST_F(test_pucch_allocator_ded_resources, test_harq_alloc_2bits_over_csi) +{ + // With 2 HARQ-ACK bits, the F1 HARQ-ACK resource overlaps with the F2 resource for CSI, thus the 2 resource will be + // multiplexed into 1, which is the PUCCH HARQ resource from set 1 (Format 2). + pucch_expected_f2.format_2.harq_ack_nof_bits = 2; + pucch_expected_f2.format_2.sr_bits = sr_nof_bits::no_sr; + pucch_expected_f2.format_2.csi_part1_bits = 4; + + add_csi_grant(); + add_harq_grant(); + std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + + auto& slot_grid = t_bench.res_grid[t_bench.k0 + t_bench.k1]; + // Expect 1 HARQ and 1 SR. + ASSERT_TRUE(test_pucch_res_indicator.has_value()); + ASSERT_EQ(pucch_res_idx, test_pucch_res_indicator.value()); + ASSERT_EQ(1, slot_grid.result.ul.pucchs.size()); + + const auto& pucch_pdus = slot_grid.result.ul.pucchs; + ASSERT_TRUE(find_pucch_pdu(pucch_pdus, [](const auto& pdu) { return pdu.csi_rep_cfg.has_value(); })); + + ASSERT_TRUE(find_pucch_pdu( + pucch_pdus, [&expected = pucch_expected_f2](const auto& pdu) { return pucch_info_match(expected, pdu); })); +} + TEST_F(test_pucch_allocator_ded_resources, test_harq_alloc_3bits_over_csi) { // We don't know a-priori whether CSI and HARQ will be multilplexed within the same resource; we need to consider both From 856a5335aecd3485d791be498c5338626c7b9a59 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Thu, 18 Jul 2024 17:28:45 +0200 Subject: [PATCH 35/54] sched: fix multiplexing for harq_bits <= 2 and csi Signed-off-by: Carlo Galiotto --- .../pucch_scheduling/pucch_allocator_impl.cpp | 29 +++++------------ .../pucch_alloc_harq_sr_csi_test.cpp | 31 +++++++++++++++++++ 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp index a52a49120b..dec9ec247d 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp @@ -1811,10 +1811,9 @@ pucch_allocator_impl::merge_pucch_resources(spanformat != pucch_format::FORMAT_0 and r_harq_ptr->format != pucch_format::FORMAT_1) { new_resource = *r_harq_ptr; } else { - pucch_harq_resource_alloc_record res_alloc = - resource_manager.reserve_next_set_1_harq_res_available(slot_harq, crnti, pucch_cfg); + const pucch_resource* pucch_res = resource_manager.reserve_set_1_res_by_res_indicator( + slot_harq, crnti, r_harq_ptr->harq_id.pucch_res_ind, pucch_cfg); resource_manager.set_new_resource_allocation(crnti, pucch_resource_usage::HARQ_SET_1); - if (res_alloc.pucch_res == nullptr) { + if (pucch_res == nullptr) { return std::nullopt; } new_resource.harq_id.pucch_set_idx = pucch_res_set_idx::set_1; - new_resource.harq_id.pucch_res_ind = res_alloc.pucch_res_indicator; - new_resource.set_res_config(*res_alloc.pucch_res); + new_resource.harq_id.pucch_res_ind = r_harq_ptr->harq_id.pucch_res_ind; + new_resource.set_res_config(*pucch_res); } new_resource.bits.harq_ack_nof_bits = r_harq_ptr->bits.harq_ack_nof_bits; new_resource.bits.sr_bits = r_sr_ptr->bits.sr_bits; diff --git a/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp b/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp index f972f036fb..1dd02f8d9e 100644 --- a/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp +++ b/tests/unittests/scheduler/uci_and_pucch/pucch_alloc_harq_sr_csi_test.cpp @@ -718,6 +718,37 @@ TEST_F(test_pucch_allocator_ded_resources, test_harq_alloc_4bits_over_sr_and_csi ASSERT_FALSE(test_pucch_res_indicator.has_value()); } +TEST_F(test_pucch_allocator_ded_resources, when_converting_harq_f1_to_f2_during_mplexing_csi_preserve_res_indicator) +{ + // This makes PUCCH resource indicator 0 busy for PUCCH resource set 0. + add_ue_with_harq_grant(); + add_csi_grant(); + + // At the end of the PUCCH allocation with Format 2, we expect the same PUCCH as for PUCCH format 1. + std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + + ASSERT_TRUE(test_pucch_res_indicator.has_value()); + // PUCCH resource indicator 0 is used by the first UE that got allocated. + ASSERT_EQ(1U, test_pucch_res_indicator.value()); +} + +TEST_F(test_pucch_allocator_ded_resources, when_converting_harq_f1_to_f2_during_mplexing_sr_csi_preserve_res_indicator) +{ + // This makes PUCCH resource indicator 0 busy for PUCCH resource set 0. + add_ue_with_harq_grant(); + add_sr_grant(); + add_csi_grant(); + + // At the end of the PUCCH allocation with Format 2, we expect the same PUCCH as for PUCCH format 1. + std::optional test_pucch_res_indicator = t_bench.pucch_alloc.alloc_ded_pucch_harq_ack_ue( + t_bench.res_grid, t_bench.get_main_ue().crnti, t_bench.get_main_ue().get_pcell().cfg(), t_bench.k0, t_bench.k1); + + ASSERT_TRUE(test_pucch_res_indicator.has_value()); + // PUCCH resource indicator 0 is used by the first UE that got allocated. + ASSERT_EQ(1U, test_pucch_res_indicator.value()); +} + /////// Test allocation of common + dedicated resources. /////// TEST_F(test_pucch_allocator_ded_resources, test_common_plus_ded_resource_without_existing_grants) From 3ca7ce055349659c8247e25b81bcf07f9c786714 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Mon, 22 Jul 2024 11:21:35 +0200 Subject: [PATCH 36/54] sched: rename local variables in pucch allocator Signed-off-by: Carlo Galiotto --- .../pucch_scheduling/pucch_allocator_impl.cpp | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp index dec9ec247d..05f0aa8fbf 100644 --- a/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp +++ b/lib/scheduler/pucch_scheduling/pucch_allocator_impl.cpp @@ -1849,43 +1849,42 @@ pucch_allocator_impl::merge_pucch_resources(spanformat == pucch_format::FORMAT_0) { + srsran_assert(r_harq != nullptr and r_sr != nullptr and r_csi != nullptr, "The three resources must be present"); + if (r_sr->format == pucch_format::FORMAT_0) { srsran_assertion_failure("This case is not yet supported"); // SR and CSI are not supported on the same slot if SR uses Format 0. return std::nullopt; } - if (r_harq_ptr->format != pucch_format::FORMAT_0 and r_harq_ptr->format != pucch_format::FORMAT_1) { - new_resource = *r_harq_ptr; + if (r_harq->format != pucch_format::FORMAT_0 and r_harq->format != pucch_format::FORMAT_1) { + new_resource = *r_harq; } else { const pucch_resource* pucch_res = resource_manager.reserve_set_1_res_by_res_indicator( - slot_harq, crnti, r_harq_ptr->harq_id.pucch_res_ind, pucch_cfg); + slot_harq, crnti, r_harq->harq_id.pucch_res_ind, pucch_cfg); resource_manager.set_new_resource_allocation(crnti, pucch_resource_usage::HARQ_SET_1); if (pucch_res == nullptr) { return std::nullopt; } new_resource.harq_id.pucch_set_idx = pucch_res_set_idx::set_1; - new_resource.harq_id.pucch_res_ind = r_harq_ptr->harq_id.pucch_res_ind; + new_resource.harq_id.pucch_res_ind = r_harq->harq_id.pucch_res_ind; new_resource.set_res_config(*pucch_res); } - new_resource.bits.harq_ack_nof_bits = r_harq_ptr->bits.harq_ack_nof_bits; - new_resource.bits.sr_bits = r_sr_ptr->bits.sr_bits; - new_resource.bits.csi_part1_nof_bits = r_csi_ptr->bits.csi_part1_nof_bits; + new_resource.bits.harq_ack_nof_bits = r_harq->bits.harq_ack_nof_bits; + new_resource.bits.sr_bits = r_sr->bits.sr_bits; + new_resource.bits.csi_part1_nof_bits = r_csi->bits.csi_part1_nof_bits; // Check if the UCI payload fits in the PUCCH resource. if (new_resource.bits.get_total_bits() <= pucch_cfg.get_max_payload(new_resource.format)) { From fd20a529d0279610463f4c31cd17a9231a69e50e Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Wed, 17 Jul 2024 14:40:43 +0200 Subject: [PATCH 37/54] phy: improve pucch sequence generator Reorganize the coefficient table and improve documentation. --- .../pucch/pucch_orthogonal_sequence.h | 66 ++++++++++++++----- 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/lib/phy/upper/signal_processors/pucch/pucch_orthogonal_sequence.h b/lib/phy/upper/signal_processors/pucch/pucch_orthogonal_sequence.h index 5b45a30506..fd07379b35 100644 --- a/lib/phy/upper/signal_processors/pucch/pucch_orthogonal_sequence.h +++ b/lib/phy/upper/signal_processors/pucch/pucch_orthogonal_sequence.h @@ -8,6 +8,9 @@ * */ +/// \file +/// \brief Generation of PUCCH Format 1 orthogonal sequences. + #pragma once #include "srsran/adt/complex.h" @@ -18,46 +21,75 @@ namespace srsran { +/// Generator of orthogonal sequences \e w for PUCCH Format 1. class pucch_orthogonal_sequence { private: + /// Alias for sequence table type. using w_array = std::array, pucch_constants::FORMAT1_N_MAX>, pucch_constants::FORMAT1_N_MAX>; - // TS 38.211 Table 6.3.2.4.1-2: Orthogonal sequences for PUCCH format 1 - const unsigned pucch_format1_rho - [pucch_constants::FORMAT1_N_MAX][pucch_constants::FORMAT1_N_MAX][pucch_constants::FORMAT1_N_MAX] = { - {{0}, {0, 0}, {0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}}, - {{}, {0, 1}, {0, 1, 2}, {0, 2, 0, 2}, {0, 1, 2, 3, 4}, {0, 1, 2, 3, 4, 5}, {0, 1, 2, 3, 4, 5, 6}}, - {{}, {}, {0, 2, 1}, {0, 0, 2, 2}, {0, 2, 4, 1, 3}, {0, 2, 4, 0, 2, 4}, {0, 2, 4, 6, 1, 3, 5}}, - {{}, {}, {}, {0, 2, 2, 0}, {0, 3, 1, 4, 2}, {0, 3, 0, 3, 0, 3}, {0, 3, 6, 2, 5, 1, 4}}, - {{}, {}, {}, {}, {0, 4, 3, 2, 1}, {0, 4, 2, 0, 4, 2}, {0, 4, 1, 5, 2, 6, 3}}, - {{}, {}, {}, {}, {}, {0, 5, 4, 3, 2, 1}, {0, 5, 3, 1, 6, 4, 2}}, - {{}, {}, {}, {}, {}, {}, {0, 6, 5, 4, 3, 2, 1}}}; + /// \brief Coefficients \f$\phi(m)\f$ for sequence generation. + /// + /// See TS38.211 Table 6.3.2.4.1-2: Orthogonal sequences for PUCCH Format 1. + static constexpr std::array< + std::array, pucch_constants::FORMAT1_N_MAX>, + pucch_constants::FORMAT1_N_MAX> + pucch_format1_phi = { + {{{{0}, {}, {}, {}, {}, {}, {}}}, + {{{0, 0}, {0, 1}, {}, {}, {}, {}, {}}}, + {{{0, 0, 0}, {0, 1, 2}, {0, 2, 1}, {}, {}, {}, {}}}, + {{{0, 0, 0, 0}, {0, 2, 0, 2}, {0, 0, 2, 2}, {0, 2, 2, 0}, {}, {}, {}}}, + {{{0, 0, 0, 0, 0}, {0, 1, 2, 3, 4}, {0, 2, 4, 1, 3}, {0, 3, 1, 4, 2}, {0, 4, 3, 2, 1}, {}, {}}}, + {{{0, 0, 0, 0, 0, 0}, + {0, 1, 2, 3, 4, 5}, + {0, 2, 4, 0, 2, 4}, + {0, 3, 0, 3, 0, 3}, + {0, 4, 2, 0, 4, 2}, + {0, 5, 4, 3, 2, 1}, + {}}}, + {{{0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 3, 4, 5, 6}, + {0, 2, 4, 6, 1, 3, 5}, + {0, 3, 6, 2, 5, 1, 4}, + {0, 4, 1, 5, 2, 6, 3}, + {0, 5, 3, 1, 6, 4, 2}, + {0, 6, 5, 4, 3, 2, 1}}}}}; + /// Table with the actual sequences \e w. w_array orthogonal_sequence; public: + /// Constructor: builds the sequences \e w from the coefficients in \ref pucch_format1_phi. pucch_orthogonal_sequence() { - for (unsigned n_pucch = 1, max_n_pucch = pucch_constants::FORMAT1_N_MAX + 1; n_pucch != max_n_pucch; ++n_pucch) { - for (unsigned i = 0; i != pucch_constants::FORMAT1_N_MAX; ++i) { - for (unsigned m = 0; m != pucch_constants::FORMAT1_N_MAX; ++m) { - auto rho = static_cast(pucch_format1_rho[i][n_pucch - 1][m]); - orthogonal_sequence[i][n_pucch - 1][m] = std::polar(1.0F, TWOPI * rho / static_cast(n_pucch)); + for (unsigned n_pucch = 0, max_n_pucch = pucch_constants::FORMAT1_N_MAX; n_pucch != max_n_pucch; ++n_pucch) { + for (unsigned i_seq = 0; i_seq != pucch_constants::FORMAT1_N_MAX; ++i_seq) { + for (unsigned i_term = 0; i_term != pucch_constants::FORMAT1_N_MAX; ++i_term) { + auto rho = static_cast(pucch_format1_phi[n_pucch][i_seq][i_term]); + orthogonal_sequence[n_pucch][i_seq][i_term] = std::polar(1.0F, TWOPI * rho / static_cast(n_pucch + 1)); } } } } + /// \brief Sequence value calculator. + /// + /// \param[in] n_pucch Length of the PUCCH Format 1 sequence + /// \f$N_{\text{SF},m'}^{\text{PUCCH},1} \in \{1, \dots, 7\}\f$. + /// \param[in] i Sequence index \f$i \in \{0, \dots, N_{\text{SF},m'}^{\text{PUCCH},1} - 1\}\f$. + /// \param[in] m Value index inside the sequence + /// \f$m \in \{0, \dots, N_{\text{SF},m'}^{\text{PUCCH},1} - 1\}\f$. + /// \returns The requested value inside the given sequence. + /// \warning An assertion is thrown if the indices do not match the limits above. cf_t get_sequence_value(unsigned n_pucch, unsigned i, unsigned m) const { srsran_assert(n_pucch >= 1 && n_pucch <= pucch_constants::FORMAT1_N_MAX, "Invalid n_pucch"); srsran_assert(i < pucch_constants::FORMAT1_N_MAX, "Invalid i"); srsran_assert(m < pucch_constants::FORMAT1_N_MAX, "Invalid m"); - // Get value - return orthogonal_sequence[i][n_pucch - 1][m]; + + return orthogonal_sequence[n_pucch - 1][i][m]; } }; From 8cbb7af8f5c790b774842003c882e012acad4117 Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Wed, 17 Jul 2024 15:05:10 +0200 Subject: [PATCH 38/54] phy up: move pucch sequence generator to include Since we need the PUCCH sequence generator to be accessible by the PUCCH detector, we move it from "lib/phy/upper/signal_processors" to "include/srsran/phy/upper". Take the opportunity to move the sequence generator outside the dmrs_pucch_processor_format1_impl class, since it could be made static. --- .../srsran/phy/upper}/pucch_orthogonal_sequence.h | 0 .../pucch/dmrs_pucch_processor_format1_impl.cpp | 5 ++++- .../pucch/dmrs_pucch_processor_format1_impl.h | 3 --- 3 files changed, 4 insertions(+), 4 deletions(-) rename {lib/phy/upper/signal_processors/pucch => include/srsran/phy/upper}/pucch_orthogonal_sequence.h (100%) diff --git a/lib/phy/upper/signal_processors/pucch/pucch_orthogonal_sequence.h b/include/srsran/phy/upper/pucch_orthogonal_sequence.h similarity index 100% rename from lib/phy/upper/signal_processors/pucch/pucch_orthogonal_sequence.h rename to include/srsran/phy/upper/pucch_orthogonal_sequence.h diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.cpp b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.cpp index 39ba731f5a..26fedd538b 100644 --- a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.cpp +++ b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.cpp @@ -10,11 +10,14 @@ #include "dmrs_pucch_processor_format1_impl.h" #include "srsran/phy/upper/pucch_helper.h" -#include "srsran/srsvec/add.h" +#include "srsran/phy/upper/pucch_orthogonal_sequence.h" #include "srsran/srsvec/sc_prod.h" using namespace srsran; +// Pre-generated orthogonal cover code. +static const pucch_orthogonal_sequence occ; + // DM-RS symbol allocation pattern for PUCCH Format 1, as defined in TS38.211 Section 6.4.1.3.1.2. static const bounded_bitset pucch_format1_dmrs_symb_mask = {true, false, true, false, true, false, true, false, true, false, true, false, true, false}; diff --git a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.h b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.h index 9bdaab4ba1..dd1fe35d31 100644 --- a/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.h +++ b/lib/phy/upper/signal_processors/pucch/dmrs_pucch_processor_format1_impl.h @@ -10,7 +10,6 @@ #pragma once -#include "pucch_orthogonal_sequence.h" #include "srsran/phy/upper/pucch_helper.h" #include "srsran/phy/upper/sequence_generators/low_papr_sequence_collection.h" #include "srsran/phy/upper/signal_processors/dmrs_pucch_processor.h" @@ -46,8 +45,6 @@ class dmrs_pucch_processor_format1_impl : public dmrs_pucch_processor /// Buffer for DM-RS symbols. dmrs_symbol_list temp_symbols; - /// Pre-generated orthogonal cover code. - const pucch_orthogonal_sequence occ; /// Holds DM-RS sequence generation parameters used in TS38.211 Section 6.4.1.3.1.1. struct sequence_generation_config { From 9e4e9ac8e1b0a529e97ac397575234c18e67ea9b Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Wed, 17 Jul 2024 16:26:12 +0200 Subject: [PATCH 39/54] phy, pucch: remove duplicated functions --- .../phy/upper/pucch_orthogonal_sequence.h | 31 +++- .../pucch_detector_impl.cpp | 144 ++---------------- .../channel_processors/pucch_detector_impl.h | 3 - 3 files changed, 41 insertions(+), 137 deletions(-) diff --git a/include/srsran/phy/upper/pucch_orthogonal_sequence.h b/include/srsran/phy/upper/pucch_orthogonal_sequence.h index fd07379b35..8916635dfe 100644 --- a/include/srsran/phy/upper/pucch_orthogonal_sequence.h +++ b/include/srsran/phy/upper/pucch_orthogonal_sequence.h @@ -14,6 +14,7 @@ #pragma once #include "srsran/adt/complex.h" +#include "srsran/adt/span.h" #include "srsran/ran/pucch/pucch_constants.h" #include "srsran/support/math_utils.h" #include "srsran/support/srsran_assert.h" @@ -59,6 +60,8 @@ class pucch_orthogonal_sequence /// Table with the actual sequences \e w. w_array orthogonal_sequence; + /// Table with the conjugated sequences \e w. + w_array orthogonal_sequence_conj; public: /// Constructor: builds the sequences \e w from the coefficients in \ref pucch_format1_phi. @@ -69,6 +72,7 @@ class pucch_orthogonal_sequence for (unsigned i_term = 0; i_term != pucch_constants::FORMAT1_N_MAX; ++i_term) { auto rho = static_cast(pucch_format1_phi[n_pucch][i_seq][i_term]); orthogonal_sequence[n_pucch][i_seq][i_term] = std::polar(1.0F, TWOPI * rho / static_cast(n_pucch + 1)); + orthogonal_sequence_conj[n_pucch][i_seq][i_term] = std::conj(orthogonal_sequence[n_pucch][i_seq][i_term]); } } } @@ -85,12 +89,33 @@ class pucch_orthogonal_sequence /// \warning An assertion is thrown if the indices do not match the limits above. cf_t get_sequence_value(unsigned n_pucch, unsigned i, unsigned m) const { - srsran_assert(n_pucch >= 1 && n_pucch <= pucch_constants::FORMAT1_N_MAX, "Invalid n_pucch"); - srsran_assert(i < pucch_constants::FORMAT1_N_MAX, "Invalid i"); - srsran_assert(m < pucch_constants::FORMAT1_N_MAX, "Invalid m"); + srsran_assert(n_pucch >= 1 && n_pucch <= pucch_constants::FORMAT1_N_MAX, + "Invalid n_pucch {}: valid values from 1 to {}.", + n_pucch, + pucch_constants::FORMAT1_N_MAX); + srsran_assert(i < n_pucch, "Invalid sequence index i = {}, valid values from 0 to {}.", i, n_pucch - 1); + srsran_assert(m < n_pucch, "Invalid value index m = {}, valid values from 0 to {}.", m, n_pucch - 1); return orthogonal_sequence[n_pucch - 1][i][m]; } + + /// \brief Gets an entire PUCCH Format 1 conjugated orthogonal sequence. + /// + /// \param[in] n_pucch Length of the PUCCH Format 1 sequence + /// \f$N_{\text{SF},m'}^{\text{PUCCH},1} \in \{1, \dots, 7\}\f$. + /// \param[in] i Sequence index \f$i \in \{0, \dots, N_{\text{SF},m'}^{\text{PUCCH},1} - 1\}\f$. + /// \returns The requested conjugated sequence. + /// \warning An assertion is thrown if the inputs do not match the limits above. + span get_sequence_conj(unsigned n_pucch, unsigned i) const + { + srsran_assert(n_pucch >= 1 && n_pucch <= pucch_constants::FORMAT1_N_MAX, + "Invalid n_pucch {}: valid values from 1 to {}.", + n_pucch, + pucch_constants::FORMAT1_N_MAX); + srsran_assert(i < n_pucch, "Invalid sequence index i = {}, valid values from 0 to {}.", i, n_pucch - 1); + + return span(orthogonal_sequence_conj[n_pucch - 1][i]).first(n_pucch); + } }; } // namespace srsran diff --git a/lib/phy/upper/channel_processors/pucch_detector_impl.cpp b/lib/phy/upper/channel_processors/pucch_detector_impl.cpp index 399f881b64..4d7724790a 100644 --- a/lib/phy/upper/channel_processors/pucch_detector_impl.cpp +++ b/lib/phy/upper/channel_processors/pucch_detector_impl.cpp @@ -13,134 +13,14 @@ #include "pucch_detector_impl.h" #include "srsran/phy/support/resource_grid_reader.h" -#include "srsran/srsvec/conversion.h" +#include "srsran/phy/upper/pucch_orthogonal_sequence.h" #include "srsran/srsvec/copy.h" #include "srsran/srsvec/mean.h" using namespace srsran; -namespace { -// Container for time-domain spreading sequences of length N. -template -struct time_spreading_sequences { - using type = cf_t; - explicit time_spreading_sequences(const std::array, N>& seed) - { - for (unsigned i_seq = 0; i_seq != N; ++i_seq) { - for (unsigned i_term = 0; i_term != N; ++i_term) { - sequences[i_seq][i_term] = std::polar(1.0F, -TWOPI * seed[i_seq][i_term] / static_cast(N)); - } - } - }; - - std::array, N> sequences; -}; - -template -span get_w_star(unsigned length, unsigned i); - -// Build and provide access to the time-domain spreading sequences of length 1. -template <> -span get_w_star<1>(unsigned /*length*/, unsigned i) -{ - static constexpr std::array w = {{{1.0F, 0.0F}}}; - srsran_assert(i == 0, "Invalid sequence index {} for sequences of length {}.", i, 1); - return {w}; -} - -// Build and provide access to the time-domain spreading sequences of length 2. -template <> -span get_w_star<2>(unsigned length, unsigned i) -{ - static constexpr unsigned N = 2; - static const time_spreading_sequences w({{{0, 0}, {0, 1}}}); - if (length != N) { - return get_w_star(length, i); - } - srsran_assert(i < N, "Invalid sequence index {} for sequences of length {}.", i, N); - return {w.sequences[i]}; -} - -// Build and provide access to the time-domain spreading sequences of length 3. -template <> -span get_w_star<3>(unsigned length, unsigned i) -{ - static constexpr unsigned N = 3; - static const time_spreading_sequences w({{{0, 0, 0}, {0, 1, 2}, {0, 2, 1}}}); - if (length != N) { - return get_w_star(length, i); - } - srsran_assert(i < N, "Invalid sequence index {} for sequences of length {}.", i, N); - return {w.sequences[i]}; -} - -// Build and provide access to the time-domain spreading sequences of length 4. -template <> -span get_w_star<4>(unsigned length, unsigned i) -{ - static constexpr unsigned N = 4; - static const time_spreading_sequences w({{{0, 0, 0, 0}, {0, 2, 0, 2}, {0, 0, 2, 2}, {0, 2, 2, 0}}}); - if (length != N) { - return get_w_star(length, i); - } - srsran_assert(i < N, "Invalid sequence index {} for sequences of length {}.", i, N); - return {w.sequences[i]}; -} - -// Build and provide access to the time-domain spreading sequences of length 5. -template <> -span get_w_star<5>(unsigned length, unsigned i) -{ - static constexpr unsigned N = 5; - static const time_spreading_sequences w( - {{{0, 0, 0, 0, 0}, {0, 1, 2, 3, 4}, {0, 2, 4, 1, 3}, {0, 3, 1, 4, 2}, {0, 4, 3, 2, 1}}}); - if (length != N) { - return get_w_star(length, i); - } - srsran_assert(i < N, "Invalid sequence index {} for sequences of length {}.", i, N); - return {w.sequences[i]}; -} - -// Build and provide access to the time-domain spreading sequences of length 6. -template <> -span get_w_star<6>(unsigned length, unsigned i) -{ - static constexpr unsigned N = 6; - static const time_spreading_sequences w({{{0, 0, 0, 0, 0, 0}, - {0, 1, 2, 3, 4, 5}, - {0, 2, 4, 0, 2, 4}, - {0, 3, 0, 3, 0, 3}, - {0, 4, 2, 0, 4, 2}, - {0, 5, 4, 3, 2, 1}}}); - if (length != N) { - return get_w_star(length, i); - } - srsran_assert(i < N, "Invalid sequence index {} for sequences of length {}.", i, N); - return {w.sequences[i]}; -} - -// Build and provide access to the time-domain spreading sequences of length 7. -template <> -span get_w_star<7>(unsigned length, unsigned i) -{ - static constexpr unsigned N = 7; - static const time_spreading_sequences w({{{0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 3, 4, 5, 6}, - {0, 2, 4, 6, 1, 3, 5}, - {0, 3, 6, 2, 5, 1, 4}, - {0, 4, 1, 5, 2, 6, 3}, - {0, 5, 3, 1, 6, 4, 2}, - {0, 6, 5, 4, 3, 2, 1}}}); - if (length == 0) { - return {}; - } - if (length != N) { - return get_w_star(length, i); - } - srsran_assert(i < N, "Invalid sequence index {} for sequences of length {}.", i, N); - return {w.sequences[i]}; -} -} // namespace +// Pre-generated orthogonal cover code. +static const pucch_orthogonal_sequence occ; static void validate_config(const pucch_detector::format1_configuration& config) { @@ -365,7 +245,7 @@ void pucch_detector_impl::marginalize_w_and_r_out(const format1_configuration& c unsigned group_index = config.n_id % 30; unsigned sequence_number = 0; - span w_star = get_w_star(nof_data_symbols_pre_hop, time_domain_occ); + span w_star = occ.get_sequence_conj(nof_data_symbols_pre_hop, time_domain_occ); compute_alpha_indices(alpha_indices, config.start_symbol_index, @@ -386,13 +266,15 @@ void pucch_detector_impl::marginalize_w_and_r_out(const format1_configuration& c } unsigned nof_data_symbols_post_hop = nof_data_symbols - nof_data_symbols_pre_hop; - w_star = get_w_star(nof_data_symbols_post_hop, time_domain_occ); - - for (unsigned i_symbol = 0; i_symbol != nof_data_symbols_post_hop; ++i_symbol, offset += NRE) { - span seq_r = - low_papr->get(group_index, sequence_number, alpha_indices[i_symbol + nof_data_symbols_pre_hop]); - for (unsigned i_elem = 0; i_elem != NRE; ++i_elem) { - detected_symbol += eq_time_spread_sequence[offset + i_elem] * w_star[i_symbol] * std::conj(seq_r[i_elem]); + if (nof_data_symbols_post_hop > 0) { + w_star = occ.get_sequence_conj(nof_data_symbols_post_hop, time_domain_occ); + + for (unsigned i_symbol = 0; i_symbol != nof_data_symbols_post_hop; ++i_symbol, offset += NRE) { + span seq_r = + low_papr->get(group_index, sequence_number, alpha_indices[i_symbol + nof_data_symbols_pre_hop]); + for (unsigned i_elem = 0; i_elem != NRE; ++i_elem) { + detected_symbol += eq_time_spread_sequence[offset + i_elem] * w_star[i_symbol] * std::conj(seq_r[i_elem]); + } } } diff --git a/lib/phy/upper/channel_processors/pucch_detector_impl.h b/lib/phy/upper/channel_processors/pucch_detector_impl.h index 765b6cc2ef..ac5fc7860c 100644 --- a/lib/phy/upper/channel_processors/pucch_detector_impl.h +++ b/lib/phy/upper/channel_processors/pucch_detector_impl.h @@ -34,9 +34,6 @@ class pucch_detector_impl : public pucch_detector /// The allocated resources are at most one PRB over all OFDM symbols. static constexpr unsigned MAX_ALLOCATED_RE_F1 = NRE * MAX_NSYMB_PER_SLOT; - /// Maximum number of OFDM symbols allocated for PUCCH Format 1 data. - static constexpr unsigned MAX_N_DATA_SYMBOLS = 7; - /// \brief Constructor: provides access to a collection of low-PAPR sequences and a pseudorandom sequence generator. /// \param[in] low_papr_ Collection of low-PAPR sequences. /// \param[in] pseudo_random_ Pseudo-random sequence generator. From 2dd7440ad3a6cf5cb466535718732e5a84fe2d99 Mon Sep 17 00:00:00 2001 From: dvdgrgrtt Date: Wed, 17 Jul 2024 17:37:13 +0200 Subject: [PATCH 40/54] phy: refactor pucch_detector_impl pucch_detector_impl used to implement Format 1 directly, while Format 0 was injected. Now, Format 1 is also implemented externally and injected into pucch_detector_impl. --- .../upper/channel_processors/pucch_detector.h | 1 - .../upper/channel_processors/CMakeLists.txt | 2 +- .../channel_processor_factories.cpp | 8 +- .../pucch_detector_format0.h | 7 +- ...or_impl.cpp => pucch_detector_format1.cpp} | 43 +++---- .../pucch_detector_format1.h | 114 ++++++++++++++++++ .../channel_processors/pucch_detector_impl.h | 100 +++------------ 7 files changed, 160 insertions(+), 115 deletions(-) rename lib/phy/upper/channel_processors/{pucch_detector_impl.cpp => pucch_detector_format1.cpp} (87%) create mode 100644 lib/phy/upper/channel_processors/pucch_detector_format1.h diff --git a/include/srsran/phy/upper/channel_processors/pucch_detector.h b/include/srsran/phy/upper/channel_processors/pucch_detector.h index 001f163de6..fbd4d6bf07 100644 --- a/include/srsran/phy/upper/channel_processors/pucch_detector.h +++ b/include/srsran/phy/upper/channel_processors/pucch_detector.h @@ -13,7 +13,6 @@ #pragma once -#include "srsran/adt/optional.h" #include "srsran/phy/upper/channel_estimation.h" #include "srsran/phy/upper/channel_processors/pucch_uci_message.h" #include "srsran/ran/pucch/pucch_mapping.h" diff --git a/lib/phy/upper/channel_processors/CMakeLists.txt b/lib/phy/upper/channel_processors/CMakeLists.txt index 019a207a22..f7fe45adc6 100644 --- a/lib/phy/upper/channel_processors/CMakeLists.txt +++ b/lib/phy/upper/channel_processors/CMakeLists.txt @@ -50,7 +50,7 @@ add_library(srsran_pucch_processor STATIC pucch_processor_impl.cpp) add_library(srsran_pucch_detector STATIC pucch_detector_format0.cpp - pucch_detector_impl.cpp) + pucch_detector_format1.cpp) add_library(srsran_ssb_processor STATIC ssb_processor_impl.cpp) target_link_libraries(srsran_ssb_processor srsran_sequence_generators srsran_signal_processors) diff --git a/lib/phy/upper/channel_processors/channel_processor_factories.cpp b/lib/phy/upper/channel_processors/channel_processor_factories.cpp index 49b82f48a6..edf90d83b2 100644 --- a/lib/phy/upper/channel_processors/channel_processor_factories.cpp +++ b/lib/phy/upper/channel_processors/channel_processor_factories.cpp @@ -656,10 +656,10 @@ class pucch_detector_factory_sw : public pucch_detector_factory std::unique_ptr detector_format0 = std::make_unique(prg_factory->create(), low_papr_factory->create(1, 0, alphas)); - return std::make_unique(low_papr_factory->create(1, 0, alphas), - prg_factory->create(), - eqzr_factory->create(), - std::move(detector_format0)); + std::unique_ptr detector_format1 = std::make_unique( + low_papr_factory->create(1, 0, alphas), prg_factory->create(), eqzr_factory->create()); + + return std::make_unique(std::move(detector_format0), std::move(detector_format1)); } }; diff --git a/lib/phy/upper/channel_processors/pucch_detector_format0.h b/lib/phy/upper/channel_processors/pucch_detector_format0.h index 80c687079f..bd20df0db9 100644 --- a/lib/phy/upper/channel_processors/pucch_detector_format0.h +++ b/lib/phy/upper/channel_processors/pucch_detector_format0.h @@ -8,6 +8,9 @@ * */ +/// \file +/// PUCCH Format 0 detector declaration. + #pragma once #include "srsran/phy/upper/channel_processors/pucch_detector.h" @@ -17,7 +20,7 @@ namespace srsran { -/// Implements a PUCCH Format 0 detector. +/// PUCCH Format 0 detector. class pucch_detector_format0 { public: @@ -29,7 +32,7 @@ class pucch_detector_format0 srsran_assert(low_papr, ""); } - /// Detects PUCCH Format0 transmission. See \ref pucch_detector for more details. + /// Detects a PUCCH Format 0 transmission. See \ref pucch_detector for more details. std::pair detect(const resource_grid_reader& grid, const pucch_detector::format0_configuration& config); diff --git a/lib/phy/upper/channel_processors/pucch_detector_impl.cpp b/lib/phy/upper/channel_processors/pucch_detector_format1.cpp similarity index 87% rename from lib/phy/upper/channel_processors/pucch_detector_impl.cpp rename to lib/phy/upper/channel_processors/pucch_detector_format1.cpp index 4d7724790a..de35bff6f7 100644 --- a/lib/phy/upper/channel_processors/pucch_detector_impl.cpp +++ b/lib/phy/upper/channel_processors/pucch_detector_format1.cpp @@ -9,10 +9,11 @@ */ /// \file -/// \brief PUCCH detector definition for Formats 0 and 1. +/// \brief PUCCH detector definition for Format 1. -#include "pucch_detector_impl.h" +#include "pucch_detector_format1.h" #include "srsran/phy/support/resource_grid_reader.h" +#include "srsran/phy/upper/channel_processors/pucch_detector.h" #include "srsran/phy/upper/pucch_orthogonal_sequence.h" #include "srsran/srsvec/copy.h" #include "srsran/srsvec/mean.h" @@ -76,16 +77,10 @@ static float detect_bits(span out_bits, cf_t detected_symbol, float eq_ return (std::norm(detected_symbol) / eq_noise_var); } -std::pair -pucch_detector_impl::detect(const srsran::resource_grid_reader& grid, - const srsran::pucch_detector::format0_configuration& config) -{ - return detector_format0->detect(grid, config); -} - -pucch_detector::pucch_detection_result pucch_detector_impl::detect(const resource_grid_reader& grid, - const channel_estimate& estimates, - const format1_configuration& config) +pucch_detector::pucch_detection_result +pucch_detector_format1::detect(const resource_grid_reader& grid, + const channel_estimate& estimates, + const pucch_detector::format1_configuration& config) { validate_config(config); @@ -127,11 +122,11 @@ pucch_detector::pucch_detection_result pucch_detector_impl::detect(const resourc // by this detector and on the used PUCCH resource. // This format doesn't support CSI reports. pucch_uci_message::configuration pucch_uci_message_config; - pucch_uci_message_config.nof_sr = 0; - pucch_uci_message_config.nof_harq_ack = config.nof_harq_ack; - pucch_uci_message_config.nof_csi_part1 = 0; - pucch_uci_message_config.nof_csi_part2 = 0; - pucch_detection_result output = {pucch_uci_message(pucch_uci_message_config), 0}; + pucch_uci_message_config.nof_sr = 0; + pucch_uci_message_config.nof_harq_ack = config.nof_harq_ack; + pucch_uci_message_config.nof_csi_part1 = 0; + pucch_uci_message_config.nof_csi_part2 = 0; + pucch_detector::pucch_detection_result output = {pucch_uci_message(pucch_uci_message_config), 0}; // Select view of the payload. span bits = output.uci_message.get_harq_ack_bits(); @@ -176,12 +171,12 @@ pucch_detector::pucch_detection_result pucch_detector_impl::detect(const resourc return output; } -void pucch_detector_impl::extract_data_and_estimates(const resource_grid_reader& grid, - const channel_estimate& estimates, - unsigned first_symbol, - unsigned first_prb, - std::optional second_prb, - const static_vector& antenna_ports) +void pucch_detector_format1::extract_data_and_estimates(const resource_grid_reader& grid, + const channel_estimate& estimates, + unsigned first_symbol, + unsigned first_prb, + std::optional second_prb, + const static_vector& antenna_ports) { for (uint8_t port : antenna_ports) { unsigned i_symbol = 0; @@ -235,7 +230,7 @@ static void compute_alpha_indices(span indices, } } -void pucch_detector_impl::marginalize_w_and_r_out(const format1_configuration& config) +void pucch_detector_format1::marginalize_w_and_r_out(const pucch_detector::format1_configuration& config) { unsigned time_domain_occ = config.time_domain_occ; diff --git a/lib/phy/upper/channel_processors/pucch_detector_format1.h b/lib/phy/upper/channel_processors/pucch_detector_format1.h new file mode 100644 index 0000000000..10d0e3958c --- /dev/null +++ b/lib/phy/upper/channel_processors/pucch_detector_format1.h @@ -0,0 +1,114 @@ +/* + * + * 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. + * + */ + +/// \file +/// PUCCH Format 1 detector declaration. + +#pragma once + +#include "srsran/phy/support/re_buffer.h" +#include "srsran/phy/support/resource_grid_reader.h" +#include "srsran/phy/upper/channel_processors/pucch_detector.h" +#include "srsran/phy/upper/equalization/channel_equalizer.h" +#include "srsran/phy/upper/equalization/dynamic_ch_est_list.h" +#include "srsran/phy/upper/pucch_helper.h" +#include "srsran/phy/upper/sequence_generators/low_papr_sequence_collection.h" +#include "srsran/phy/upper/sequence_generators/pseudo_random_generator.h" + +namespace srsran { + +/// PUCCH Format 1 detector. +class pucch_detector_format1 +{ +public: + /// \brief Maximum number of REs allocated to PUCCH Format 1. + /// + /// The allocated resources are at most one PRB over all OFDM symbols. + static constexpr unsigned MAX_ALLOCATED_RE_F1 = NRE * MAX_NSYMB_PER_SLOT; + + /// \brief Constructor: provides access to a collection of low-PAPR sequences and a pseudorandom sequence generator. + /// \param[in] low_papr_ Collection of low-PAPR sequences. + /// \param[in] pseudo_random_ Pseudo-random sequence generator. + /// \param[in] equalizer_ Channel equalizer. + /// \remark The low-PAPR collection should correspond to the cyclic shifts \f$\{\alpha : \alpha = 2 \pi + /// \frac{n}{N_{\textup{sc}}^{\textup{RB}}}, \quad n = 0, \dots, N_{\textup{sc}}^{\textup{RB}}-1\}\f$, where + /// \f$N_{\textup{sc}}^{\textup{RB}} = 12\f$ is the number of subcarriers in a resource block. + pucch_detector_format1(std::unique_ptr low_papr_, + std::unique_ptr pseudo_random_, + std::unique_ptr equalizer_) : + low_papr(std::move(low_papr_)), + helper(std::move(pseudo_random_)), + equalizer(std::move(equalizer_)), + ch_estimates(MAX_ALLOCATED_RE_F1, MAX_PORTS / 2, 1) + { + srsran_assert(low_papr, "Invalid Low PAPR sequence generator."); + srsran_assert(equalizer, "Invalid equalizer."); + } + + /// Detects a PUCCH Format 1 transmission. See \ref pucch_detector for more details. + pucch_detector::pucch_detection_result detect(const resource_grid_reader& grid, + const channel_estimate& estimates, + const pucch_detector::format1_configuration& config); + +private: + /// \brief Extracts PUCCH data and channel coefficients. + /// + /// This method extracts the PUCCH data REs from the resource grid as well as the corresponding channel estimates. + void extract_data_and_estimates(const resource_grid_reader& grid, + const channel_estimate& estimates, + unsigned first_symbol, + unsigned first_prb, + std::optional second_prb, + const static_vector& antenna_ports); + + /// \brief Marginalizes the spreading sequences out. + /// + /// A PUCCH Format 1 consists of a single modulation symbol spread over all time and frequency allocated + /// resources. This method combines all the replicas into a single estimate of the modulation symbol and it + /// computes the equivalent noise variance. The PUCCH configuration is needed to build the proper spreading + /// sequences. + void marginalize_w_and_r_out(const pucch_detector::format1_configuration& config); + + /// Collection of low-PAPR sequences. + std::unique_ptr low_papr; + /// Pseudorandom sequence generator. + pucch_helper helper; + /// Channel equalizer. + std::unique_ptr equalizer; + /// \brief Buffer for storing the spread data sequence. + /// \remark Only half of the allocated symbols contain data, the other half being used for DM-RS. + static_re_buffer time_spread_sequence; + /// \brief Tensor for storing the channel estimates corresponding to the spread data sequence. + /// \remark Only half of the allocated symbols contain data, the other half being used for DM-RS. + dynamic_ch_est_list ch_estimates; + /// \brief Buffer for storing the spread data sequence after equalization. + /// \remark Only half of the allocated symbols contain data, the other half being used for DM-RS. + static_vector eq_time_spread_sequence; + /// \brief Buffer for storing the equivalent channel noise variances corresponding to the equalized spread data + /// sequence. + /// \remark Only half of the allocated symbols contain data, the other half being used for DM-RS. + static_vector eq_time_spread_noise_var; + /// Buffer for storing alpha indices. + std::array alpha_buffer; + /// Buffer for noise variances. + std::array noise_var_buffer; + /// View of the alpha indices buffer. + span alpha_indices; + /// Detected symbol. + cf_t detected_symbol = 0; + /// Equivalent noise variance of detected symbol. + float eq_noise_var = 0; + /// Total number of data symbols. + unsigned nof_data_symbols = 0; + /// Number of data symbols before frequency hopping. + unsigned nof_data_symbols_pre_hop = 0; +}; + +} // namespace srsran diff --git a/lib/phy/upper/channel_processors/pucch_detector_impl.h b/lib/phy/upper/channel_processors/pucch_detector_impl.h index ac5fc7860c..5768e6d080 100644 --- a/lib/phy/upper/channel_processors/pucch_detector_impl.h +++ b/lib/phy/upper/channel_processors/pucch_detector_impl.h @@ -14,14 +14,8 @@ #pragma once #include "pucch_detector_format0.h" -#include "srsran/phy/support/re_buffer.h" -#include "srsran/phy/support/resource_grid_reader.h" +#include "pucch_detector_format1.h" #include "srsran/phy/upper/channel_processors/pucch_detector.h" -#include "srsran/phy/upper/equalization/channel_equalizer.h" -#include "srsran/phy/upper/equalization/dynamic_ch_est_list.h" -#include "srsran/phy/upper/pucch_helper.h" -#include "srsran/phy/upper/sequence_generators/low_papr_sequence_collection.h" -#include "srsran/phy/upper/sequence_generators/pseudo_random_generator.h" namespace srsran { @@ -29,97 +23,37 @@ namespace srsran { class pucch_detector_impl : public pucch_detector { public: - /// \brief Maximum number of REs allocated to PUCCH Format 1. - /// - /// The allocated resources are at most one PRB over all OFDM symbols. - static constexpr unsigned MAX_ALLOCATED_RE_F1 = NRE * MAX_NSYMB_PER_SLOT; - - /// \brief Constructor: provides access to a collection of low-PAPR sequences and a pseudorandom sequence generator. - /// \param[in] low_papr_ Collection of low-PAPR sequences. - /// \param[in] pseudo_random_ Pseudo-random sequence generator. - /// \param[in] equalizer_ Channel equalizer. + /// \brief Constructor: provides access to the actual Format 0 and Format 1 detectors. /// \param[in] detector_format0_ PUCCH Format 0 detector. - /// \remark The low-PAPR collection should correspond to the cyclic shifts \f$\{\alpha : \alpha = 2 \pi - /// \frac{n}{N_{\textup{sc}}^{\textup{RB}}}, \quad n = 0, \dots, N_{\textup{sc}}^{\textup{RB}}-1\}\f$, where - /// \f$N_{\textup{sc}}^{\textup{RB}} = 12\f$ is the number of subcarriers in a resource block. - pucch_detector_impl(std::unique_ptr low_papr_, - std::unique_ptr pseudo_random_, - std::unique_ptr equalizer_, - std::unique_ptr detector_format0_) : - low_papr(std::move(low_papr_)), - helper(std::move(pseudo_random_)), - equalizer(std::move(equalizer_)), - detector_format0(std::move(detector_format0_)), - ch_estimates(MAX_ALLOCATED_RE_F1, MAX_PORTS / 2, 1) + /// \param[in] detector_format1_ PUCCH Format 1 detector. + pucch_detector_impl(std::unique_ptr detector_format0_, + std::unique_ptr detector_format1_) : + detector_format0(std::move(detector_format0_)), detector_format1(std::move(detector_format1_)) { - srsran_assert(low_papr, "Invalid Low PAPR sequence generator."); - srsran_assert(equalizer, "Invalid equalizer."); srsran_assert(detector_format0, "PUCCH Format 0 detector."); + srsran_assert(detector_format1, "PUCCH Format 1 detector."); } // See interface for documentation. std::pair detect(const resource_grid_reader& grid, - const format0_configuration& config) override; + const format0_configuration& config) override + { + return detector_format0->detect(grid, config); + } // See interface for documentation. pucch_detection_result detect(const resource_grid_reader& grid, const channel_estimate& estimates, - const format1_configuration& config) override; + const format1_configuration& config) override + { + return detector_format1->detect(grid, estimates, config); + } private: - /// \brief Extracts PUCCH data and channel coefficients. - /// - /// This method extracts the PUCCH data REs from the resource grid as well as the corresponding channel estimates. - void extract_data_and_estimates(const resource_grid_reader& grid, - const channel_estimate& estimates, - unsigned first_symbol, - unsigned first_prb, - std::optional second_prb, - const static_vector& antenna_ports); - - /// \brief Marginalizes the spreading sequences out. - /// - /// A PUCCH Format 1 consists of a single modulation symbol spread over all time and frequency allocated - /// resources. This method combines all the replicas into a single estimate of the modulation symbol and it - /// computes the equivalent noise variance. The PUCCH configuration is needed to build the proper spreading - /// sequences. - void marginalize_w_and_r_out(const format1_configuration& config); - - /// Collection of low-PAPR sequences. - std::unique_ptr low_papr; - /// Pseudorandom sequence generator. - pucch_helper helper; - /// Channel equalizer. - std::unique_ptr equalizer; /// PUCCH Format 0 detector. std::unique_ptr detector_format0; - /// \brief Buffer for storing the spread data sequence. - /// \remark Only half of the allocated symbols contain data, the other half being used for DM-RS. - static_re_buffer time_spread_sequence; - /// \brief Tensor for storing the channel estimates corresponding to the spread data sequence. - /// \remark Only half of the allocated symbols contain data, the other half being used for DM-RS. - dynamic_ch_est_list ch_estimates; - /// \brief Buffer for storing the spread data sequence after equalization. - /// \remark Only half of the allocated symbols contain data, the other half being used for DM-RS. - static_vector eq_time_spread_sequence; - /// \brief Buffer for storing the equivalent channel noise variances corresponding to the equalized spread data - /// sequence. - /// \remark Only half of the allocated symbols contain data, the other half being used for DM-RS. - static_vector eq_time_spread_noise_var; - /// Buffer for storing alpha indices. - std::array alpha_buffer; - /// Buffer for noise variances. - std::array noise_var_buffer; - /// View of the alpha indices buffer. - span alpha_indices; - /// Detected symbol. - cf_t detected_symbol = 0; - /// Equivalent noise variance of detected symbol. - float eq_noise_var = 0; - /// Total number of data symbols. - unsigned nof_data_symbols = 0; - /// Number of data symbols before frequency hopping. - unsigned nof_data_symbols_pre_hop = 0; + /// PUCCH Format 1 detector. + std::unique_ptr detector_format1; }; } // namespace srsran From e1e9c2cb3078bc9263ee5ac53f3c1692cb221dcb Mon Sep 17 00:00:00 2001 From: asaezper Date: Mon, 22 Jul 2024 10:15:46 +0200 Subject: [PATCH 41/54] ci,actions: fix image names --- .github/workflows/docker.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 41f0a98042..b321c117e1 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -21,8 +21,8 @@ jobs: PLATFORM: amd64 LIB: "" LIB_VERSION: "" - DOCKERFILE: ./docker/grafana/Dockerfile - CONTEXT: ./docker/grafana + DOCKERFILE: ./docker/metrics_server/Dockerfile + CONTEXT: ./docker/metrics_server # --> grafana - TAGNAME: "" REPOSITORY: grafana @@ -31,8 +31,8 @@ jobs: PLATFORM: amd64 LIB: "" LIB_VERSION: "" - DOCKERFILE: ./docker/metrics_server/Dockerfile - CONTEXT: ./docker/metrics_server + DOCKERFILE: ./docker/grafana/Dockerfile + CONTEXT: ./docker/grafana # --> split72 # AMD AVX2 - TAGNAME: split72_release_avx2 From 0d2cec8fc248acb69cf87952984dc4c788877c8a Mon Sep 17 00:00:00 2001 From: asaezper Date: Mon, 22 Jul 2024 10:07:18 +0200 Subject: [PATCH 42/54] ci,e2e: change viavi tests criteria --- .gitlab/ci/e2e.yml | 2 ++ tests/e2e/tests/viavi/test_declaration.yml | 14 +++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 0e72ea1d95..d0e3f0552a 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -605,6 +605,7 @@ viavi: - job: "basic avx512 dpdk" artifacts: true - *retina-needs + allow_failure: true parallel: matrix: - KEYWORDS: [ @@ -628,6 +629,7 @@ viavi-debug: KUBECONFIG_VAR_NAME: "RETINA_NAMESPACE_KUBECONFIG" RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.rlc_enable=True gnb.all.rlc_rb_type=srb" RETINA_LAUNCHER_ARGS: "--retina-pod-timeout 900" + allow_failure: true needs: - job: "basic avx512 dpdk withassert" artifacts: true diff --git a/tests/e2e/tests/viavi/test_declaration.yml b/tests/e2e/tests/viavi/test_declaration.yml index 111217b473..c9305c37db 100644 --- a/tests/e2e/tests/viavi/test_declaration.yml +++ b/tests/e2e/tests/viavi/test_declaration.yml @@ -39,7 +39,7 @@ tests: # test/fail criteria expected_dl_bitrate: *expected_dl_bitrate_high expected_ul_bitrate: *expected_ul_bitrate_high - fail_if_kos: true + fail_if_kos: false warning_as_errors: true - campaign_filename: *campaign_filename @@ -53,7 +53,7 @@ tests: # test/fail criteria expected_dl_bitrate: *expected_dl_bitrate_high expected_ul_bitrate: *expected_ul_bitrate_high - fail_if_kos: true + fail_if_kos: false warning_as_errors: true - campaign_filename: *campaign_filename @@ -95,7 +95,7 @@ tests: # test/fail criteria expected_dl_bitrate: *expected_dl_bitrate_low expected_ul_bitrate: *expected_ul_bitrate_low - fail_if_kos: true + fail_if_kos: false warning_as_errors: true - campaign_filename: *campaign_filename @@ -109,7 +109,7 @@ tests: # test/fail criteria expected_dl_bitrate: *expected_dl_bitrate_low expected_ul_bitrate: *expected_ul_bitrate_low - fail_if_kos: true + fail_if_kos: false warning_as_errors: true - campaign_filename: *campaign_filename @@ -151,7 +151,7 @@ tests: # test/fail criteria expected_dl_bitrate: *expected_dl_bitrate_low expected_ul_bitrate: *expected_ul_bitrate_low - fail_if_kos: true + fail_if_kos: false warning_as_errors: true # - campaign_filename: *campaign_filename @@ -207,7 +207,7 @@ tests: # test/fail criteria expected_dl_bitrate: *expected_dl_bitrate_low expected_ul_bitrate: *expected_ul_bitrate_low - fail_if_kos: true + fail_if_kos: false warning_as_errors: true - campaign_filename: *campaign_filename @@ -221,7 +221,7 @@ tests: # test/fail criteria expected_dl_bitrate: *expected_dl_bitrate_low expected_ul_bitrate: *expected_ul_bitrate_low - fail_if_kos: true + fail_if_kos: false warning_as_errors: true - campaign_filename: *campaign_filename From f55ce3a72ab3a5d00a75f539537147a9d706f507 Mon Sep 17 00:00:00 2001 From: asaezper Date: Mon, 22 Jul 2024 12:40:47 +0200 Subject: [PATCH 43/54] ci: fix basic asan flags --- .gitlab/ci/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 012125ee9b..cf0a625f12 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -1962,7 +1962,7 @@ basic asan: variables: TEST_MODE: none SAVE_ARTIFACTS: "True" - BUILD_ARGS: -DEXIT_TIMEOUT=15 + BUILD_ARGS: -DCMAKE_CXX_FLAGS="-march=x86-64-v3" -DEXIT_TIMEOUT=15 tags: ["${AMD64_AVX2_TAG}"] artifacts: <<: *build_artifacts From 6e06317493e924f7196c7a852286da53301dff14 Mon Sep 17 00:00:00 2001 From: asaezper Date: Mon, 22 Jul 2024 12:40:57 +0200 Subject: [PATCH 44/54] ci: fix variable parameters print --- .gitlab/ci/build.yml | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index cf0a625f12..1d3473c89a 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -133,16 +133,6 @@ variables: artifacts: false before_script: - !reference [.fetch_src_cache, script] - - | - # Print build parameters - echo "INFRASTRUCTURE_TAG=${INFRASTRUCTURE_TAG}" - echo "OS=${OS}" - echo "COMPILER=${COMPILER}" - echo "TEST_MODE=${TEST_MODE}" - echo "BUILD_ARGS=${BUILD_ARGS}" - echo "MAKE_ARGS=${MAKE_ARGS}" - echo "UHD_VERSION=${UHD_VERSION}" - echo "DPDK_VERSION=${DPDK_VERSION}" - | build_srsgnb() { start_time=$(date +%s) @@ -204,6 +194,15 @@ variables: BUILD_CMD="${BUILD_CMD} ${BUILD_ARGS}" fi + echo "INFRASTRUCTURE_TAG=${INFRASTRUCTURE_TAG}" + echo "OS=${OS}" + echo "COMPILER=${COMPILER}" + echo "TEST_MODE=${TEST_MODE}" + echo "BUILD_ARGS=${BUILD_CMD}" + echo "MAKE_ARGS=${MAKE_ARGS}" + echo "UHD_VERSION=${UHD_VERSION}" + echo "DPDK_VERSION=${DPDK_VERSION}" + if [ -n "${DPDK_VERSION}" ]; then BUILD_CMD="-d ${DPDK_VERSION} ${BUILD_CMD}" export LD_LIBRARY_PATH=/opt/dpdk/${DPDK_VERSION}/lib/x86_64-linux-gnu/:/opt/dpdk/${DPDK_VERSION}/lib/aarch64-linux-gnu/:${LD_LIBRARY_PATH} From 6790e32cb98747fadad92207843c844db9428a7c Mon Sep 17 00:00:00 2001 From: asaezper Date: Mon, 22 Jul 2024 10:14:45 +0200 Subject: [PATCH 45/54] ci: remove unnecessary after script --- .gitlab/ci/build.yml | 75 +++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 1d3473c89a..f478ea9b20 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -116,7 +116,6 @@ variables: # TEST TEST_EXECUTION_TIMEOUT: 0 # CI - SAVE_ARTIFACTS: "" # Empty by default KUBERNETES_CPU_REQUEST: 6 KUBERNETES_CPU_LIMIT: 6 KUBERNETES_MEMORY_REQUEST: 12Gi @@ -326,23 +325,22 @@ variables: script: - build_srsgnb - launch_tests - after_script: + timeout: 6h + cache: + - !reference [.fetch_src_cache, cache] + +.build_artifacts: + after_script: &build_after_script - mv ${CI_PROJECT_DIR}/build/coverage.xml ${CI_PROJECT_DIR}/${CI_JOB_ID}_coverage.xml || true - | - if [ -z "${SAVE_ARTIFACTS}" ]; then - rm -Rf ${CI_PROJECT_DIR}/build - rm -Rf build_time_metrics.txt - else - mv ${CI_PROJECT_DIR}/build/apps/gnb/gnb /tmp/gnb - mv ${CI_PROJECT_DIR}/build/apps/cu/srscu /tmp/srscu - mv ${CI_PROJECT_DIR}/build/apps/du/srsdu /tmp/srsdu - cd build - make clean - mv /tmp/gnb ${CI_PROJECT_DIR}/build/apps/gnb/gnb - mv /tmp/srscu ${CI_PROJECT_DIR}/build/apps/cu/srscu - mv /tmp/srsdu ${CI_PROJECT_DIR}/build/apps/du/srsdu - fi - timeout: 6h + mv ${CI_PROJECT_DIR}/build/apps/gnb/gnb /tmp/gnb + mv ${CI_PROJECT_DIR}/build/apps/cu/srscu /tmp/srscu + mv ${CI_PROJECT_DIR}/build/apps/du/srsdu /tmp/srsdu + cd build + make clean + mv /tmp/gnb ${CI_PROJECT_DIR}/build/apps/gnb/gnb + mv /tmp/srscu ${CI_PROJECT_DIR}/build/apps/cu/srscu + mv /tmp/srsdu ${CI_PROJECT_DIR}/build/apps/du/srsdu artifacts: &build_artifacts when: always reports: @@ -354,8 +352,6 @@ variables: - build/ - build_time_metrics.txt expire_in: 10 minutes - cache: - - !reference [.fetch_src_cache, cache] # Basic builds (MR and update cache on Nightly) @@ -504,8 +500,10 @@ smoke relwithdeb cached: - if: $CI_MERGE_REQUEST_LABELS =~ /no-cache/ when: never - if: $ON_MR - variables: - SAVE_ARTIFACTS: "True" + after_script: + - *build_after_script + artifacts: + <<: *build_artifacts cache: - !reference [.fetch_src_cache, cache] - *cache_build_get @@ -638,8 +636,10 @@ smoke relwithdeb clean: extends: .smoke relwithdeb rules: - if: $CI_MERGE_REQUEST_LABELS =~ /no-cache/ - variables: - SAVE_ARTIFACTS: "True" + after_script: + - *build_after_script + artifacts: + <<: *build_artifacts smoke tsan clean: extends: .smoke tsan @@ -691,8 +691,6 @@ intermediate commits cached: when: never - if: $ON_MR timeout: 2 hour - variables: - SAVE_ARTIFACTS: "True" script: - git config advice.detachedHead false - git fetch origin --depth=20 $CI_MERGE_REQUEST_TARGET_BRANCH_NAME $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME @@ -706,6 +704,10 @@ intermediate commits cached: build_srsgnb done - launch_tests + after_script: + - *build_after_script + artifacts: + <<: *build_artifacts cache: - !reference [.fetch_src_cache, cache] - *cache_build_get @@ -726,7 +728,6 @@ valgrind changed tests: CLEAN_BUILD: "False" FINGERPRINT: "fingerprints.csv" TEST_EXECUTION_TIMEOUT: 20m - SAVE_ARTIFACTS: "True" script: - git config advice.detachedHead false - git fetch origin $CI_MERGE_REQUEST_TARGET_BRANCH_NAME $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME --depth 40 @@ -780,8 +781,8 @@ smoke release update cache: start_in: 30 minutes retry: 2 interruptible: false - variables: - SAVE_ARTIFACTS: "True" + after_script: + - *build_after_script cache: - !reference [.fetch_src_cache, cache] - *cache_build_set @@ -1921,7 +1922,8 @@ basic relwithdeb: interruptible: false variables: TEST_MODE: none - SAVE_ARTIFACTS: "True" + after_script: + - *build_after_script artifacts: <<: *build_artifacts expire_in: 3 day @@ -1947,7 +1949,8 @@ basic tsan: interruptible: false variables: TEST_MODE: none - SAVE_ARTIFACTS: "True" + after_script: + - *build_after_script artifacts: <<: *build_artifacts expire_in: 3 day @@ -1960,9 +1963,10 @@ basic asan: interruptible: false variables: TEST_MODE: none - SAVE_ARTIFACTS: "True" BUILD_ARGS: -DCMAKE_CXX_FLAGS="-march=x86-64-v3" -DEXIT_TIMEOUT=15 tags: ["${AMD64_AVX2_TAG}"] + after_script: + - *build_after_script artifacts: <<: *build_artifacts expire_in: 3 day @@ -1975,7 +1979,8 @@ basic memcheck: interruptible: false variables: TEST_MODE: none - SAVE_ARTIFACTS: "True" + after_script: + - *build_after_script artifacts: <<: *build_artifacts expire_in: 3 day @@ -1999,8 +2004,9 @@ basic avx512 dpdk: BUILD_ARGS: -DCMAKE_CXX_FLAGS="-march=x86-64-v4" FORCE_DEBUG_INFO: "True" ASSERT_LEVEL: MINIMAL - SAVE_ARTIFACTS: "True" tags: ["${AMD64_AVX512_TAG}"] + after_script: + - *build_after_script artifacts: <<: *build_artifacts expire_in: 3 day @@ -2022,8 +2028,11 @@ custom build: variables: ENABLE_ZEROMQ: "" AUTO_DETECT_ISA: "" - SAVE_ARTIFACTS: "True" tags: ["${INFRASTRUCTURE_TAG}"] + after_script: + - *build_after_script + artifacts: + <<: *build_artifacts cache: - !reference [.fetch_src_cache, cache] - *cache_build_get From 8d7279bbe4790887f273f4b7fbeb95e729e059b1 Mon Sep 17 00:00:00 2001 From: asaezper Date: Tue, 16 Jul 2024 15:03:19 +0200 Subject: [PATCH 46/54] ci,e2e: add smoke e2e tests: attach-detach, ho and reest --- .gitlab/ci/e2e.yml | 2 + tests/e2e/tests/attach_detach.py | 32 ++++++++++++++ tests/e2e/tests/handover.py | 63 +++++++++++++++++++++++++-- tests/e2e/tests/iperf.py | 7 +-- tests/e2e/tests/reestablishment.py | 68 +++++++++++++++++++++++++++--- 5 files changed, 158 insertions(+), 14 deletions(-) diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index d0e3f0552a..3c20835ed7 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -369,6 +369,7 @@ amari 4UE asan: extends: .zmq variables: MARKERS: "smoke" + KEYWORDS: "iperf" RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.mac_enable=True gnb.all.rlc_enable=True gnb.all.enable_integrity_protection=True" needs: - job: "basic asan" @@ -380,6 +381,7 @@ amari 4UE tsan: extends: .zmq variables: MARKERS: "smoke" + KEYWORDS: "iperf" RETINA_PARAM_ARGS: "gnb.all.pcap=True gnb.all.mac_enable=True gnb.all.rlc_enable=True gnb.all.enable_integrity_protection=True" needs: - job: "basic tsan" diff --git a/tests/e2e/tests/attach_detach.py b/tests/e2e/tests/attach_detach.py index ead5b102bc..546fd5eb6b 100644 --- a/tests/e2e/tests/attach_detach.py +++ b/tests/e2e/tests/attach_detach.py @@ -28,6 +28,38 @@ BITRATE_THRESHOLD: float = 0.1 +@mark.zmq +@mark.smoke +def test_smoke( + retina_manager: RetinaTestManager, + retina_data: RetinaTestData, + ue_4: Tuple[UEStub, ...], + fivegc: FiveGCStub, + gnb: GNBStub, +): + """ + Smoke ZMQ Attach / Detach + """ + _attach_and_detach_multi_ues( + retina_manager=retina_manager, + retina_data=retina_data, + ue_array=ue_4, + gnb=gnb, + fivegc=fivegc, + band=41, + common_scs=30, + bandwidth=50, + sample_rate=None, + iperf_duration=30, + bitrate=HIGH_BITRATE, + protocol=IPerfProto.UDP, + direction=IPerfDir.BIDIRECTIONAL, + global_timing_advance=0, + time_alignment_calibration=0, + always_download_artifacts=False, + ) + + @mark.parametrize( "direction", ( diff --git a/tests/e2e/tests/handover.py b/tests/e2e/tests/handover.py index c1cc1a0a68..ec9c00654d 100644 --- a/tests/e2e/tests/handover.py +++ b/tests/e2e/tests/handover.py @@ -39,6 +39,33 @@ ) +@mark.zmq +@mark.smoke +def test_smoke_sequentially( + retina_manager: RetinaTestManager, + retina_data: RetinaTestData, + ue_2: UEStub, + fivegc: FiveGCStub, + gnb: GNBStub, +): + """ + ZMQ Handover tests + """ + _handover_sequentially( + retina_manager=retina_manager, + retina_data=retina_data, + ue_array=ue_2, + fivegc=fivegc, + gnb=gnb, + metrics_summary=None, + band=41, + common_scs=30, + bandwidth=50, + noise_spd=0, + always_download_artifacts=False, + ) + + @mark.parametrize( "band, common_scs, bandwidth, noise_spd", ( @@ -50,7 +77,7 @@ ) @mark.zmq @mark.flaky(reruns=2, only_rerun=["failed to start", "Attach timeout reached", "StatusCode.ABORTED"]) -# pylint: disable=too-many-arguments,too-many-locals +# pylint: disable=too-many-arguments def test_zmq_handover_sequentially( retina_manager: RetinaTestManager, retina_data: RetinaTestData, @@ -66,10 +93,38 @@ def test_zmq_handover_sequentially( """ ZMQ Handover tests """ - with _handover_multi_ues( + _handover_sequentially( retina_manager=retina_manager, retina_data=retina_data, ue_array=ue_8, + fivegc=fivegc, + gnb=gnb, + metrics_summary=metrics_summary, + band=band, + common_scs=common_scs, + bandwidth=bandwidth, + noise_spd=noise_spd, + ) + + +# pylint: disable=too-many-arguments,too-many-locals +def _handover_sequentially( + retina_manager: RetinaTestManager, + retina_data: RetinaTestData, + ue_array: UEStub, + fivegc: FiveGCStub, + gnb: GNBStub, + metrics_summary: Optional[MetricsSummary], + band: int, + common_scs: int, + bandwidth: int, + noise_spd: int, + always_download_artifacts: bool = True, +): + with _handover_multi_ues( + retina_manager=retina_manager, + retina_data=retina_data, + ue_array=ue_array, gnb=gnb, fivegc=fivegc, metrics_summary=metrics_summary, @@ -79,7 +134,7 @@ def test_zmq_handover_sequentially( sample_rate=None, # default from testbed global_timing_advance=0, time_alignment_calibration=0, - always_download_artifacts=True, + always_download_artifacts=always_download_artifacts, noise_spd=noise_spd, warning_as_errors=True, ) as (ue_attach_info_dict, movements, traffic_seconds): @@ -164,7 +219,7 @@ def _handover_multi_ues( ue_array: Sequence[UEStub], fivegc: FiveGCStub, gnb: GNBStub, - metrics_summary: MetricsSummary, + metrics_summary: Optional[MetricsSummary], band: int, common_scs: int, bandwidth: int, diff --git a/tests/e2e/tests/iperf.py b/tests/e2e/tests/iperf.py index 0b7b660ff6..65edcd1c05 100644 --- a/tests/e2e/tests/iperf.py +++ b/tests/e2e/tests/iperf.py @@ -407,15 +407,12 @@ def test_zmq_4x4_mimo( ) @mark.parametrize( "band, common_scs, bandwidth, bitrate", - ( - param(3, 15, 20, LOW_BITRATE, id=ZMQ_ID), - param(41, 30, 20, LOW_BITRATE, id=ZMQ_ID), - ), + (param(41, 30, 20, LOW_BITRATE, id=ZMQ_ID),), ) @mark.zmq @mark.smoke # pylint: disable=too-many-arguments -def test_zmq_smoke( +def test_smoke( retina_manager: RetinaTestManager, retina_data: RetinaTestData, ue_4: Tuple[UEStub, ...], diff --git a/tests/e2e/tests/reestablishment.py b/tests/e2e/tests/reestablishment.py index f86d62a96b..6d0ace5c4e 100644 --- a/tests/e2e/tests/reestablishment.py +++ b/tests/e2e/tests/reestablishment.py @@ -42,6 +42,33 @@ _ONLY_RERUN = ["failed to start", "Attach timeout reached", "StatusCode.ABORTED", "socket is already closed"] +@mark.zmq +@mark.smoke +def test_smoke_sequentially( + retina_manager: RetinaTestManager, + retina_data: RetinaTestData, + ue_4: Tuple[UEStub, ...], + fivegc: FiveGCStub, + gnb: GNBStub, +): + """ + ZMQ Ping + Reestablishment + """ + _reestablishment_sequentially_ping( + retina_manager=retina_manager, + retina_data=retina_data, + ue_array=ue_4, + fivegc=fivegc, + gnb=gnb, + metrics_summary=None, + band=41, + common_scs=30, + bandwidth=50, + noise_spd=0, + always_download_artifacts=False, + ) + + @mark.parametrize( "band, common_scs, bandwidth, noise_spd", ( @@ -53,7 +80,7 @@ ) @mark.zmq @mark.flaky(reruns=2, only_rerun=_ONLY_RERUN) -# pylint: disable=too-many-arguments,too-many-locals +# pylint: disable=too-many-arguments def test_zmq_reestablishment_sequentially( retina_manager: RetinaTestManager, retina_data: RetinaTestData, @@ -65,6 +92,37 @@ def test_zmq_reestablishment_sequentially( common_scs: int, bandwidth: int, noise_spd: int, +): + """ + ZMQ Ping + Reestablishment + """ + _reestablishment_sequentially_ping( + retina_manager=retina_manager, + retina_data=retina_data, + ue_array=ue_8, + fivegc=fivegc, + gnb=gnb, + metrics_summary=metrics_summary, + band=band, + common_scs=common_scs, + bandwidth=bandwidth, + noise_spd=noise_spd, + ) + + +# pylint: disable=too-many-arguments,too-many-locals +def _reestablishment_sequentially_ping( + retina_manager: RetinaTestManager, + retina_data: RetinaTestData, + ue_array: Tuple[UEStub, ...], + fivegc: FiveGCStub, + gnb: GNBStub, + metrics_summary: Optional[MetricsSummary], + band: int, + common_scs: int, + bandwidth: int, + noise_spd: int, + always_download_artifacts: bool = True, ): """ ZMQ Ping + Reestablishment @@ -75,7 +133,7 @@ def test_zmq_reestablishment_sequentially( for reest_ue_attach_info_dict, other_ue_attach_info_dict in _iterator_over_attached_ues( retina_manager=retina_manager, retina_data=retina_data, - ue_array=ue_8, + ue_array=ue_array, fivegc=fivegc, gnb=gnb, metrics_summary=metrics_summary, @@ -85,7 +143,7 @@ def test_zmq_reestablishment_sequentially( sample_rate=None, global_timing_advance=0, time_alignment_calibration=0, - always_download_artifacts=True, + always_download_artifacts=always_download_artifacts, noise_spd=noise_spd, log_ip_level="debug", warning_as_errors=True, @@ -324,7 +382,7 @@ def _iterator_over_attached_ues( ue_array: Sequence[UEStub], fivegc: FiveGCStub, gnb: GNBStub, - metrics_summary: MetricsSummary, + metrics_summary: Optional[MetricsSummary], band: int, common_scs: int, bandwidth: int, @@ -381,7 +439,7 @@ def _test_reestablishments( ue_array: Sequence[UEStub], fivegc: FiveGCStub, gnb: GNBStub, - metrics_summary: MetricsSummary, + metrics_summary: Optional[MetricsSummary], band: int, common_scs: int, bandwidth: int, From 152aeaf8b74016c1263af81e0f6a2cdf1cf3828d Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Fri, 19 Jul 2024 15:11:28 +0200 Subject: [PATCH 47/54] phy: integrate transform precoding in PUSCH demodulator phy: fix typo --- .../channel_processors/pusch/factories.h | 3 + .../pusch/pusch_demodulator.h | 2 + include/srsran/ran/pusch/pusch_constants.h | 3 + lib/phy/upper/CMakeLists.txt | 1 + .../channel_processors/pusch/factories.cpp | 14 ++ .../pusch/pusch_demodulator_impl.cpp | 166 ++++++++---------- .../pusch/pusch_demodulator_impl.h | 30 ++-- .../pusch/pusch_processor_impl.cpp | 1 + .../pusch/ulsch_demultiplex_impl.h | 7 +- lib/phy/upper/upper_phy_factories.cpp | 11 +- .../channel_processors/pusch/CMakeLists.txt | 1 + .../pusch/pusch_processor_benchmark.cpp | 8 +- .../pxsch_bler_test_factories.cpp | 8 +- .../channel_processors/pusch/CMakeLists.txt | 3 + .../pusch/pusch_demodulator_test_data.h | 102 +++++------ .../pusch/pusch_demodulator_test_data.tar.gz | 4 +- .../pusch/pusch_demodulator_vectortest.cpp | 14 +- .../pusch/pusch_processor_unittest.cpp | 1 + .../pusch/pusch_processor_validator_test.cpp | 8 +- .../pusch/pusch_processor_vectortest.cpp | 10 +- 20 files changed, 224 insertions(+), 173 deletions(-) diff --git a/include/srsran/phy/upper/channel_processors/pusch/factories.h b/include/srsran/phy/upper/channel_processors/pusch/factories.h index 56e27457c1..6cd1e2ea85 100644 --- a/include/srsran/phy/upper/channel_processors/pusch/factories.h +++ b/include/srsran/phy/upper/channel_processors/pusch/factories.h @@ -11,6 +11,7 @@ #pragma once #include "srsran/hal/phy/upper/channel_processors/pusch/hw_accelerator_pusch_dec_factory.h" +#include "srsran/phy/generic_functions/transform_precoding/transform_precoding_factories.h" #include "srsran/phy/upper/channel_coding/channel_coding_factories.h" #include "srsran/phy/upper/channel_modulation/channel_modulation_factories.h" #include "srsran/phy/upper/channel_processors/pusch/pusch_decoder.h" @@ -76,8 +77,10 @@ class pusch_demodulator_factory std::shared_ptr create_pusch_demodulator_factory_sw(std::shared_ptr equalizer_factory, + std::shared_ptr precoder_factory, std::shared_ptr demodulation_factory, std::shared_ptr prg_factory, + unsigned max_nof_prb, bool enable_evm = false, bool enable_post_eq_sinr = false); diff --git a/include/srsran/phy/upper/channel_processors/pusch/pusch_demodulator.h b/include/srsran/phy/upper/channel_processors/pusch/pusch_demodulator.h index ca13bec4db..6be84774ad 100644 --- a/include/srsran/phy/upper/channel_processors/pusch/pusch_demodulator.h +++ b/include/srsran/phy/upper/channel_processors/pusch/pusch_demodulator.h @@ -58,6 +58,8 @@ class pusch_demodulator unsigned n_id; /// Number of transmit layers. unsigned nof_tx_layers; + /// Set to true for enabling transform precoding. + bool enable_transform_precoding; /// Receive antenna port indices the PUSCH transmission is mapped to. static_vector rx_ports; }; diff --git a/include/srsran/ran/pusch/pusch_constants.h b/include/srsran/ran/pusch/pusch_constants.h index fb33bb13ac..0b3a7924bc 100644 --- a/include/srsran/ran/pusch/pusch_constants.h +++ b/include/srsran/ran/pusch/pusch_constants.h @@ -51,6 +51,9 @@ inline constexpr units::bits get_max_codeword_size(unsigned nof_prb, unsigned no return units::bits{get_codeword_max_symbols(nof_prb, nof_layers) * pusch_constants::MAX_MODULATION_ORDER}; } +/// Maximum number of bits per OFDM symbol. +constexpr unsigned MAX_NOF_BITS_PER_OFDM_SYMBOL = MAX_NOF_LAYERS * MAX_RB * NRE * pusch_constants::MAX_MODULATION_ORDER; + /// Maximum number of OFDM symbols carrying DM-RS in a slot is at most \f$4 \times 2\f$, being 4 the maximum /// number of positions \f$\bar{l}\f$ and 2 the maximum number of indices \f$l'\f$, as per TS38.211 Section 6.4.1.1. static constexpr unsigned MAX_NOF_DMRS_SYMBOLS = 4 * 2; diff --git a/lib/phy/upper/CMakeLists.txt b/lib/phy/upper/CMakeLists.txt index 630bc1aa6c..fc5e7cf420 100644 --- a/lib/phy/upper/CMakeLists.txt +++ b/lib/phy/upper/CMakeLists.txt @@ -35,6 +35,7 @@ target_link_libraries(srsran_upper_phy srsran_uplink_processor srsran_phy_support srsran_generic_funcs + srsran_transform_precoding srsran_channel_equalizer) add_library(log_likelihood_ratio log_likelihood_ratio.cpp) diff --git a/lib/phy/upper/channel_processors/pusch/factories.cpp b/lib/phy/upper/channel_processors/pusch/factories.cpp index 0a589a9abe..b1e67236a4 100644 --- a/lib/phy/upper/channel_processors/pusch/factories.cpp +++ b/lib/phy/upper/channel_processors/pusch/factories.cpp @@ -19,6 +19,7 @@ #include "pusch_processor_pool.h" #include "pusch_processor_validator_impl.h" #include "ulsch_demultiplex_impl.h" +#include "srsran/phy/generic_functions/transform_precoding/transform_precoding_factories.h" #include "srsran/phy/upper/channel_modulation/channel_modulation_factories.h" #include "srsran/phy/upper/channel_processors/pusch/pusch_processor_result_notifier.h" #include "srsran/phy/upper/sequence_generators/sequence_generator_factories.h" @@ -143,32 +144,41 @@ class pusch_demodulator_factory_generic : public pusch_demodulator_factory evm_calc = demodulation_factory->create_evm_calculator(); } return std::make_unique(equalizer_factory->create(), + precoder_factory->create(), demodulation_factory->create_demodulation_mapper(), std::move(evm_calc), prg_factory->create(), + max_nof_prb, enable_post_eq_sinr); } pusch_demodulator_factory_generic(std::shared_ptr equalizer_factory_, + std::shared_ptr precoder_factory_, std::shared_ptr demodulation_factory_, std::shared_ptr prg_factory_, + unsigned max_nof_prb_, bool enable_evm_, bool enable_post_eq_sinr_) : equalizer_factory(std::move(equalizer_factory_)), + precoder_factory(std::move(precoder_factory_)), demodulation_factory(std::move(demodulation_factory_)), prg_factory(std::move(prg_factory_)), + max_nof_prb(max_nof_prb_), enable_evm(enable_evm_), enable_post_eq_sinr(enable_post_eq_sinr_) { srsran_assert(equalizer_factory, "Invalid equalizer factory."); + srsran_assert(precoder_factory, "Invalid transform precoder factory."); srsran_assert(demodulation_factory, "Invalid demodulation factory."); srsran_assert(prg_factory, "Invalid PRG factory."); } private: std::shared_ptr equalizer_factory; + std::shared_ptr precoder_factory; std::shared_ptr demodulation_factory; std::shared_ptr prg_factory; + unsigned max_nof_prb; bool enable_evm; bool enable_post_eq_sinr; }; @@ -327,14 +337,18 @@ srsran::create_pusch_decoder_factory_hw(const pusch_decoder_factory_hw_configura std::shared_ptr srsran::create_pusch_demodulator_factory_sw(std::shared_ptr equalizer_factory, + std::shared_ptr precoder_factory, std::shared_ptr demodulation_factory, std::shared_ptr prg_factory, + unsigned max_nof_prb, bool enable_evm, bool enable_post_eq_sinr) { return std::make_shared(std::move(equalizer_factory), + std::move(precoder_factory), std::move(demodulation_factory), std::move(prg_factory), + max_nof_prb, enable_evm, enable_post_eq_sinr); } diff --git a/lib/phy/upper/channel_processors/pusch/pusch_demodulator_impl.cpp b/lib/phy/upper/channel_processors/pusch/pusch_demodulator_impl.cpp index 0ba9ca59b9..a0ccb09bfd 100644 --- a/lib/phy/upper/channel_processors/pusch/pusch_demodulator_impl.cpp +++ b/lib/phy/upper/channel_processors/pusch/pusch_demodulator_impl.cpp @@ -149,115 +149,110 @@ void pusch_demodulator_impl::demodulate(pusch_codeword_buffer& codeword_buf float noise_var_accumulate = 0.0; float evm_accumulate = 0.0; + // Process each OFDM symbol. for (unsigned i_symbol = config.start_symbol_index, i_symbol_end = config.start_symbol_index + config.nof_symbols; i_symbol != i_symbol_end; ++i_symbol) { // Select RE mask for the symbol. re_symbol_mask_type& symbol_re_mask = config.dmrs_symb_pos.test(i_symbol) ? re_mask_dmrs : re_mask; + // Count the number of active RE in the symbol. + unsigned nof_re_symbol = symbol_re_mask.count(); + // Skip symbol if it does not contain data. - if (symbol_re_mask.none()) { + if (nof_re_symbol == 0) { continue; } - // Process subcarriers in groups. - for (unsigned i_subc = symbol_re_mask.find_lowest(), i_subc_end = symbol_re_mask.find_highest() + 1; - i_subc != i_subc_end;) { - // Calculate the remainder number of subcarriers to process for the current OFDM symbol. - unsigned nof_block_subc = i_subc_end - i_subc; - - // Limit number of RE to the maximum block size. - nof_block_subc = std::min(nof_block_subc, MAX_BLOCK_SIZE / nof_bits_per_re); - - // Get a view of the codeword buffer destination. - span codeword_block = codeword_buffer.get_next_block_view(nof_block_subc * nof_bits_per_re); + // Resize equalizer output buffers. + span eq_re = span(temp_eq_re).first(nof_re_symbol * config.nof_tx_layers); + span eq_noise_vars = span(temp_eq_noise_vars).first(nof_re_symbol * config.nof_tx_layers); - // If the codeword is empty, skip the rest of the symbol. - if (codeword_block.empty()) { - unsigned nof_remainder_re = symbol_re_mask.slice(i_subc, symbol_re_mask.size()).count(); - srsran_assert(nof_remainder_re == 0, "There are {} remaining RE.", nof_remainder_re); - break; - } + // Extract the data symbols and channel estimates from the resource grid. + const re_buffer_reader& ch_re = get_ch_data_re(grid, i_symbol, symbol_re_mask, config.rx_ports); + const channel_equalizer::ch_est_list& ch_estimates = + get_ch_data_estimates(estimates, i_symbol, config.nof_tx_layers, symbol_re_mask, config.rx_ports); - // Limit block size if the codeword block is smaller. - srsran_assert(codeword_block.size() % nof_bits_per_re == 0, - "The codeword block size (i.e., {}) must be multiple of the number of bits per RE (i.e., {}).", - codeword_block.size(), - nof_bits_per_re); - - // Extract mask for the block. - // First, get the mask of data REs in the current block of received symbols. - re_symbol_mask_type block_re_mask = symbol_re_mask.slice(i_subc, i_subc + nof_block_subc); - // Next, get the number of subcarriers needed to carry the current codeword block. - unsigned nof_required_subc = static_cast(codeword_block.size()) / nof_bits_per_re; - // Ensure the number of data REs in the block of received symbols is not larger than the codeword block (expressed - // as a number of subcarriers). - while (block_re_mask.count() > nof_required_subc) { - --nof_block_subc; - block_re_mask = symbol_re_mask.slice(i_subc, i_subc + nof_block_subc); - } + // Extract the Rx port noise variances from the channel estimation. + for (unsigned i_port = 0; i_port != nof_rx_ports; ++i_port) { + noise_var_estimates[i_port] = estimates.get_noise_variance(i_port, 0); + } - // Number of data Resource Elements in a slot for a single Rx port. - unsigned nof_re_port = static_cast(block_re_mask.count()); + // Equalize channels and, for each Tx layer, combine contribution from all Rx antenna ports. + equalizer->equalize( + eq_re, eq_noise_vars, ch_re, ch_estimates, span(noise_var_estimates).first(nof_rx_ports), 1.0F); - // Skip block if no data. - if (nof_re_port == 0) { - i_subc += nof_block_subc; - continue; - } + // Revert transform precoding for the entire OFDM symbol. + if (config.enable_transform_precoding) { + srsran_assert(config.nof_tx_layers == 1, + "Transform precoding is only possible with one layer (i.e. {}).", + config.nof_tx_layers); + precoder->deprecode_ofdm_symbol(eq_re, eq_re); + } - // Resize equalizer output buffers. - span eq_re = span(temp_eq_re).first(nof_re_port * config.nof_tx_layers); - span eq_noise_vars = span(temp_eq_noise_vars).first(nof_re_port * config.nof_tx_layers); + // Estimate post equalization Signal-to-Interference-plus-Noise Ratio. + if (compute_post_eq_sinr) { + noise_var_accumulate += + std::accumulate(eq_noise_vars.begin(), eq_noise_vars.end(), 0.0F, [&sinr_softbit_count](float sum, float in) { + // Exclude outliers with infinite variance. This makes sure that handling of the DC carrier does not skew + // the SINR results. + if (std::isinf(in)) { + return sum; + } + + ++sinr_softbit_count; + return sum + in; + }); + } - // Extract the data symbols and channel estimates from the resource grid. - const re_buffer_reader& ch_re = get_ch_data_re(grid, i_symbol, i_subc, block_re_mask, config.rx_ports); - const channel_equalizer::ch_est_list& ch_estimates = - get_ch_data_estimates(estimates, i_symbol, i_subc, config.nof_tx_layers, block_re_mask, config.rx_ports); + // Counts the number of processed RE for the OFDM symbol. + unsigned count_re_symbol = 0; - // Increment subcarrier count. - i_subc += nof_block_subc; + // Process subcarriers in groups. + while (count_re_symbol != nof_re_symbol) { + // Calculate the remainder number of subcarriers to process for the current OFDM symbol. + unsigned remain_nof_subc = nof_re_symbol - count_re_symbol; - // Extract the Rx port noise variances from the channel estimation. - for (unsigned i_port = 0; i_port != nof_rx_ports; ++i_port) { - noise_var_estimates[i_port] = estimates.get_noise_variance(i_port, 0); - } + // Get a view of the codeword buffer destination. + span codeword = codeword_buffer.get_next_block_view(remain_nof_subc * nof_bits_per_re); - // Equalize channels and, for each Tx layer, combine contribution from all Rx antenna ports. - equalizer->equalize( - eq_re, eq_noise_vars, ch_re, ch_estimates, span(noise_var_estimates).first(nof_rx_ports), 1.0F); - - // Estimate post equalization Signal-to-Interference-plus-Noise Ratio. - if (compute_post_eq_sinr) { - noise_var_accumulate += std::accumulate( - eq_noise_vars.begin(), eq_noise_vars.end(), 0.0F, [&sinr_softbit_count](float sum, float in) { - // Exclude outliers with infinite variance. This makes sure that handling of the DC carrier does not skew - // the SINR results. - if (std::isinf(in)) { - return sum; - } - - ++sinr_softbit_count; - return sum + in; - }); - } + // Limit block size if the codeword block is smaller. + srsran_assert(codeword.size() % nof_bits_per_re == 0, + "The codeword block size (i.e., {}) must be multiple of the number of bits per RE (i.e., {}).", + codeword.size(), + nof_bits_per_re); - // Get codeword buffer. - unsigned nof_block_softbits = nof_re_port * nof_bits_per_re; - span codeword = codeword_block.first(nof_block_softbits); + // Select equalizer output. + unsigned nof_block_softbits = codeword.size(); + unsigned codeword_block_offset = count_re_symbol * config.nof_tx_layers; + unsigned codeword_block_size = nof_block_softbits / get_bits_per_symbol(config.modulation); + span eq_re_block = eq_re.subspan(codeword_block_offset, codeword_block_size); + span eq_noise_vars_block = eq_noise_vars.subspan(codeword_block_offset, codeword_block_size); // Build LLRs from channel symbols. - demapper->demodulate_soft(codeword, eq_re, eq_noise_vars, config.modulation); + demapper->demodulate_soft(codeword, eq_re_block, eq_noise_vars_block, config.modulation); // Calculate EVM only if it is available. if (evm_calc) { - unsigned nof_re_evm = eq_re.size(); - evm_accumulate += static_cast(nof_re_evm) * evm_calc->calculate(codeword, eq_re, config.modulation); - evm_symbol_count += nof_re_evm; + evm_accumulate += + static_cast(codeword_block_size) * evm_calc->calculate(codeword, eq_re_block, config.modulation); + evm_symbol_count += codeword_block_size; } - // Update and notify statistics. - if (i_subc == i_subc_end) { + // Generate scrambling sequence. + static_bit_buffer scrambling_seq(nof_block_softbits); + descrambler->generate(scrambling_seq); + + // Revert scrambling. + revert_scrambling(codeword, codeword, scrambling_seq); + + // Increment the number of processed RE within the OFDM symbol. + count_re_symbol += nof_block_softbits / nof_bits_per_re; + + // Update and notify statistics if it is the last processed block for the OFDM symbol. The provisional stats must + // be notified earlier than the new processed block to ensure the stats are available upon the notification of the + // results. + if (count_re_symbol == nof_re_symbol) { if ((sinr_softbit_count != 0) && (noise_var_accumulate > 0.0)) { float mean_noise_var = noise_var_accumulate / static_cast(sinr_softbit_count); stats.sinr_dB.emplace(-convert_power_to_dB(mean_noise_var)); @@ -270,13 +265,6 @@ void pusch_demodulator_impl::demodulate(pusch_codeword_buffer& codeword_buf notifier.on_provisional_stats(stats); } - // Generate scrambling sequence. - static_bit_buffer scrambling_seq(nof_block_softbits); - descrambler->generate(scrambling_seq); - - // Revert scrambling. - revert_scrambling(codeword, codeword, scrambling_seq); - // Notify a new processed block. codeword_buffer.on_new_block(codeword, scrambling_seq); } diff --git a/lib/phy/upper/channel_processors/pusch/pusch_demodulator_impl.h b/lib/phy/upper/channel_processors/pusch/pusch_demodulator_impl.h index 24fdd32634..2910890abc 100644 --- a/lib/phy/upper/channel_processors/pusch/pusch_demodulator_impl.h +++ b/lib/phy/upper/channel_processors/pusch/pusch_demodulator_impl.h @@ -13,6 +13,7 @@ #pragma once +#include "srsran/phy/generic_functions/transform_precoding/transform_precoder.h" #include "srsran/phy/support/re_buffer.h" #include "srsran/phy/support/resource_grid_reader.h" #include "srsran/phy/upper/channel_modulation/demodulation_mapper.h" @@ -33,16 +34,22 @@ class pusch_demodulator_impl : public pusch_demodulator public: /// Constructor: sets up internal components and acquires their ownership. pusch_demodulator_impl(std::unique_ptr equalizer_, + std::unique_ptr precoder_, std::unique_ptr demapper_, std::unique_ptr evm_calc_, std::unique_ptr descrambler_, + unsigned max_nof_rb, bool compute_post_eq_sinr_) : equalizer(std::move(equalizer_)), + precoder(std::move(precoder_)), demapper(std::move(demapper_)), evm_calc(std::move(evm_calc_)), descrambler(std::move(descrambler_)), + ch_re_copy(MAX_PORTS, max_nof_rb * NRE), ch_re_view(pusch_constants::MAX_NOF_RX_PORTS), - ch_estimates_copy(MAX_BLOCK_SIZE, pusch_constants::MAX_NOF_RX_PORTS, pusch_constants::MAX_NOF_LAYERS), + temp_eq_re(max_nof_rb * NRE * pusch_constants::MAX_NOF_LAYERS), + temp_eq_noise_vars(max_nof_rb * NRE * pusch_constants::MAX_NOF_LAYERS), + ch_estimates_copy(max_nof_rb * NRE, pusch_constants::MAX_NOF_RX_PORTS, pusch_constants::MAX_NOF_LAYERS), ch_estimates_view(pusch_constants::MAX_NOF_RX_PORTS, pusch_constants::MAX_NOF_LAYERS), compute_post_eq_sinr(compute_post_eq_sinr_) { @@ -58,8 +65,6 @@ class pusch_demodulator_impl : public pusch_demodulator const configuration& config) override; private: - /// Maximum processing block size in bits. - static constexpr unsigned MAX_BLOCK_SIZE = 4096; /// Data type for representing an RE mask within an OFDM symbol. using re_symbol_mask_type = bounded_bitset; @@ -70,13 +75,11 @@ class pusch_demodulator_impl : public pusch_demodulator /// /// \param[in] grid Resource grid for the current slot. /// \param[in] i_symbol OFDM symbol index relative to the beginning of the slot. - /// \param[in] init_subc Initial subcarrier index relative to Point A. /// \param[in] re_mask Resource element mask, it selects the RE elements to extract. /// \param[in] rx_ports Receive ports. /// \return A reference to the PUSCH channel data symbols. const re_buffer_reader& get_ch_data_re(const resource_grid_reader& grid, unsigned i_symbol, - unsigned init_subc, const re_symbol_mask_type& re_mask, const static_vector& rx_ports) { @@ -97,7 +100,7 @@ class pusch_demodulator_impl : public pusch_demodulator span ch_data_re = grid.get_view(i_port, i_symbol); // Set the view in the channel estimates. - ch_re_view.set_slice(i_port, ch_data_re.subspan(init_subc + begin, nof_re)); + ch_re_view.set_slice(i_port, ch_data_re.subspan(begin, nof_re)); } return ch_re_view; } @@ -111,7 +114,7 @@ class pusch_demodulator_impl : public pusch_demodulator span re_port_buffer = ch_re_copy.get_slice(i_port); // Copy grid data resource elements into the buffer. - re_port_buffer = grid.get(re_port_buffer, rx_ports[i_port], i_symbol, init_subc, re_mask); + re_port_buffer = grid.get(re_port_buffer, rx_ports[i_port], i_symbol, 0, re_mask); // Verify buffer size. srsran_assert( @@ -136,7 +139,6 @@ class pusch_demodulator_impl : public pusch_demodulator /// \return A reference to the PUSCH channel data estimates. const channel_equalizer::ch_est_list& get_ch_data_estimates(const channel_estimate& channel_estimate, unsigned i_symbol, - unsigned init_subc, unsigned nof_tx_layers, const re_symbol_mask_type& re_mask, const static_vector& rx_ports) @@ -159,7 +161,7 @@ class pusch_demodulator_impl : public pusch_demodulator span symbol_estimates = channel_estimate.get_symbol_ch_estimate(i_symbol, i_port, i_layer); // Set the view in the channel estimates. - ch_estimates_view.set_channel(symbol_estimates.subspan(init_subc + begin, nof_re), i_port, i_layer); + ch_estimates_view.set_channel(symbol_estimates.subspan(begin, nof_re), i_port, i_layer); } } @@ -179,7 +181,7 @@ class pusch_demodulator_impl : public pusch_demodulator span symbol_estimates = channel_estimate.get_symbol_ch_estimate(i_symbol, i_port, i_layer); // Get view of the selected area of the grid. - symbol_estimates = symbol_estimates.subspan(init_subc, re_mask.size()); + symbol_estimates = symbol_estimates.first(re_mask.size()); // Skip DM-RS estimates. re_mask.for_each(0, re_mask.size(), [&symbol_estimates, &ch_port_buffer](unsigned i_re) { @@ -202,6 +204,8 @@ class pusch_demodulator_impl : public pusch_demodulator /// Channel equalization component, also in charge of combining contributions of all receive antenna ports. std::unique_ptr equalizer; + /// Transform precoder. + std::unique_ptr precoder; /// Demodulation mapper component: transforms channel symbols into log-likelihood ratios (i.e., soft bits). std::unique_ptr demapper; /// EVM calculator. Optional, set to nullptr if not available. @@ -209,13 +213,13 @@ class pusch_demodulator_impl : public pusch_demodulator /// Descrambler component. std::unique_ptr descrambler; /// Copy buffer used to transfer channel modulation symbols from the resource grid to the equalizer. - static_re_buffer ch_re_copy; + dynamic_re_buffer ch_re_copy; /// View buffer used to transfer channel modulation symbols from the resource grid to the equalizer. modular_re_buffer_reader ch_re_view; /// Buffer used to store channel modulation resource elements at the equalizer output. - std::array temp_eq_re; + std::vector temp_eq_re; /// Buffer used to transfer symbol noise variances at the equalizer output. - std::array temp_eq_noise_vars; + std::vector temp_eq_noise_vars; /// Copy buffer used to transfer channel estimation coefficients from the channel estimate to the equalizer. dynamic_ch_est_list ch_estimates_copy; /// View buffer used to transfer channel estimation coefficients from the channel estimate to the equalizer. diff --git a/lib/phy/upper/channel_processors/pusch/pusch_processor_impl.cpp b/lib/phy/upper/channel_processors/pusch/pusch_processor_impl.cpp index 3cad769ff7..76cf4b2d68 100644 --- a/lib/phy/upper/channel_processors/pusch/pusch_processor_impl.cpp +++ b/lib/phy/upper/channel_processors/pusch/pusch_processor_impl.cpp @@ -279,6 +279,7 @@ void pusch_processor_impl::process(span data, demod_config.nof_cdm_groups_without_data = pdu.nof_cdm_groups_without_data; demod_config.n_id = pdu.n_id; demod_config.nof_tx_layers = pdu.nof_tx_layers; + demod_config.enable_transform_precoding = false; demod_config.rx_ports = pdu.rx_ports; dependencies.get_demodulator().demodulate( demodulator_buffer, notifier_adaptor.get_demodulator_notifier(), grid, ch_estimate, demod_config); diff --git a/lib/phy/upper/channel_processors/pusch/ulsch_demultiplex_impl.h b/lib/phy/upper/channel_processors/pusch/ulsch_demultiplex_impl.h index 040e8096da..3c5e3a0e8d 100644 --- a/lib/phy/upper/channel_processors/pusch/ulsch_demultiplex_impl.h +++ b/lib/phy/upper/channel_processors/pusch/ulsch_demultiplex_impl.h @@ -33,9 +33,6 @@ class ulsch_demultiplex_impl : public ulsch_demultiplex, private pusch_codeword_ const configuration& config) override; private: - static constexpr unsigned max_nof_bits_ofdm_symbol = - MAX_RB * NRE * pusch_constants::MAX_MODULATION_ORDER * pusch_constants::MAX_NOF_LAYERS; - // See pusch_codeword_buffer for documentation. span get_next_block_view(unsigned block_size) override; @@ -104,9 +101,9 @@ class ulsch_demultiplex_impl : public ulsch_demultiplex, private pusch_codeword_ /// Set of resource elements for CSI Part 2 transmission. re_set_type csi_part2_re_set; /// Demodulated soft bits buffer for an entire OFDM symbol. - std::array temp_data_ofdm_symbol; + std::array temp_data_ofdm_symbol; /// Scrambling sequence for an entire OFDM symbol. - static_bit_buffer temp_scrambling_seq_ofdm_symbol; + static_bit_buffer temp_scrambling_seq_ofdm_symbol; }; } // namespace srsran diff --git a/lib/phy/upper/upper_phy_factories.cpp b/lib/phy/upper/upper_phy_factories.cpp index 04800e652d..2fc6151f23 100644 --- a/lib/phy/upper/upper_phy_factories.cpp +++ b/lib/phy/upper/upper_phy_factories.cpp @@ -373,8 +373,15 @@ static std::shared_ptr create_ul_processor_factory(con std::shared_ptr ch_estimator_factory = create_port_channel_estimator_factory_sw(ta_estimator_factory); - std::shared_ptr equalizer_factory = create_channel_equalizer_generic_factory(); + std::shared_ptr equalizer_factory = create_channel_equalizer_generic_factory(); + report_error_if_not(equalizer_factory, "Invalid equalizer factory."); + + std::shared_ptr precoding_factory = + create_dft_transform_precoder_factory(dft_factory, config.ul_bw_rb); + report_fatal_error_if_not(precoding_factory, "Invalid transform precoder factory."); + std::shared_ptr demodulation_factory = create_channel_modulation_sw_factory(); + report_error_if_not(demodulation_factory, "Invalid demodulation factory."); std::shared_ptr crc_calc_factory = create_crc_calculator_factory_sw(config.crc_calculator_type); @@ -417,7 +424,7 @@ static std::shared_ptr create_ul_processor_factory(con pusch_processor_factory_sw_configuration pusch_config; pusch_config.estimator_factory = create_dmrs_pusch_estimator_factory_sw(prg_factory, ch_estimator_factory); pusch_config.demodulator_factory = create_pusch_demodulator_factory_sw( - equalizer_factory, demodulation_factory, prg_factory, enable_evm, enable_eq_sinr); + equalizer_factory, precoding_factory, demodulation_factory, prg_factory, enable_evm, enable_eq_sinr); pusch_config.demux_factory = create_ulsch_demultiplex_factory_sw(); pusch_config.uci_dec_factory = uci_dec_factory; pusch_config.dec_nof_iterations = config.ldpc_decoder_iterations; diff --git a/tests/benchmarks/phy/upper/channel_processors/pusch/CMakeLists.txt b/tests/benchmarks/phy/upper/channel_processors/pusch/CMakeLists.txt index f792baaa4d..04ba258e8d 100644 --- a/tests/benchmarks/phy/upper/channel_processors/pusch/CMakeLists.txt +++ b/tests/benchmarks/phy/upper/channel_processors/pusch/CMakeLists.txt @@ -29,6 +29,7 @@ set(PUSCH_PROCESSOR_LIBRARIES srsran_phy_support srsran_channel_equalizer srsran_channel_precoder srsran_channel_processors + srsran_transform_precoding srslog srsvec) diff --git a/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_processor_benchmark.cpp b/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_processor_benchmark.cpp index 8439de2e3b..c4cd0827e7 100644 --- a/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_processor_benchmark.cpp +++ b/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_processor_benchmark.cpp @@ -538,9 +538,13 @@ static pusch_processor_factory& get_pusch_processor_factory() std::shared_ptr eq_factory = create_channel_equalizer_generic_factory(); TESTASSERT(eq_factory); + std::shared_ptr precoding_factory = + create_dft_transform_precoder_factory(dft_factory, MAX_RB); + TESTASSERT(precoding_factory); + // Create PUSCH demodulator factory. - std::shared_ptr pusch_demod_factory = - create_pusch_demodulator_factory_sw(eq_factory, chan_modulation_factory, prg_factory, enable_evm); + std::shared_ptr pusch_demod_factory = create_pusch_demodulator_factory_sw( + eq_factory, precoding_factory, chan_modulation_factory, prg_factory, MAX_RB, enable_evm); TESTASSERT(pusch_demod_factory); // Create PUSCH demultiplexer factory. diff --git a/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_factories.cpp b/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_factories.cpp index 9277bbbdf0..da35f08414 100644 --- a/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_factories.cpp +++ b/tests/integrationtests/phy/upper/channel_processors/pxsch_bler_test_factories.cpp @@ -105,8 +105,12 @@ std::shared_ptr srsran::create_sw_pusch_processor_facto std::shared_ptr chan_mod_factory = create_channel_modulation_sw_factory(); report_fatal_error_if_not(chan_mod_factory, "Failed to create factory."); - std::shared_ptr pusch_demod_factory = - create_pusch_demodulator_factory_sw(eq_factory, chan_mod_factory, pseudo_random_gen_factory, true, true); + std::shared_ptr precoding_factory = + create_dft_transform_precoder_factory(dft_proc_factory, MAX_RB); + report_fatal_error_if_not(precoding_factory, "Invalid transform precoding factory."); + + std::shared_ptr pusch_demod_factory = create_pusch_demodulator_factory_sw( + eq_factory, precoding_factory, chan_mod_factory, pseudo_random_gen_factory, MAX_RB, true, true); report_fatal_error_if_not(pusch_demod_factory, "Failed to create factory."); std::shared_ptr demux_factory = create_ulsch_demultiplex_factory_sw(); diff --git a/tests/unittests/phy/upper/channel_processors/pusch/CMakeLists.txt b/tests/unittests/phy/upper/channel_processors/pusch/CMakeLists.txt index 980e660359..ef15534d43 100644 --- a/tests/unittests/phy/upper/channel_processors/pusch/CMakeLists.txt +++ b/tests/unittests/phy/upper/channel_processors/pusch/CMakeLists.txt @@ -18,6 +18,7 @@ target_link_libraries(pusch_processor_validator_test srsran_phy_support srslog srsran_upper_phy_support + srsran_transform_precoding gtest gtest_main) add_test(pusch_processor_validator_test pusch_processor_validator_test) @@ -46,6 +47,7 @@ if (USE_PHY_TESTVECTORS) srsran_phy_support srslog srsran_upper_phy_support + srsran_transform_precoding gtest gtest_main) add_test_vector(pusch_demodulator_vectortest pusch_demodulator_test_data.tar.gz "") @@ -56,6 +58,7 @@ if (USE_PHY_TESTVECTORS) srsran_phy_support srslog srsran_upper_phy_support + srsran_transform_precoding gtest gtest_main) diff --git a/tests/unittests/phy/upper/channel_processors/pusch/pusch_demodulator_test_data.h b/tests/unittests/phy/upper/channel_processors/pusch/pusch_demodulator_test_data.h index 356f03d4df..5cd5eefe3b 100644 --- a/tests/unittests/phy/upper/channel_processors/pusch/pusch_demodulator_test_data.h +++ b/tests/unittests/phy/upper/channel_processors/pusch/pusch_demodulator_test_data.h @@ -10,7 +10,7 @@ #pragma once -// This file was generated using the following MATLAB class on 27-06-2024 (seed 0): +// This file was generated using the following MATLAB class on 19-07-2024 (seed 0): // + "srsPUSCHDemodulatorUnittest.m" #include "../../../support/resource_grid_test_doubles.h" @@ -37,56 +37,56 @@ struct test_case_t { static const std::vector pusch_demodulator_test_data = { // clang-format off - {{0.0016124, 30.3963, {41442, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, modulation_scheme::PI_2_BPSK, 2, 7, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 1, 821, 1, {0}}}, {"test_data/pusch_demodulator_test_input_symbols0.dat"}, {"test_data/pusch_demodulator_test_input_estimates0.dat", {300, 14, 1, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq0.dat"}, {"test_data/pusch_demodulator_test_output0.dat"}}, - {{0.0014186, 28.6761, {43699, {1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::PI_2_BPSK, 1, 13, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 1, 995, 1, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols2.dat"}, {"test_data/pusch_demodulator_test_input_estimates2.dat", {300, 14, 2, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq2.dat"}, {"test_data/pusch_demodulator_test_output2.dat"}}, - {{0.00073408, 29.564, {59376, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0}, modulation_scheme::PI_2_BPSK, 1, 8, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 510, 2, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols4.dat"}, {"test_data/pusch_demodulator_test_input_estimates4.dat", {300, 14, 2, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq4.dat"}, {"test_data/pusch_demodulator_test_output4.dat"}}, - {{0.018395, 18.4471, {14385, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::PI_2_BPSK, 1, 12, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 684, 1, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols6.dat"}, {"test_data/pusch_demodulator_test_input_estimates6.dat", {300, 14, 4, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq6.dat"}, {"test_data/pusch_demodulator_test_output6.dat"}}, - {{0.0022435, 25.5939, {5510, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::PI_2_BPSK, 0, 8, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 1, 238, 2, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols8.dat"}, {"test_data/pusch_demodulator_test_input_estimates8.dat", {300, 14, 4, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq8.dat"}, {"test_data/pusch_demodulator_test_output8.dat"}}, - {{0.10174, 11.8499, {11247, {1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QPSK, 1, 9, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 24, 1, {0}}}, {"test_data/pusch_demodulator_test_input_symbols10.dat"}, {"test_data/pusch_demodulator_test_input_estimates10.dat", {300, 14, 1, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq10.dat"}, {"test_data/pusch_demodulator_test_output10.dat"}}, - {{0.0014186, 29.2471, {13308, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QPSK, 1, 8, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 1, 441, 1, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols12.dat"}, {"test_data/pusch_demodulator_test_input_estimates12.dat", {300, 14, 2, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq12.dat"}, {"test_data/pusch_demodulator_test_output12.dat"}}, - {{0.029224, 13.5496, {60495, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0}, modulation_scheme::QPSK, 1, 8, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 638, 2, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols14.dat"}, {"test_data/pusch_demodulator_test_input_estimates14.dat", {300, 14, 2, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq14.dat"}, {"test_data/pusch_demodulator_test_output14.dat"}}, - {{0.00073234, 32.0545, {8543, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QPSK, 0, 8, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 1, 431, 1, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols16.dat"}, {"test_data/pusch_demodulator_test_input_estimates16.dat", {300, 14, 4, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq16.dat"}, {"test_data/pusch_demodulator_test_output16.dat"}}, - {{0.035557, 14.1995, {36974, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, modulation_scheme::QPSK, 0, 11, {0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE1, 1, 75, 2, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols18.dat"}, {"test_data/pusch_demodulator_test_input_estimates18.dat", {300, 14, 4, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq18.dat"}, {"test_data/pusch_demodulator_test_output18.dat"}}, - {{0.064192, 14.2557, {27364, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM16, 1, 13, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 1, 638, 1, {0}}}, {"test_data/pusch_demodulator_test_input_symbols20.dat"}, {"test_data/pusch_demodulator_test_input_estimates20.dat", {300, 14, 1, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq20.dat"}, {"test_data/pusch_demodulator_test_output20.dat"}}, - {{0.022483, 16.6985, {43398, {1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM16, 1, 12, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 2, 86, 1, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols22.dat"}, {"test_data/pusch_demodulator_test_input_estimates22.dat", {300, 14, 2, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq22.dat"}, {"test_data/pusch_demodulator_test_output22.dat"}}, - {{0.011634, 13.654, {5149, {1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM16, 0, 14, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 1, 592, 2, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols24.dat"}, {"test_data/pusch_demodulator_test_input_estimates24.dat", {300, 14, 2, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq24.dat"}, {"test_data/pusch_demodulator_test_output24.dat"}}, - {{0.00058172, 33.3567, {7243, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM16, 1, 13, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 2, 58, 1, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols26.dat"}, {"test_data/pusch_demodulator_test_input_estimates26.dat", {300, 14, 4, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq26.dat"}, {"test_data/pusch_demodulator_test_output26.dat"}}, - {{0.0056354, 21.8862, {16991, {1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM16, 1, 13, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 1, 726, 2, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols28.dat"}, {"test_data/pusch_demodulator_test_input_estimates28.dat", {300, 14, 4, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq28.dat"}, {"test_data/pusch_demodulator_test_output28.dat"}}, - {{0.0064192, 23.9812, {56623, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0}, modulation_scheme::QAM64, 0, 7, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 642, 1, {0}}}, {"test_data/pusch_demodulator_test_input_symbols30.dat"}, {"test_data/pusch_demodulator_test_input_estimates30.dat", {300, 14, 1, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq30.dat"}, {"test_data/pusch_demodulator_test_output30.dat"}}, - {{0.0022483, 27.3943, {2220, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM64, 2, 8, {0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 64, 1, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols32.dat"}, {"test_data/pusch_demodulator_test_input_estimates32.dat", {300, 14, 2, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq32.dat"}, {"test_data/pusch_demodulator_test_output32.dat"}}, - {{0.036791, 10.9553, {14331, {1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM64, 2, 10, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 1, 261, 2, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols34.dat"}, {"test_data/pusch_demodulator_test_input_estimates34.dat", {300, 14, 2, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq34.dat"}, {"test_data/pusch_demodulator_test_output34.dat"}}, - {{0.0011607, 29.9179, {46813, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0}, modulation_scheme::QAM64, 1, 11, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 1, 556, 1, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols36.dat"}, {"test_data/pusch_demodulator_test_input_estimates36.dat", {300, 14, 4, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq36.dat"}, {"test_data/pusch_demodulator_test_output36.dat"}}, - {{0.011244, 19.0355, {4963, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM64, 0, 12, {0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 493, 2, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols38.dat"}, {"test_data/pusch_demodulator_test_input_estimates38.dat", {300, 14, 4, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq38.dat"}, {"test_data/pusch_demodulator_test_output38.dat"}}, - {{0.080813, 12.6709, {61941, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM256, 1, 7, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 1, 425, 1, {0}}}, {"test_data/pusch_demodulator_test_input_symbols40.dat"}, {"test_data/pusch_demodulator_test_input_estimates40.dat", {300, 14, 1, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq40.dat"}, {"test_data/pusch_demodulator_test_output40.dat"}}, - {{0.011268, 20.1044, {5690, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM256, 2, 9, {0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 689, 1, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols42.dat"}, {"test_data/pusch_demodulator_test_input_estimates42.dat", {300, 14, 2, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq42.dat"}, {"test_data/pusch_demodulator_test_output42.dat"}}, - {{0.0046318, 20.4928, {7084, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM256, 1, 10, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 727, 2, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols44.dat"}, {"test_data/pusch_demodulator_test_input_estimates44.dat", {300, 14, 2, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq44.dat"}, {"test_data/pusch_demodulator_test_output44.dat"}}, - {{0.0036704, 25.3347, {11215, {1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM256, 1, 10, {0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE1, 1, 446, 1, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols46.dat"}, {"test_data/pusch_demodulator_test_input_estimates46.dat", {300, 14, 4, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq46.dat"}, {"test_data/pusch_demodulator_test_output46.dat"}}, - {{0.0044763, 23.2376, {25869, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM256, 1, 8, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 70, 2, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols48.dat"}, {"test_data/pusch_demodulator_test_input_estimates48.dat", {300, 14, 4, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq48.dat"}, {"test_data/pusch_demodulator_test_output48.dat"}}, - {{0.025555, 18.0999, {11969, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0}, modulation_scheme::PI_2_BPSK, 2, 11, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE2, 3, 604, 1, {0}}}, {"test_data/pusch_demodulator_test_input_symbols50.dat"}, {"test_data/pusch_demodulator_test_input_estimates50.dat", {300, 14, 1, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq50.dat"}, {"test_data/pusch_demodulator_test_output50.dat"}}, - {{0.044859, 14.4257, {22934, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::PI_2_BPSK, 0, 12, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE2, 3, 830, 1, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols52.dat"}, {"test_data/pusch_demodulator_test_input_estimates52.dat", {300, 14, 2, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq52.dat"}, {"test_data/pusch_demodulator_test_output52.dat"}}, - {{0.023214, 15.0447, {50487, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::PI_2_BPSK, 1, 7, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE2, 2, 824, 2, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols54.dat"}, {"test_data/pusch_demodulator_test_input_estimates54.dat", {300, 14, 2, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq54.dat"}, {"test_data/pusch_demodulator_test_output54.dat"}}, - {{0.0023159, 27.2753, {22017, {1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::PI_2_BPSK, 1, 8, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE2, 2, 239, 1, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols56.dat"}, {"test_data/pusch_demodulator_test_input_estimates56.dat", {300, 14, 4, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq56.dat"}, {"test_data/pusch_demodulator_test_output56.dat"}}, - {{0.028244, 15.2944, {48073, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0}, modulation_scheme::PI_2_BPSK, 1, 9, {0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE2, 1, 788, 2, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols58.dat"}, {"test_data/pusch_demodulator_test_input_estimates58.dat", {300, 14, 4, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq58.dat"}, {"test_data/pusch_demodulator_test_output58.dat"}}, - {{0.025555, 17.8496, {14840, {1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QPSK, 1, 12, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, dmrs_type::TYPE2, 1, 960, 1, {0}}}, {"test_data/pusch_demodulator_test_input_symbols60.dat"}, {"test_data/pusch_demodulator_test_input_estimates60.dat", {300, 14, 1, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq60.dat"}, {"test_data/pusch_demodulator_test_output60.dat"}}, - {{0.0056474, 22.7951, {20601, {1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QPSK, 1, 13, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, dmrs_type::TYPE2, 2, 146, 1, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols62.dat"}, {"test_data/pusch_demodulator_test_input_estimates62.dat", {300, 14, 2, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq62.dat"}, {"test_data/pusch_demodulator_test_output62.dat"}}, - {{0.014647, 14.337, {25000, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QPSK, 2, 10, {0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE2, 3, 499, 2, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols64.dat"}, {"test_data/pusch_demodulator_test_input_estimates64.dat", {300, 14, 2, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq64.dat"}, {"test_data/pusch_demodulator_test_output64.dat"}}, - {{0.0073234, 22.1002, {35076, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}, modulation_scheme::QPSK, 2, 10, {0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE2, 3, 249, 1, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols66.dat"}, {"test_data/pusch_demodulator_test_input_estimates66.dat", {300, 14, 4, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq66.dat"}, {"test_data/pusch_demodulator_test_output66.dat"}}, - {{0.014155, 17.6081, {4117, {1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QPSK, 0, 14, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, dmrs_type::TYPE2, 1, 248, 2, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols68.dat"}, {"test_data/pusch_demodulator_test_input_estimates68.dat", {300, 14, 4, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq68.dat"}, {"test_data/pusch_demodulator_test_output68.dat"}}, - {{0.016124, 20.2665, {17118, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM16, 2, 7, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE2, 2, 457, 1, {0}}}, {"test_data/pusch_demodulator_test_input_symbols70.dat"}, {"test_data/pusch_demodulator_test_input_estimates70.dat", {300, 14, 1, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq70.dat"}, {"test_data/pusch_demodulator_test_output70.dat"}}, - {{0.017859, 18.005, {60097, {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM16, 0, 9, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE2, 3, 477, 1, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols72.dat"}, {"test_data/pusch_demodulator_test_input_estimates72.dat", {300, 14, 2, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq72.dat"}, {"test_data/pusch_demodulator_test_output72.dat"}}, - {{0.0029224, 23.3405, {14064, {1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM16, 0, 10, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE2, 2, 514, 2, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols74.dat"}, {"test_data/pusch_demodulator_test_input_estimates74.dat", {300, 14, 2, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq74.dat"}, {"test_data/pusch_demodulator_test_output74.dat"}}, - {{0.0058172, 22.7771, {28692, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, modulation_scheme::QAM16, 0, 8, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE2, 3, 207, 1, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols76.dat"}, {"test_data/pusch_demodulator_test_input_estimates76.dat", {300, 14, 4, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq76.dat"}, {"test_data/pusch_demodulator_test_output76.dat"}}, - {{0.0011244, 28.9833, {24074, {1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM16, 1, 13, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, dmrs_type::TYPE2, 1, 538, 2, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols78.dat"}, {"test_data/pusch_demodulator_test_input_estimates78.dat", {300, 14, 4, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq78.dat"}, {"test_data/pusch_demodulator_test_output78.dat"}}, - {{0.0020299, 29.1925, {15934, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM64, 1, 10, {0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE2, 1, 986, 1, {0}}}, {"test_data/pusch_demodulator_test_input_symbols80.dat"}, {"test_data/pusch_demodulator_test_input_estimates80.dat", {300, 14, 1, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq80.dat"}, {"test_data/pusch_demodulator_test_output80.dat"}}, - {{0.00056474, 33.0377, {46564, {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM64, 1, 12, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, dmrs_type::TYPE2, 1, 564, 1, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols82.dat"}, {"test_data/pusch_demodulator_test_input_estimates82.dat", {300, 14, 2, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq82.dat"}, {"test_data/pusch_demodulator_test_output82.dat"}}, - {{0.029224, 9.1004, {35572, {1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM64, 2, 12, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE2, 2, 156, 2, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols84.dat"}, {"test_data/pusch_demodulator_test_input_estimates84.dat", {300, 14, 2, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq84.dat"}, {"test_data/pusch_demodulator_test_output84.dat"}}, - {{0.0073234, 21.9987, {749, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM64, 0, 12, {0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE2, 1, 13, 1, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols86.dat"}, {"test_data/pusch_demodulator_test_input_estimates86.dat", {300, 14, 4, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq86.dat"}, {"test_data/pusch_demodulator_test_output86.dat"}}, - {{0.00089315, 30.3226, {21309, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM64, 2, 11, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, dmrs_type::TYPE2, 3, 39, 2, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols88.dat"}, {"test_data/pusch_demodulator_test_input_estimates88.dat", {300, 14, 4, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq88.dat"}, {"test_data/pusch_demodulator_test_output88.dat"}}, - {{0.005099, 25.0125, {47542, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM256, 0, 10, {0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE2, 1, 760, 1, {0}}}, {"test_data/pusch_demodulator_test_input_symbols90.dat"}, {"test_data/pusch_demodulator_test_input_estimates90.dat", {300, 14, 1, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq90.dat"}, {"test_data/pusch_demodulator_test_output90.dat"}}, - {{0.00089506, 31.2937, {59296, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM256, 0, 12, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, dmrs_type::TYPE2, 1, 898, 1, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols92.dat"}, {"test_data/pusch_demodulator_test_input_estimates92.dat", {300, 14, 2, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq92.dat"}, {"test_data/pusch_demodulator_test_output92.dat"}}, - {{0.018439, 12.0363, {44327, {1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM256, 0, 14, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE2, 1, 635, 2, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols94.dat"}, {"test_data/pusch_demodulator_test_input_estimates94.dat", {300, 14, 2, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq94.dat"}, {"test_data/pusch_demodulator_test_output94.dat"}}, - {{0.0011607, 30.1039, {5270, {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM256, 1, 13, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, dmrs_type::TYPE2, 1, 470, 1, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols96.dat"}, {"test_data/pusch_demodulator_test_input_estimates96.dat", {300, 14, 4, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq96.dat"}, {"test_data/pusch_demodulator_test_output96.dat"}}, - {{0.017821, 16.2618, {2792, {1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, modulation_scheme::QAM256, 0, 8, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE2, 2, 380, 2, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols98.dat"}, {"test_data/pusch_demodulator_test_input_estimates98.dat", {300, 14, 4, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq98.dat"}, {"test_data/pusch_demodulator_test_output98.dat"}}, + {{0.016194, 20.1985, {6393, {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::PI_2_BPSK, 2, 10, {0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 128, 1, true, {0}}}, {"test_data/pusch_demodulator_test_input_symbols0.dat"}, {"test_data/pusch_demodulator_test_input_estimates0.dat", {288, 14, 1, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq0.dat"}, {"test_data/pusch_demodulator_test_output0.dat"}}, + {{0.023644, 18.2904, {29714, {{1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::PI_2_BPSK, 2, 10, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 401, 1, true, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols2.dat"}, {"test_data/pusch_demodulator_test_input_estimates2.dat", {96, 14, 2, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq2.dat"}, {"test_data/pusch_demodulator_test_output2.dat"}}, + {{0.01932, 15.3112, {35832, {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::PI_2_BPSK, 2, 7, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 881, 2, false, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols4.dat"}, {"test_data/pusch_demodulator_test_input_estimates4.dat", {144, 14, 2, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq4.dat"}, {"test_data/pusch_demodulator_test_output4.dat"}}, + {{0.0006635, 32.9662, {7320, {{1, 1, 1, 1, 1}}, modulation_scheme::PI_2_BPSK, 0, 12, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 2, 347, 1, false, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols6.dat"}, {"test_data/pusch_demodulator_test_input_estimates6.dat", {60, 14, 4, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq6.dat"}, {"test_data/pusch_demodulator_test_output6.dat"}}, + {{0.0022768, 26.4585, {52579, {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::PI_2_BPSK, 1, 11, {0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE1, 1, 9, 2, false, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols8.dat"}, {"test_data/pusch_demodulator_test_input_estimates8.dat", {240, 14, 4, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq8.dat"}, {"test_data/pusch_demodulator_test_output8.dat"}}, + {{0.0066064, 23.9641, {47998, {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::QPSK, 1, 12, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 2, 893, 1, false, {0}}}, {"test_data/pusch_demodulator_test_input_symbols10.dat"}, {"test_data/pusch_demodulator_test_input_estimates10.dat", {240, 14, 1, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq10.dat"}, {"test_data/pusch_demodulator_test_output10.dat"}}, + {{0.011268, 19.8845, {2342, {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::QPSK, 0, 8, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 693, 1, false, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols12.dat"}, {"test_data/pusch_demodulator_test_input_estimates12.dat", {300, 14, 2, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq12.dat"}, {"test_data/pusch_demodulator_test_output12.dat"}}, + {{0.0092416, 15.8933, {26738, {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::QPSK, 1, 11, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 1, 870, 2, false, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols14.dat"}, {"test_data/pusch_demodulator_test_input_estimates14.dat", {300, 14, 2, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq14.dat"}, {"test_data/pusch_demodulator_test_output14.dat"}}, + {{0.00033254, 35.9197, {41693, {{1, 1, 1, 1, 1}}, modulation_scheme::QPSK, 1, 8, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 752, 1, false, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols16.dat"}, {"test_data/pusch_demodulator_test_input_estimates16.dat", {60, 14, 4, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq16.dat"}, {"test_data/pusch_demodulator_test_output16.dat"}}, + {{0.0045049, 24.2641, {29758, {{1, 1}}, modulation_scheme::QPSK, 2, 9, {0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE1, 1, 176, 2, false, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols18.dat"}, {"test_data/pusch_demodulator_test_input_estimates18.dat", {24, 14, 4, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq18.dat"}, {"test_data/pusch_demodulator_test_output18.dat"}}, + {{0.052477, 14.9325, {57306, {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::QAM16, 0, 12, {0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 768, 1, false, {0}}}, {"test_data/pusch_demodulator_test_input_symbols20.dat"}, {"test_data/pusch_demodulator_test_input_estimates20.dat", {240, 14, 1, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq20.dat"}, {"test_data/pusch_demodulator_test_output20.dat"}}, + {{0.049126, 15.3987, {18491, {{1, 1}}, modulation_scheme::QAM16, 2, 9, {0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE1, 1, 802, 1, false, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols22.dat"}, {"test_data/pusch_demodulator_test_input_estimates22.dat", {24, 14, 2, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq22.dat"}, {"test_data/pusch_demodulator_test_output22.dat"}}, + {{0.0065728, 20.9563, {26726, {{1, 1, 1, 1, 1, 1}}, modulation_scheme::QAM16, 0, 8, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 1007, 2, false, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols24.dat"}, {"test_data/pusch_demodulator_test_input_estimates24.dat", {72, 14, 2, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq24.dat"}, {"test_data/pusch_demodulator_test_output24.dat"}}, + {{0.0052086, 23.9511, {12591, {{1, 1, 1, 1, 1, 1}}, modulation_scheme::QAM16, 0, 12, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 2, 870, 1, true, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols26.dat"}, {"test_data/pusch_demodulator_test_input_estimates26.dat", {72, 14, 4, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq26.dat"}, {"test_data/pusch_demodulator_test_output26.dat"}}, + {{0.0018408, 27.7353, {45087, {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::QAM16, 0, 12, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 1, 597, 2, false, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols28.dat"}, {"test_data/pusch_demodulator_test_input_estimates28.dat", {120, 14, 4, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq28.dat"}, {"test_data/pusch_demodulator_test_output28.dat"}}, + {{0.025555, 18.2237, {44634, {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::QAM64, 1, 9, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 528, 1, true, {0}}}, {"test_data/pusch_demodulator_test_input_symbols30.dat"}, {"test_data/pusch_demodulator_test_input_estimates30.dat", {300, 14, 1, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq30.dat"}, {"test_data/pusch_demodulator_test_output30.dat"}}, + {{0.0045558, 24.9776, {29606, {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::QAM64, 2, 12, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 2, 669, 1, true, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols32.dat"}, {"test_data/pusch_demodulator_test_input_estimates32.dat", {120, 14, 2, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq32.dat"}, {"test_data/pusch_demodulator_test_output32.dat"}}, + {{0.0023783, 23.9836, {30045, {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::QAM64, 1, 9, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 1, 795, 2, false, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols34.dat"}, {"test_data/pusch_demodulator_test_input_estimates34.dat", {192, 14, 2, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq34.dat"}, {"test_data/pusch_demodulator_test_output34.dat"}}, + {{0.00043207, 35.0645, {42119, {1}, modulation_scheme::QAM64, 2, 10, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 1, 912, 1, false, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols36.dat"}, {"test_data/pusch_demodulator_test_input_estimates36.dat", {12, 14, 4, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq36.dat"}, {"test_data/pusch_demodulator_test_output36.dat"}}, + {{0.036098, 15.0866, {43254, {{1, 1, 1, 1, 1}}, modulation_scheme::QAM64, 1, 10, {0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 491, 2, false, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols38.dat"}, {"test_data/pusch_demodulator_test_input_estimates38.dat", {60, 14, 4, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq38.dat"}, {"test_data/pusch_demodulator_test_output38.dat"}}, + {{0.0053621, 25.4388, {63880, {{1, 1}}, modulation_scheme::QAM256, 2, 8, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 250, 1, true, {0}}}, {"test_data/pusch_demodulator_test_input_symbols40.dat"}, {"test_data/pusch_demodulator_test_input_estimates40.dat", {24, 14, 1, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq40.dat"}, {"test_data/pusch_demodulator_test_output40.dat"}}, + {{0.017859, 17.8897, {7448, {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::QAM256, 0, 10, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 1, 998, 1, false, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols42.dat"}, {"test_data/pusch_demodulator_test_input_estimates42.dat", {300, 14, 2, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq42.dat"}, {"test_data/pusch_demodulator_test_output42.dat"}}, + {{0.004853, 10.3186, {64276, {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::QAM256, 2, 12, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, dmrs_type::TYPE1, 2, 825, 2, false, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols44.dat"}, {"test_data/pusch_demodulator_test_input_estimates44.dat", {144, 14, 2, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq44.dat"}, {"test_data/pusch_demodulator_test_output44.dat"}}, + {{0.0020736, 28.0302, {33013, {{1, 1, 1, 1, 1, 1}}, modulation_scheme::QAM256, 2, 9, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 88, 1, true, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols46.dat"}, {"test_data/pusch_demodulator_test_input_estimates46.dat", {72, 14, 4, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq46.dat"}, {"test_data/pusch_demodulator_test_output46.dat"}}, + {{0.0035508, 25.0019, {3768, {1}, modulation_scheme::QAM256, 0, 9, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 1, 931, 2, false, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols48.dat"}, {"test_data/pusch_demodulator_test_input_estimates48.dat", {12, 14, 4, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq48.dat"}, {"test_data/pusch_demodulator_test_output48.dat"}}, + {{0.010174, 22.2436, {48990, {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::PI_2_BPSK, 2, 9, {0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE2, 1, 888, 1, false, {0}}}, {"test_data/pusch_demodulator_test_input_symbols50.dat"}, {"test_data/pusch_demodulator_test_input_estimates50.dat", {300, 14, 1, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq50.dat"}, {"test_data/pusch_demodulator_test_output50.dat"}}, + {{0.0061508, 24.5003, {22589, {{1, 1, 1, 1}}, modulation_scheme::PI_2_BPSK, 2, 8, {0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 856, 1, true, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols52.dat"}, {"test_data/pusch_demodulator_test_input_estimates52.dat", {48, 14, 2, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq52.dat"}, {"test_data/pusch_demodulator_test_output52.dat"}}, + {{0.00086413, 29.3548, {23085, {1}, modulation_scheme::PI_2_BPSK, 2, 10, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, dmrs_type::TYPE2, 3, 983, 2, false, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols54.dat"}, {"test_data/pusch_demodulator_test_input_estimates54.dat", {12, 14, 2, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq54.dat"}, {"test_data/pusch_demodulator_test_output54.dat"}}, + {{0.0018395, 27.9189, {31255, {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::PI_2_BPSK, 2, 10, {0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 630, 1, true, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols56.dat"}, {"test_data/pusch_demodulator_test_input_estimates56.dat", {300, 14, 4, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq56.dat"}, {"test_data/pusch_demodulator_test_output56.dat"}}, + {{0.00091017, 30.4726, {58724, {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::PI_2_BPSK, 1, 11, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, dmrs_type::TYPE2, 2, 840, 2, false, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols58.dat"}, {"test_data/pusch_demodulator_test_input_estimates58.dat", {216, 14, 4, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq58.dat"}, {"test_data/pusch_demodulator_test_output58.dat"}}, + {{0.053869, 15.3704, {63790, {{1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::QPSK, 2, 9, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 579, 1, true, {0}}}, {"test_data/pusch_demodulator_test_input_symbols60.dat"}, {"test_data/pusch_demodulator_test_input_estimates60.dat", {96, 14, 1, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq60.dat"}, {"test_data/pusch_demodulator_test_output60.dat"}}, + {{0.01954, 19.0331, {63937, {{1, 1, 1}}, modulation_scheme::QPSK, 2, 12, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, dmrs_type::TYPE2, 3, 474, 1, false, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols62.dat"}, {"test_data/pusch_demodulator_test_input_estimates62.dat", {36, 14, 2, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq62.dat"}, {"test_data/pusch_demodulator_test_output62.dat"}}, + {{0.017253, 17.1841, {29327, {{1, 1}}, modulation_scheme::QPSK, 2, 7, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE2, 3, 930, 2, false, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols64.dat"}, {"test_data/pusch_demodulator_test_input_estimates64.dat", {24, 14, 2, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq64.dat"}, {"test_data/pusch_demodulator_test_output64.dat"}}, + {{0.00036783, 34.7887, {188, {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::QPSK, 0, 9, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 717, 1, true, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols66.dat"}, {"test_data/pusch_demodulator_test_input_estimates66.dat", {288, 14, 4, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq66.dat"}, {"test_data/pusch_demodulator_test_output66.dat"}}, + {{0.0014576, 28.8097, {2024, {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::QPSK, 2, 12, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE2, 1, 102, 2, false, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols68.dat"}, {"test_data/pusch_demodulator_test_input_estimates68.dat", {180, 14, 4, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq68.dat"}, {"test_data/pusch_demodulator_test_output68.dat"}}, + {{0.067817, 14.1592, {6517, {{1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::QAM16, 1, 11, {0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 90, 1, true, {0}}}, {"test_data/pusch_demodulator_test_input_symbols70.dat"}, {"test_data/pusch_demodulator_test_input_estimates70.dat", {96, 14, 1, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq70.dat"}, {"test_data/pusch_demodulator_test_output70.dat"}}, + {{0.015425, 20.413, {21290, {1}, modulation_scheme::QAM16, 2, 9, {0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 554, 1, true, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols72.dat"}, {"test_data/pusch_demodulator_test_input_estimates72.dat", {12, 14, 2, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq72.dat"}, {"test_data/pusch_demodulator_test_output72.dat"}}, + {{0.0054558, 22.1841, {7525, {{1, 1}}, modulation_scheme::QAM16, 2, 8, {0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE2, 3, 5, 2, false, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols74.dat"}, {"test_data/pusch_demodulator_test_input_estimates74.dat", {24, 14, 2, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq74.dat"}, {"test_data/pusch_demodulator_test_output74.dat"}}, + {{0.0033254, 25.9483, {62190, {{1, 1, 1, 1, 1}}, modulation_scheme::QAM16, 1, 9, {0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE2, 1, 997, 1, false, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols76.dat"}, {"test_data/pusch_demodulator_test_input_estimates76.dat", {60, 14, 4, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq76.dat"}, {"test_data/pusch_demodulator_test_output76.dat"}}, + {{0.0022862, 26.3743, {9953, {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::QAM16, 0, 11, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE2, 3, 788, 2, false, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols78.dat"}, {"test_data/pusch_demodulator_test_input_estimates78.dat", {216, 14, 4, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq78.dat"}, {"test_data/pusch_demodulator_test_output78.dat"}}, + {{0.016961, 20.1405, {64150, {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::QAM64, 1, 11, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE2, 2, 337, 1, false, {0}}}, {"test_data/pusch_demodulator_test_input_symbols80.dat"}, {"test_data/pusch_demodulator_test_input_estimates80.dat", {144, 14, 1, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq80.dat"}, {"test_data/pusch_demodulator_test_output80.dat"}}, + {{0.01954, 18.9169, {20207, {{1, 1, 1}}, modulation_scheme::QAM64, 1, 13, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, dmrs_type::TYPE2, 3, 477, 1, false, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols82.dat"}, {"test_data/pusch_demodulator_test_input_estimates82.dat", {36, 14, 2, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq82.dat"}, {"test_data/pusch_demodulator_test_output82.dat"}}, + {{0.0017253, 27.0822, {24481, {{1, 1}}, modulation_scheme::QAM64, 2, 8, {0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE2, 2, 775, 2, false, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols84.dat"}, {"test_data/pusch_demodulator_test_input_estimates84.dat", {24, 14, 2, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq84.dat"}, {"test_data/pusch_demodulator_test_output84.dat"}}, + {{0.00068004, 33.07, {55959, {{1, 1, 1}}, modulation_scheme::QAM64, 2, 11, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, dmrs_type::TYPE2, 3, 169, 1, false, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols86.dat"}, {"test_data/pusch_demodulator_test_input_estimates86.dat", {36, 14, 4, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq86.dat"}, {"test_data/pusch_demodulator_test_output86.dat"}}, + {{0.0028782, 25.0366, {13040, {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::QAM64, 0, 8, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE2, 1, 384, 2, false, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols88.dat"}, {"test_data/pusch_demodulator_test_input_estimates88.dat", {216, 14, 4, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq88.dat"}, {"test_data/pusch_demodulator_test_output88.dat"}}, + {{0.053655, 15.1483, {13654, {{1, 1, 1, 1}}, modulation_scheme::QAM256, 1, 11, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, dmrs_type::TYPE2, 3, 712, 1, false, {0}}}, {"test_data/pusch_demodulator_test_input_symbols90.dat"}, {"test_data/pusch_demodulator_test_input_estimates90.dat", {48, 14, 1, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq90.dat"}, {"test_data/pusch_demodulator_test_output90.dat"}}, + {{0.0043393, 25.1588, {10041, {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::QAM256, 1, 9, {0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0}, dmrs_type::TYPE1, 2, 707, 1, true, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols92.dat"}, {"test_data/pusch_demodulator_test_input_estimates92.dat", {144, 14, 2, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq92.dat"}, {"test_data/pusch_demodulator_test_output92.dat"}}, + {{0.015006, 16.5095, {51140, {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::QAM256, 0, 9, {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE2, 2, 718, 2, false, {0, 1}}}, {"test_data/pusch_demodulator_test_input_symbols94.dat"}, {"test_data/pusch_demodulator_test_input_estimates94.dat", {192, 14, 2, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq94.dat"}, {"test_data/pusch_demodulator_test_output94.dat"}}, + {{0.0010778, 30.8774, {9132, {{1, 1, 1}}, modulation_scheme::QAM256, 0, 7, {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, dmrs_type::TYPE2, 1, 484, 1, false, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols96.dat"}, {"test_data/pusch_demodulator_test_input_estimates96.dat", {36, 14, 4, 1}}, {"test_data/pusch_demodulator_test_output_scrambling_seq96.dat"}, {"test_data/pusch_demodulator_test_output96.dat"}}, + {{0.0058027, 22.8169, {55366, {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}, modulation_scheme::QAM256, 2, 12, {0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}, dmrs_type::TYPE2, 2, 112, 2, false, {0, 1, 2, 3}}}, {"test_data/pusch_demodulator_test_input_symbols98.dat"}, {"test_data/pusch_demodulator_test_input_estimates98.dat", {180, 14, 4, 2}}, {"test_data/pusch_demodulator_test_output_scrambling_seq98.dat"}, {"test_data/pusch_demodulator_test_output98.dat"}}, // clang-format on }; diff --git a/tests/unittests/phy/upper/channel_processors/pusch/pusch_demodulator_test_data.tar.gz b/tests/unittests/phy/upper/channel_processors/pusch/pusch_demodulator_test_data.tar.gz index c5bd79a03d..a29dc597af 100644 --- a/tests/unittests/phy/upper/channel_processors/pusch/pusch_demodulator_test_data.tar.gz +++ b/tests/unittests/phy/upper/channel_processors/pusch/pusch_demodulator_test_data.tar.gz @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3dbe7d40c49c66cd61eefe7ab24a9ea915145aab149578c26a7c27e2c8d661fb -size 7727150 +oid sha256:f0fb3a846877ce8a202e5c6c2b1a448e9271ceeec618980a31cb94712f4487e2 +size 4113238 diff --git a/tests/unittests/phy/upper/channel_processors/pusch/pusch_demodulator_vectortest.cpp b/tests/unittests/phy/upper/channel_processors/pusch/pusch_demodulator_vectortest.cpp index b84c614dfa..1800bc1c04 100644 --- a/tests/unittests/phy/upper/channel_processors/pusch/pusch_demodulator_vectortest.cpp +++ b/tests/unittests/phy/upper/channel_processors/pusch/pusch_demodulator_vectortest.cpp @@ -26,7 +26,7 @@ std::ostream& operator<<(std::ostream& os, const test_case_t& test_case) { fmt::print(os, "rnti={} rb_mask=[{}] modulation={} t_alloc={}:{} dmrs_pos=[{}] dmrs_type={} nof_cdm...data={} n_id={} " - "nof_tx_layers={} rx_ports={}", + "nof_tx_layers={} enable...precoding={} rx_ports=[{}]", test_case.context.config.rnti, test_case.context.config.rb_mask, to_string(test_case.context.config.modulation), @@ -37,6 +37,7 @@ std::ostream& operator<<(std::ostream& os, const test_case_t& test_case) test_case.context.config.nof_cdm_groups_without_data, test_case.context.config.n_id, test_case.context.config.nof_tx_layers, + test_case.context.config.enable_transform_precoding, span(test_case.context.config.rx_ports)); return os; } @@ -88,8 +89,15 @@ class PuschDemodulatorFixture : public ::testing::TestWithParam std::shared_ptr prg_factory = create_pseudo_random_generator_sw_factory(); ASSERT_TRUE(prg_factory); - std::shared_ptr pusch_demod_factory = - create_pusch_demodulator_factory_sw(equalizer_factory, demod_factory, prg_factory, true, true); + std::shared_ptr dft_factory = create_dft_processor_factory_fftw_slow(); + ASSERT_TRUE(dft_factory); + + std::shared_ptr precoding_factory = + create_dft_transform_precoder_factory(dft_factory, MAX_RB); + ASSERT_TRUE(precoding_factory); + + std::shared_ptr pusch_demod_factory = create_pusch_demodulator_factory_sw( + equalizer_factory, precoding_factory, demod_factory, prg_factory, MAX_RB, true, true); ASSERT_TRUE(pusch_demod_factory); // Create actual PUSCH demodulator. diff --git a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_unittest.cpp b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_unittest.cpp index ecd91b0ee7..8872620b66 100644 --- a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_unittest.cpp +++ b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_unittest.cpp @@ -407,6 +407,7 @@ TEST_P(PuschProcessorFixture, PuschProcessorUnittest) ASSERT_EQ(pdu.nof_cdm_groups_without_data, demodulator_entry.config.nof_cdm_groups_without_data); ASSERT_EQ(pdu.n_id, demodulator_entry.config.n_id); ASSERT_EQ(pdu.nof_tx_layers, demodulator_entry.config.nof_tx_layers); + ASSERT_EQ(false, demodulator_entry.config.enable_transform_precoding); ASSERT_EQ(span(pdu.rx_ports), span(demodulator_entry.config.rx_ports)); // Assert demux if UCI is multiplexed. diff --git a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_validator_test.cpp b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_validator_test.cpp index 673b7416e1..65b17544e9 100644 --- a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_validator_test.cpp +++ b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_validator_test.cpp @@ -217,9 +217,13 @@ class PuschProcessorFixture : public ::testing::TestWithParam std::shared_ptr eq_factory = create_channel_equalizer_generic_factory(); ASSERT_NE(eq_factory, nullptr); + std::shared_ptr precoding_factory = + create_dft_transform_precoder_factory(dft_factory, MAX_RB); + ASSERT_NE(precoding_factory, nullptr); + // Create PUSCH demodulator factory. - std::shared_ptr pusch_demod_factory = - create_pusch_demodulator_factory_sw(eq_factory, chan_modulation_factory, prg_factory); + std::shared_ptr pusch_demod_factory = create_pusch_demodulator_factory_sw( + eq_factory, precoding_factory, chan_modulation_factory, prg_factory, MAX_RB); ASSERT_NE(pusch_demod_factory, nullptr); // Create PUSCH demultiplexer factory. diff --git a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_vectortest.cpp b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_vectortest.cpp index 2436bdfcac..fa271dd20c 100644 --- a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_vectortest.cpp +++ b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_vectortest.cpp @@ -248,9 +248,15 @@ class PuschProcessorFixture : public ::testing::TestWithParam precoding_factory = + create_dft_transform_precoder_factory(dft_factory, MAX_NOF_PRBS); + if (!precoding_factory) { + return nullptr; + } + // Create PUSCH demodulator factory. - std::shared_ptr pusch_demod_factory = - create_pusch_demodulator_factory_sw(eq_factory, chan_modulation_factory, prg_factory, true, true); + std::shared_ptr pusch_demod_factory = create_pusch_demodulator_factory_sw( + eq_factory, precoding_factory, chan_modulation_factory, prg_factory, MAX_NOF_PRBS, true, true); if (!pusch_demod_factory) { return nullptr; } From 00f627582fc76483d4fe751b45395b5b7581ebff Mon Sep 17 00:00:00 2001 From: Xavier Arteaga Date: Mon, 22 Jul 2024 16:17:52 +0200 Subject: [PATCH 48/54] phy: fix PUSCH demodulator --- lib/phy/upper/upper_phy_factories.cpp | 11 ++++++++--- .../pusch/pusch_processor_benchmark.cpp | 2 +- .../pusch/pusch_processor_validator_test.cpp | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/phy/upper/upper_phy_factories.cpp b/lib/phy/upper/upper_phy_factories.cpp index 2fc6151f23..1ca1070ab6 100644 --- a/lib/phy/upper/upper_phy_factories.cpp +++ b/lib/phy/upper/upper_phy_factories.cpp @@ -422,9 +422,14 @@ static std::shared_ptr create_ul_processor_factory(con (config.log_level == srslog::basic_levels::debug); pusch_processor_factory_sw_configuration pusch_config; - pusch_config.estimator_factory = create_dmrs_pusch_estimator_factory_sw(prg_factory, ch_estimator_factory); - pusch_config.demodulator_factory = create_pusch_demodulator_factory_sw( - equalizer_factory, precoding_factory, demodulation_factory, prg_factory, enable_evm, enable_eq_sinr); + pusch_config.estimator_factory = create_dmrs_pusch_estimator_factory_sw(prg_factory, ch_estimator_factory); + pusch_config.demodulator_factory = create_pusch_demodulator_factory_sw(equalizer_factory, + precoding_factory, + demodulation_factory, + prg_factory, + config.ul_bw_rb, + enable_evm, + enable_eq_sinr); pusch_config.demux_factory = create_ulsch_demultiplex_factory_sw(); pusch_config.uci_dec_factory = uci_dec_factory; pusch_config.dec_nof_iterations = config.ldpc_decoder_iterations; diff --git a/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_processor_benchmark.cpp b/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_processor_benchmark.cpp index c4cd0827e7..5d715aa4ea 100644 --- a/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_processor_benchmark.cpp +++ b/tests/benchmarks/phy/upper/channel_processors/pusch/pusch_processor_benchmark.cpp @@ -544,7 +544,7 @@ static pusch_processor_factory& get_pusch_processor_factory() // Create PUSCH demodulator factory. std::shared_ptr pusch_demod_factory = create_pusch_demodulator_factory_sw( - eq_factory, precoding_factory, chan_modulation_factory, prg_factory, MAX_RB, enable_evm); + eq_factory, precoding_factory, chan_modulation_factory, prg_factory, MAX_RB, enable_evm, false); TESTASSERT(pusch_demod_factory); // Create PUSCH demultiplexer factory. diff --git a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_validator_test.cpp b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_validator_test.cpp index 65b17544e9..899d699dce 100644 --- a/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_validator_test.cpp +++ b/tests/unittests/phy/upper/channel_processors/pusch/pusch_processor_validator_test.cpp @@ -223,7 +223,7 @@ class PuschProcessorFixture : public ::testing::TestWithParam // Create PUSCH demodulator factory. std::shared_ptr pusch_demod_factory = create_pusch_demodulator_factory_sw( - eq_factory, precoding_factory, chan_modulation_factory, prg_factory, MAX_RB); + eq_factory, precoding_factory, chan_modulation_factory, prg_factory, MAX_RB, false, false); ASSERT_NE(pusch_demod_factory, nullptr); // Create PUSCH demultiplexer factory. From 330119158793cacbc51c16f6527c853efc9efbcf Mon Sep 17 00:00:00 2001 From: asaezper Date: Fri, 19 Jul 2024 14:47:57 +0200 Subject: [PATCH 49/54] ci,release: dynamic token by project key --- .gitlab/ci/release.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.gitlab/ci/release.yml b/.gitlab/ci/release.yml index 274341cee3..cbc8bf589b 100644 --- a/.gitlab/ci/release.yml +++ b/.gitlab/ci/release.yml @@ -46,11 +46,14 @@ load release variables: echo "PUBLIC_REPO=softwareradiosystems/srsRAN_$KEY" >> repo.env echo "HEADERS=" >> repo.env echo "PUBLIC_BRANCH=main" >> repo.env + TOKEN_VAR_NAME="PUBLIC_${KEY}_TOKEN" + echo "PUBLIC_PUSH_TOKEN=${!TOKEN_VAR_NAME}" >> repo.env else echo "PRIVATE_BRANCH=agpl_main" >> repo.env echo "PUBLIC_NAME=srsRAN Project" >> repo.env echo "PUBLIC_REPO=srsran/srsRAN_Project" >> repo.env echo "HEADERS=true" >> repo.env + echo "PUBLIC_PUSH_TOKEN=$PUBLIC_TOKEN" >> repo.env fi - cat repo.env artifacts: @@ -161,7 +164,7 @@ coverity-agpl: # Download private repo and add public as origin - git clone --branch $PRIVATE_BRANCH https://${CODEBOT_USERNAME}:${CODEBOT_TOKEN}@gitlab.com/${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}.git /${CI_PROJECT_NAME} - cd /${CI_PROJECT_NAME} - - git remote add github_public https://${PUBLIC_TOKEN}@github.com/${PUBLIC_REPO}.git + - git remote add github_public https://${PUBLIC_PUSH_TOKEN}@github.com/${PUBLIC_REPO}.git # Push code to public repo - git push github_public ${PRIVATE_BRANCH}:${PUBLIC_BRANCH} @@ -264,7 +267,7 @@ release public: - export PUBLIC_RELEASE_NOTES=${CI_COMMIT_TAG_MESSAGE} # Download public repo - - git clone --branch $PUBLIC_BRANCH https://${PUBLIC_TOKEN}@github.com/${PUBLIC_REPO}.git srsran + - git clone --branch $PUBLIC_BRANCH https://${PUBLIC_PUSH_TOKEN}@github.com/${PUBLIC_REPO}.git srsran - cd srsran # Push tag @@ -276,7 +279,7 @@ release public: RELEASE_ID=$(curl -L \ -X POST \ -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer ${PUBLIC_TOKEN}" \ + -H "Authorization: Bearer ${PUBLIC_PUSH_TOKEN}" \ -H "X-GitHub-Api-Version: 2022-11-28" \ https://api.github.com/repos/${PUBLIC_REPO}/releases \ -d "{\"tag_name\":\"${PUBLIC_TAG}\",\"target_commitish\":\"${PUBLIC_BRANCH}\",\"name\":\"${PUBLIC_RELEASE_NAME}\",\"body\":\"${PUBLIC_RELEASE_NOTES}\",\"draft\":false,\"prerelease\":false,\"generate_release_notes\":false}" | jq '.id') @@ -286,7 +289,7 @@ release public: curl -L \ -X POST \ -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer ${PUBLIC_TOKEN}" \ + -H "Authorization: Bearer ${PUBLIC_PUSH_TOKEN}" \ -H "X-GitHub-Api-Version: 2022-11-28" \ -H "Content-Type: application/octet-stream" \ https://uploads.github.com/repos/${PUBLIC_REPO}/releases/${RELEASE_ID}/assets?name=${ARTIFACT} \ From 4c7045654d118ff71511c422be9b742a82209d8d Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Wed, 17 Jul 2024 10:21:08 +0100 Subject: [PATCH 50/54] config: add nru section to example configs --- configs/cu.yml | 6 +++++- configs/du_rf_b200_tdd_n78_20mhz.yml | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/configs/cu.yml b/configs/cu.yml index 1980a7ca29..1e11e89f6a 100644 --- a/configs/cu.yml +++ b/configs/cu.yml @@ -7,10 +7,14 @@ cu_cp: f1ap: bind_addr: 127.0.10.1 +cu_up: + nru: + bind_addr: 127.0.10.1 + log: filename: /tmp/cu.log all_level: warning pcap: ngap_enable: false - ngap_filename: /tmp/cu_ngap.pcap \ No newline at end of file + ngap_filename: /tmp/cu_ngap.pcap diff --git a/configs/du_rf_b200_tdd_n78_20mhz.yml b/configs/du_rf_b200_tdd_n78_20mhz.yml index 7bda39ed29..7d2f498af7 100644 --- a/configs/du_rf_b200_tdd_n78_20mhz.yml +++ b/configs/du_rf_b200_tdd_n78_20mhz.yml @@ -2,6 +2,8 @@ f1ap: cu_cp_addr: 127.0.10.1 bind_addr: 127.0.10.2 +nru: + bind_addr: 127.0.10.2 ru_sdr: device_driver: uhd @@ -30,4 +32,4 @@ pcap: f1ap_enable: false f1ap_filename: /tmp/du_f1ap.pcap f1u_enable: false - f1u_filename: /tmp/du_f1u.pcap \ No newline at end of file + f1u_filename: /tmp/du_f1u.pcap From 5121495ed3b510adc64bbd7e2fb8cfc85ac6f534 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 19 Jul 2024 15:36:47 +0200 Subject: [PATCH 51/54] du-high: do now warn on RLF detection when the UE context release is already under way --- lib/du_manager/du_ue/du_ue_controller_impl.cpp | 8 ++++---- lib/mac/mac_sched/rlf_detector.h | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/du_manager/du_ue/du_ue_controller_impl.cpp b/lib/du_manager/du_ue/du_ue_controller_impl.cpp index f2e95ab579..db9ab396bc 100644 --- a/lib/du_manager/du_ue/du_ue_controller_impl.cpp +++ b/lib/du_manager/du_ue/du_ue_controller_impl.cpp @@ -152,10 +152,10 @@ class srsran::srs_du::du_ue_controller_impl::rlf_state_machine // The release timer is not running yet. We need to store the cause and start the timer. current_cause = cause; auto timeout_val = get_release_timeout(); - logger.info("ue={}: RLF detected with cause=\"{}\". Timer of {} msec to release UE started...", - ue_ctx.ue_index, - get_rlf_cause_str(cause), - timeout_val.count()); + logger.warning("ue={}: RLF detected with cause=\"{}\". Timer of {} msec to release UE started...", + ue_ctx.ue_index, + get_rlf_cause_str(cause), + timeout_val.count()); // Start timer. release_timer.set(timeout_val, [this](timer_id_t tid) { trigger_ue_release(); }); diff --git a/lib/mac/mac_sched/rlf_detector.h b/lib/mac/mac_sched/rlf_detector.h index 61fdc7d268..e1f4b6110e 100644 --- a/lib/mac/mac_sched/rlf_detector.h +++ b/lib/mac/mac_sched/rlf_detector.h @@ -90,7 +90,7 @@ class rlf_detector if (current_count == max_consecutive_kos[cell_index].max_consecutive_csi_dtx) { std::lock_guard lock(u.notifier_mutex); if (u.notifier != nullptr) { - logger.warning("ue={}: RLF detected. Cause: {} consecutive undecoded CSIs", ue_index, current_count); + logger.info("ue={}: RLF detected. Cause: {} consecutive undecoded CSIs", ue_index, current_count); // Notify upper layers. u.notifier->on_rlf_detected(); @@ -127,10 +127,10 @@ class rlf_detector if (current_count == max_counter) { std::lock_guard lock(u.notifier_mutex); if (u.notifier != nullptr) { - logger.warning("ue={}: RLF detected. Cause: {} consecutive {} KOs.", - ue_index, - current_count, - is_dl ? "HARQ-ACK" : "CRC"); + logger.info("ue={}: RLF detected. Cause: {} consecutive {} KOs.", + ue_index, + current_count, + is_dl ? "HARQ-ACK" : "CRC"); // Notify upper layers. u.notifier->on_rlf_detected(); From 375e2fca2b6ff73bbaf932cc078f124c92f6486a Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 19 Jul 2024 10:32:17 +0200 Subject: [PATCH 52/54] cu-cp: implementation of class for handing paging messages --- lib/cu_cp/CMakeLists.txt | 1 + lib/cu_cp/adapters/ngap_adapters.h | 15 ++-- lib/cu_cp/cu_cp_impl.cpp | 3 +- lib/cu_cp/cu_cp_impl.h | 4 + lib/cu_cp/du_processor/du_processor.h | 4 + lib/cu_cp/du_processor/du_processor_impl.h | 5 +- lib/cu_cp/paging/paging_message_handler.cpp | 85 +++++++++++++++++++++ lib/cu_cp/paging/paging_message_handler.h | 37 +++++++++ 8 files changed, 144 insertions(+), 10 deletions(-) create mode 100644 lib/cu_cp/paging/paging_message_handler.cpp create mode 100644 lib/cu_cp/paging/paging_message_handler.h diff --git a/lib/cu_cp/CMakeLists.txt b/lib/cu_cp/CMakeLists.txt index e3213effef..f3dbf461be 100644 --- a/lib/cu_cp/CMakeLists.txt +++ b/lib/cu_cp/CMakeLists.txt @@ -47,6 +47,7 @@ set(SOURCES ue_manager/cu_cp_ue_impl.cpp ue_manager/ue_manager_impl.cpp ue_manager/ue_task_scheduler_impl.cpp + paging/paging_message_handler.cpp ) add_library(srsran_cu_cp STATIC ${SOURCES}) diff --git a/lib/cu_cp/adapters/ngap_adapters.h b/lib/cu_cp/adapters/ngap_adapters.h index de2b4e3fb0..13cb572b7c 100644 --- a/lib/cu_cp/adapters/ngap_adapters.h +++ b/lib/cu_cp/adapters/ngap_adapters.h @@ -12,6 +12,7 @@ #include "../cu_cp_impl_interface.h" #include "../du_processor/du_processor.h" +#include "../paging/paging_message_handler.h" #include "../ue_manager/cu_cp_ue_impl_interface.h" #include "srsran/cu_cp/ue_task_scheduler.h" #include "srsran/ngap/ngap.h" @@ -26,16 +27,16 @@ class ngap_cu_cp_adapter : public ngap_cu_cp_du_repository_notifier, public ngap public: explicit ngap_cu_cp_adapter() = default; - void connect_cu_cp(du_repository_ngap_handler& du_repository_handler_, cu_cp_ngap_handler& cu_cp_handler_) + void connect_cu_cp(cu_cp_ngap_handler& cu_cp_handler_, paging_message_handler& paging_handler_) { - du_repository_handler = &du_repository_handler_; - cu_cp_handler = &cu_cp_handler_; + cu_cp_handler = &cu_cp_handler_; + paging_handler = &paging_handler_; } void on_paging_message(cu_cp_paging_message& msg) override { - srsran_assert(du_repository_handler != nullptr, "CU-CP Paging handler must not be nullptr"); - du_repository_handler->handle_paging_message(msg); + srsran_assert(paging_handler != nullptr, "CU-CP Paging handler must not be nullptr"); + paging_handler->handle_paging_message(msg); } async_task @@ -117,8 +118,8 @@ class ngap_cu_cp_adapter : public ngap_cu_cp_du_repository_notifier, public ngap } private: - du_repository_ngap_handler* du_repository_handler = nullptr; - cu_cp_ngap_handler* cu_cp_handler = nullptr; + cu_cp_ngap_handler* cu_cp_handler = nullptr; + paging_message_handler* paging_handler = nullptr; }; /// Adapter between NGAP and CU-CP UE diff --git a/lib/cu_cp/cu_cp_impl.cpp b/lib/cu_cp/cu_cp_impl.cpp index 190b51cae8..6361952bf0 100644 --- a/lib/cu_cp/cu_cp_impl.cpp +++ b/lib/cu_cp/cu_cp_impl.cpp @@ -65,13 +65,14 @@ cu_cp_impl::cu_cp_impl(const cu_cp_configuration& config_) : conn_notifier, srslog::fetch_basic_logger("CU-CP")}), cu_up_db(cu_up_repository_config{cfg, e1ap_ev_notifier, srslog::fetch_basic_logger("CU-CP")}), + paging_handler(du_db), metrics_hdlr( std::make_unique(*cfg.services.cu_cp_executor, *cfg.services.timers, ue_mng, du_db)) { assert_cu_cp_configuration_valid(cfg); // connect event notifiers to layers - ngap_cu_cp_ev_notifier.connect_cu_cp(du_db, *this); + ngap_cu_cp_ev_notifier.connect_cu_cp(*this, paging_handler); mobility_manager_ev_notifier.connect_cu_cp(get_cu_cp_mobility_manager_handler()); e1ap_ev_notifier.connect_cu_cp(get_cu_cp_e1ap_handler()); rrc_du_cu_cp_notifier.connect_cu_cp(get_cu_cp_measurement_config_handler()); diff --git a/lib/cu_cp/cu_cp_impl.h b/lib/cu_cp/cu_cp_impl.h index 65577d41f0..2d2f7b30ee 100644 --- a/lib/cu_cp/cu_cp_impl.h +++ b/lib/cu_cp/cu_cp_impl.h @@ -22,6 +22,7 @@ #include "cu_cp_impl_interface.h" #include "cu_up_processor/cu_up_processor_repository.h" #include "du_processor/du_processor_repository.h" +#include "paging/paging_message_handler.h" #include "routine_managers/cu_cp_routine_manager.h" #include "ue_manager/ue_manager_impl.h" #include "srsran/cu_cp/cu_cp_configuration.h" @@ -192,6 +193,9 @@ class cu_cp_impl final : public cu_cp, // CU-UP connections being managed by the CU-CP. cu_up_processor_repository cu_up_db; + // Handler of paging messages. + paging_message_handler paging_handler; + // Handler of the CU-CP connections to other remote nodes (e.g. AMF, CU-UPs, DUs). std::unique_ptr controller; diff --git a/lib/cu_cp/du_processor/du_processor.h b/lib/cu_cp/du_processor/du_processor.h index 07723880f8..bc460f94df 100644 --- a/lib/cu_cp/du_processor/du_processor.h +++ b/lib/cu_cp/du_processor/du_processor.h @@ -10,6 +10,7 @@ #pragma once +#include "du_configuration_handler.h" #include "du_metrics_handler.h" #include "srsran/adt/static_vector.h" #include "srsran/f1ap/cu_cp/f1ap_cu.h" @@ -68,6 +69,9 @@ class du_processor_cell_info_interface /// \brief Checks whether a cell with the specified NR cell global id is served by the DU. virtual bool has_cell(nr_cell_global_id_t cgi) = 0; + + /// \brief Get DU configuration context. + virtual const du_configuration_context& get_context() const = 0; }; /// Interface to notify RRC DU about UE management procedures. diff --git a/lib/cu_cp/du_processor/du_processor_impl.h b/lib/cu_cp/du_processor/du_processor_impl.h index 054a7b743e..5b14be801d 100644 --- a/lib/cu_cp/du_processor/du_processor_impl.h +++ b/lib/cu_cp/du_processor/du_processor_impl.h @@ -57,8 +57,9 @@ class du_processor_impl : public du_processor, void handle_paging_message(cu_cp_paging_message& msg) override; // du_processor_cell_info_interface - bool has_cell(pci_t pci) override; - bool has_cell(nr_cell_global_id_t cgi) override; + bool has_cell(pci_t pci) override; + bool has_cell(nr_cell_global_id_t cgi) override; + const du_configuration_context& get_context() const override { return cfg.du_cfg_hdlr->get_context(); } metrics_report::du_info handle_du_metrics_report_request() const override; diff --git a/lib/cu_cp/paging/paging_message_handler.cpp b/lib/cu_cp/paging/paging_message_handler.cpp new file mode 100644 index 0000000000..1be410a413 --- /dev/null +++ b/lib/cu_cp/paging/paging_message_handler.cpp @@ -0,0 +1,85 @@ +/* + * + * 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 "paging_message_handler.h" +#include "../du_processor/du_processor_repository.h" +#include "srsran/cu_cp/cu_cp_types.h" + +using namespace srsran; +using namespace srs_cu_cp; + +paging_message_handler::paging_message_handler(du_processor_repository& dus_) : + dus(dus_), logger(srslog::fetch_basic_logger("CU-CP")) +{ +} + +void paging_message_handler::handle_paging_message(const cu_cp_paging_message& msg) +{ + // Forward paging message to all DU processors + bool paging_sent = false; + for (unsigned i = 0; i != dus.get_nof_dus(); ++i) { + paging_sent |= handle_du_paging_message(uint_to_du_index(i), msg); + } + + if (not paging_sent) { + logger.warning("No DU processor was able to handle the paging message"); + } +} + +bool paging_message_handler::handle_du_paging_message(du_index_t du_index, const cu_cp_paging_message& msg_before) +{ + du_processor& du = dus.get_du_processor(du_index); + const du_configuration_context& du_cfg = du.get_context(); + + // Recommended cells will be added to the original paging message. + cu_cp_paging_message msg_expanded{msg_before}; + if (not msg_expanded.assist_data_for_paging.has_value()) { + msg_expanded.assist_data_for_paging.emplace(); + } + if (not msg_expanded.assist_data_for_paging.value().assist_data_for_recommended_cells.has_value()) { + msg_expanded.assist_data_for_paging.value().assist_data_for_recommended_cells.emplace(); + } + auto& recommended_cells = msg_expanded.assist_data_for_paging.value() + .assist_data_for_recommended_cells.value() + .recommended_cells_for_paging.recommended_cell_list; + + for (const auto& tai_list_item : msg_expanded.tai_list_for_paging) { + for (const du_cell_configuration& cell : du_cfg.served_cells) { + if (cell.tac != tai_list_item.tai.tac) { + // Only add cells with matching TAC. + continue; + } + + // Check if cell already exists in the list of recommended. + for (auto& recommended_cell : recommended_cells) { + if (recommended_cell.ngran_cgi == cell.cgi) { + // NR CGI for TAC is already present. Continue with next cell. + continue; + break; + } + } + + // Setup recommended cell item to add in case it doesn't exist + cu_cp_recommended_cell_item cell_item; + cell_item.ngran_cgi = cell.cgi; + recommended_cells.push_back(cell_item); + } + } + + if (recommended_cells.empty()) { + logger.info("du={}: No cells with matching TAC available at this DU", du_index); + return false; + } + + // Forward message to F1AP of the respective DU. + du.get_f1ap_handler().get_f1ap_paging_manager().handle_paging(msg_expanded); + + return true; +} diff --git a/lib/cu_cp/paging/paging_message_handler.h b/lib/cu_cp/paging/paging_message_handler.h new file mode 100644 index 0000000000..2c3382f509 --- /dev/null +++ b/lib/cu_cp/paging/paging_message_handler.h @@ -0,0 +1,37 @@ +/* + * + * 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/cu_cp/cu_cp_types.h" + +namespace srsran { +namespace srs_cu_cp { + +class du_processor_repository; +struct cu_cp_paging_message; + +/// Class responsible for handling incoming paging messages and forwarding them to the appropriate DUs. +class paging_message_handler +{ +public: + paging_message_handler(du_processor_repository& dus_); + + void handle_paging_message(const cu_cp_paging_message& msg); + +private: + bool handle_du_paging_message(du_index_t du_index, const cu_cp_paging_message& msg); + + du_processor_repository& dus; + srslog::basic_logger& logger; +}; + +} // namespace srs_cu_cp +} // namespace srsran \ No newline at end of file From eaf2cf1032036f48d62195768aa6928ddf725e4c Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 19 Jul 2024 10:49:33 +0200 Subject: [PATCH 53/54] cu-cp: remove unused paging code from du_processor_impl --- lib/cu_cp/adapters/du_processor_adapters.h | 21 ---- lib/cu_cp/du_processor/du_processor.h | 22 ----- lib/cu_cp/du_processor/du_processor_impl.cpp | 95 ------------------- lib/cu_cp/du_processor/du_processor_impl.h | 12 +-- .../du_processor/du_processor_repository.cpp | 8 -- .../du_processor/du_processor_repository.h | 4 +- lib/cu_cp/paging/paging_message_handler.h | 4 +- 7 files changed, 5 insertions(+), 161 deletions(-) diff --git a/lib/cu_cp/adapters/du_processor_adapters.h b/lib/cu_cp/adapters/du_processor_adapters.h index e75694b685..3bac60a81c 100644 --- a/lib/cu_cp/adapters/du_processor_adapters.h +++ b/lib/cu_cp/adapters/du_processor_adapters.h @@ -110,27 +110,6 @@ class du_processor_f1ap_ue_context_adapter : public du_processor_f1ap_ue_context f1ap_ue_context_manager* handler = nullptr; }; -// Adapter between DU processor and F1AP for Paging -class du_processor_f1ap_paging_adapter : public du_processor_f1ap_paging_notifier -{ -public: - du_processor_f1ap_paging_adapter() = default; - - void connect_f1(f1ap_paging_manager& handler_) { handler = &handler_; } - - void on_paging_message(const cu_cp_paging_message& msg) override - { - if (handler == nullptr) { - srslog::fetch_basic_logger("CU-CP").info("DU not connected - dropping paging message"); - return; - } - handler->handle_paging(msg); - } - -private: - f1ap_paging_manager* handler = nullptr; -}; - // Adapter between DU processor and RRC DU class du_processor_rrc_du_adapter : public du_processor_rrc_du_ue_notifier { diff --git a/lib/cu_cp/du_processor/du_processor.h b/lib/cu_cp/du_processor/du_processor.h index bc460f94df..8f760df74a 100644 --- a/lib/cu_cp/du_processor/du_processor.h +++ b/lib/cu_cp/du_processor/du_processor.h @@ -222,27 +222,6 @@ class du_processor_cu_cp_notifier virtual async_task on_transaction_info_loss(const f1_ue_transaction_info_loss_event& ev) = 0; }; -/// DU processor Paging handler. -class du_processor_paging_handler -{ -public: - virtual ~du_processor_paging_handler() = default; - - /// \brief Handles a Paging message. - virtual void handle_paging_message(cu_cp_paging_message& msg) = 0; -}; - -/// Interface for the NGAP to interface with the DU repository -/// Useful for paging and handover -class du_repository_ngap_handler -{ -public: - virtual ~du_repository_ngap_handler() = default; - - /// \brief Handles a Paging message notification. - virtual void handle_paging_message(cu_cp_paging_message& msg) = 0; -}; - class du_processor : public du_processor_cell_info_interface { public: @@ -251,7 +230,6 @@ class du_processor : public du_processor_cell_info_interface /// \brief Retrieve F1AP handler for the respective DU. virtual f1ap_cu& get_f1ap_handler() = 0; - virtual du_processor_paging_handler& get_paging_handler() = 0; virtual du_processor_mobility_handler& get_mobility_handler() = 0; /// \brief Get the F1AP message handler interface of the DU processor object. diff --git a/lib/cu_cp/du_processor/du_processor_impl.cpp b/lib/cu_cp/du_processor/du_processor_impl.cpp index afc412bad7..07e1af1576 100644 --- a/lib/cu_cp/du_processor/du_processor_impl.cpp +++ b/lib/cu_cp/du_processor/du_processor_impl.cpp @@ -135,19 +135,6 @@ du_setup_result du_processor_impl::handle_du_setup_request(const du_setup_reques return res; } - const du_configuration_context& du_config = cfg.du_cfg_hdlr->get_context(); - for (const du_cell_configuration& cell : du_config.served_cells) { - // Add cell to lookup - if (tac_to_nr_cgi.find(cell.tac) == tac_to_nr_cgi.end()) { - tac_to_nr_cgi.emplace(cell.tac, std::vector{cell.cgi}); - } else { - tac_to_nr_cgi.at(cell.tac).push_back(cell.cgi); - } - } - - // connect paging f1ap paging adapter - f1ap_paging_notifier.connect_f1(f1ap->get_f1ap_paging_manager()); - // Prepare DU response with accepted setup. auto& accepted = res.result.emplace(); accepted.gnb_cu_name = cfg.cu_cp_cfg.node.ran_node_name; @@ -287,88 +274,6 @@ void du_processor_impl::handle_du_initiated_ue_context_release_request(const f1a })); } -void du_processor_impl::handle_paging_message(cu_cp_paging_message& msg) -{ - // Add assist data for paging - // This will go through all tai items in the paging message and add the related NR CGI to the assist data for paging - // if it doesn't exist yet. - // This way the F1AP will always receive messages with the assist data for paging set. - - bool nr_cgi_for_tac_found = false; - - for (const auto& tai_list_item : msg.tai_list_for_paging) { - if (tac_to_nr_cgi.find(tai_list_item.tai.tac) == tac_to_nr_cgi.end()) { - logger.debug("Could not find nr cgi for tac={}", tai_list_item.tai.tac); - continue; - } - - nr_cgi_for_tac_found = true; - - for (const auto& cgi : tac_to_nr_cgi.at(tai_list_item.tai.tac)) { - // Setup recommended cell item to add in case it doesn't exist - cu_cp_recommended_cell_item cell_item; - cell_item.ngran_cgi = cgi; - - // Check if assist data for paging is already present - if (msg.assist_data_for_paging.has_value()) { - // Check if assist data for recommended cells is already present - if (msg.assist_data_for_paging.value().assist_data_for_recommended_cells.has_value()) { - // Check if recommended cell list already contains values - if (!msg.assist_data_for_paging.value() - .assist_data_for_recommended_cells.value() - .recommended_cells_for_paging.recommended_cell_list.empty()) { - // Check if NR CGI already present - bool is_present = false; - for (const auto& present_cell_item : msg.assist_data_for_paging.value() - .assist_data_for_recommended_cells.value() - .recommended_cells_for_paging.recommended_cell_list) { - if (present_cell_item.ngran_cgi.nci == cgi.nci) { - is_present = true; - continue; - } - } - if (is_present) { - // NR CGI for TAC is already present - continue; - } - } - - // NR CGI for TAC is not present so we add it - msg.assist_data_for_paging.value() - .assist_data_for_recommended_cells.value() - .recommended_cells_for_paging.recommended_cell_list.push_back(cell_item); - } else { - // Assist data for recommended cells is not present, we need to add it - cu_cp_assist_data_for_recommended_cells assist_data_for_recommended_cells; - assist_data_for_recommended_cells.recommended_cells_for_paging.recommended_cell_list.push_back(cell_item); - - msg.assist_data_for_paging.value().assist_data_for_recommended_cells = assist_data_for_recommended_cells; - } - } else { - // Assist data for paging is not present, we need to add it - cu_cp_assist_data_for_paging assist_data_for_paging; - - // Add assist data for recommended cells - cu_cp_assist_data_for_recommended_cells assist_data_for_recommended_cells; - // Add cell item - assist_data_for_recommended_cells.recommended_cells_for_paging.recommended_cell_list.push_back(cell_item); - - assist_data_for_paging.assist_data_for_recommended_cells = assist_data_for_recommended_cells; - - msg.assist_data_for_paging = assist_data_for_paging; - } - } - } - - // If not nr cgi for a tac from the paging message is found paging message is not forwarded to DU - if (!nr_cgi_for_tac_found) { - logger.info("du_index={}: No NR CGI for paging TACs available at this DU", cfg.du_index); - return; - } - - f1ap_paging_notifier.on_paging_message(msg); -} - bool du_processor_impl::has_cell(pci_t pci) { return cfg.du_cfg_hdlr->get_context().find_cell(pci) != nullptr; diff --git a/lib/cu_cp/du_processor/du_processor_impl.h b/lib/cu_cp/du_processor/du_processor_impl.h index 5b14be801d..9ba29d5894 100644 --- a/lib/cu_cp/du_processor/du_processor_impl.h +++ b/lib/cu_cp/du_processor/du_processor_impl.h @@ -27,10 +27,7 @@ namespace srsran { namespace srs_cu_cp { -class du_processor_impl : public du_processor, - public du_metrics_handler, - public du_processor_paging_handler, - public du_processor_mobility_handler +class du_processor_impl : public du_processor, public du_metrics_handler, public du_processor_mobility_handler { public: du_processor_impl(du_processor_config_t du_processor_config_, @@ -53,9 +50,6 @@ class du_processor_impl : public du_processor, std::optional get_cgi(pci_t pci) override; byte_buffer get_packed_sib1(nr_cell_global_id_t cgi) override; - // du_processor paging handler - void handle_paging_message(cu_cp_paging_message& msg) override; - // du_processor_cell_info_interface bool has_cell(pci_t pci) override; bool has_cell(nr_cell_global_id_t cgi) override; @@ -63,7 +57,6 @@ class du_processor_impl : public du_processor, metrics_report::du_info handle_du_metrics_report_request() const override; - du_processor_paging_handler& get_paging_handler() override { return *this; } du_processor_mobility_handler& get_mobility_handler() override { return *this; } du_processor_f1ap_ue_context_notifier& get_f1ap_ue_context_notifier() override { return f1ap_ue_context_notifier; } du_metrics_handler& get_metrics_handler() override { return *this; } @@ -100,13 +93,10 @@ class du_processor_impl : public du_processor, rrc_ue_nas_notifier& rrc_ue_nas_pdu_notifier; ue_manager& ue_mng; du_processor_f1ap_ue_context_adapter f1ap_ue_context_notifier; - du_processor_f1ap_paging_adapter f1ap_paging_notifier; // F1AP to DU processor adapter std::unique_ptr f1ap_ev_notifier; - std::map> tac_to_nr_cgi; - // F1AP to RRC UE adapters std::unordered_map f1ap_rrc_ue_adapters; diff --git a/lib/cu_cp/du_processor/du_processor_repository.cpp b/lib/cu_cp/du_processor/du_processor_repository.cpp index 55a53bd577..8561e8c5e7 100644 --- a/lib/cu_cp/du_processor/du_processor_repository.cpp +++ b/lib/cu_cp/du_processor/du_processor_repository.cpp @@ -133,14 +133,6 @@ du_processor& du_processor_repository::get_du_processor(du_index_t du_index) return *du_db.at(du_index).processor; } -void du_processor_repository::handle_paging_message(cu_cp_paging_message& msg) -{ - // Forward paging message to all DU processors - for (auto& du : du_db) { - du.second.processor->get_paging_handler().handle_paging_message(msg); - } -} - std::vector du_processor_repository::handle_du_metrics_report_request() const { std::vector du_reports; diff --git a/lib/cu_cp/du_processor/du_processor_repository.h b/lib/cu_cp/du_processor/du_processor_repository.h index 8f82115c7d..72762f930e 100644 --- a/lib/cu_cp/du_processor/du_processor_repository.h +++ b/lib/cu_cp/du_processor/du_processor_repository.h @@ -42,7 +42,7 @@ struct du_repository_config { srslog::basic_logger& logger; }; -class du_processor_repository : public du_repository_ngap_handler, public du_repository_metrics_handler +class du_processor_repository : public du_repository_metrics_handler { public: explicit du_processor_repository(du_repository_config cfg_); @@ -59,8 +59,6 @@ class du_processor_repository : public du_repository_ngap_handler, public du_rep du_processor& get_du_processor(du_index_t du_index); - void handle_paging_message(cu_cp_paging_message& msg) override; - std::vector handle_du_metrics_report_request() const override; size_t get_nof_f1ap_ues(); diff --git a/lib/cu_cp/paging/paging_message_handler.h b/lib/cu_cp/paging/paging_message_handler.h index 2c3382f509..62c4dce96b 100644 --- a/lib/cu_cp/paging/paging_message_handler.h +++ b/lib/cu_cp/paging/paging_message_handler.h @@ -11,6 +11,7 @@ #pragma once #include "srsran/cu_cp/cu_cp_types.h" +#include "srsran/srslog/logger.h" namespace srsran { namespace srs_cu_cp { @@ -24,6 +25,7 @@ class paging_message_handler public: paging_message_handler(du_processor_repository& dus_); + /// Handle Paging message sent by the core network and distribute across the served DU cells. void handle_paging_message(const cu_cp_paging_message& msg); private: @@ -34,4 +36,4 @@ class paging_message_handler }; } // namespace srs_cu_cp -} // namespace srsran \ No newline at end of file +} // namespace srsran From 807e0b93fc9dcc6e86d167bc553dc8a4ebf63889 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 19 Jul 2024 12:30:36 +0200 Subject: [PATCH 54/54] cu-cp: fix failing cu-cp paging tests --- lib/cu_cp/du_processor/du_processor.h | 2 +- lib/cu_cp/du_processor/du_processor_impl.h | 5 +- lib/cu_cp/paging/paging_message_handler.cpp | 84 ++++++++++++++------- 3 files changed, 61 insertions(+), 30 deletions(-) diff --git a/lib/cu_cp/du_processor/du_processor.h b/lib/cu_cp/du_processor/du_processor.h index 8f760df74a..d900232860 100644 --- a/lib/cu_cp/du_processor/du_processor.h +++ b/lib/cu_cp/du_processor/du_processor.h @@ -71,7 +71,7 @@ class du_processor_cell_info_interface virtual bool has_cell(nr_cell_global_id_t cgi) = 0; /// \brief Get DU configuration context. - virtual const du_configuration_context& get_context() const = 0; + virtual const du_configuration_context* get_context() const = 0; }; /// Interface to notify RRC DU about UE management procedures. diff --git a/lib/cu_cp/du_processor/du_processor_impl.h b/lib/cu_cp/du_processor/du_processor_impl.h index 9ba29d5894..d73390b6ca 100644 --- a/lib/cu_cp/du_processor/du_processor_impl.h +++ b/lib/cu_cp/du_processor/du_processor_impl.h @@ -53,7 +53,10 @@ class du_processor_impl : public du_processor, public du_metrics_handler, public // du_processor_cell_info_interface bool has_cell(pci_t pci) override; bool has_cell(nr_cell_global_id_t cgi) override; - const du_configuration_context& get_context() const override { return cfg.du_cfg_hdlr->get_context(); } + const du_configuration_context* get_context() const override + { + return cfg.du_cfg_hdlr->has_context() ? &cfg.du_cfg_hdlr->get_context() : nullptr; + } metrics_report::du_info handle_du_metrics_report_request() const override; diff --git a/lib/cu_cp/paging/paging_message_handler.cpp b/lib/cu_cp/paging/paging_message_handler.cpp index 1be410a413..fe9d7fe7a2 100644 --- a/lib/cu_cp/paging/paging_message_handler.cpp +++ b/lib/cu_cp/paging/paging_message_handler.cpp @@ -33,44 +33,72 @@ void paging_message_handler::handle_paging_message(const cu_cp_paging_message& m } } +static bool is_tac_in_list(span tai_list, unsigned tac) +{ + return std::any_of(tai_list.begin(), tai_list.end(), [&tac](const auto& tai) { return tai.tai.tac == tac; }); +} + +/// Remove recommended cells that do not match any TAC in the TAI list or that do not belong to this DU. +static void remove_non_applicable_recommended_cells(cu_cp_paging_message& msg, const du_configuration_context& du_cfg) +{ + auto& recommended_cells = msg.assist_data_for_paging.value() + .assist_data_for_recommended_cells.value() + .recommended_cells_for_paging.recommended_cell_list; + + auto is_bad_recommended_cell = [&](const cu_cp_recommended_cell_item& recommended_cell) { + auto cell_it = std::find_if(du_cfg.served_cells.begin(), + du_cfg.served_cells.end(), + [&recommended_cell](const auto& c) { return recommended_cell.ngran_cgi == c.cgi; }); + if (cell_it == du_cfg.served_cells.end()) { + // Recommended cell not found for this DU. + return true; + } + return not is_tac_in_list(msg.tai_list_for_paging, cell_it->tac); + }; + + recommended_cells.erase(std::remove_if(recommended_cells.begin(), recommended_cells.end(), is_bad_recommended_cell), + recommended_cells.end()); +} + bool paging_message_handler::handle_du_paging_message(du_index_t du_index, const cu_cp_paging_message& msg_before) { du_processor& du = dus.get_du_processor(du_index); - const du_configuration_context& du_cfg = du.get_context(); + const du_configuration_context* du_cfg = du.get_context(); + if (du_cfg == nullptr) { + // DU has not completed F1 Setup. + return false; + } // Recommended cells will be added to the original paging message. - cu_cp_paging_message msg_expanded{msg_before}; - if (not msg_expanded.assist_data_for_paging.has_value()) { - msg_expanded.assist_data_for_paging.emplace(); + cu_cp_paging_message msg_filtered{msg_before}; + if (not msg_filtered.assist_data_for_paging.has_value()) { + msg_filtered.assist_data_for_paging.emplace(); } - if (not msg_expanded.assist_data_for_paging.value().assist_data_for_recommended_cells.has_value()) { - msg_expanded.assist_data_for_paging.value().assist_data_for_recommended_cells.emplace(); + if (not msg_filtered.assist_data_for_paging.value().assist_data_for_recommended_cells.has_value()) { + msg_filtered.assist_data_for_paging.value().assist_data_for_recommended_cells.emplace(); } - auto& recommended_cells = msg_expanded.assist_data_for_paging.value() + auto& recommended_cells = msg_filtered.assist_data_for_paging.value() .assist_data_for_recommended_cells.value() .recommended_cells_for_paging.recommended_cell_list; - for (const auto& tai_list_item : msg_expanded.tai_list_for_paging) { - for (const du_cell_configuration& cell : du_cfg.served_cells) { - if (cell.tac != tai_list_item.tai.tac) { - // Only add cells with matching TAC. - continue; - } - - // Check if cell already exists in the list of recommended. - for (auto& recommended_cell : recommended_cells) { - if (recommended_cell.ngran_cgi == cell.cgi) { - // NR CGI for TAC is already present. Continue with next cell. - continue; - break; - } - } - - // Setup recommended cell item to add in case it doesn't exist - cu_cp_recommended_cell_item cell_item; - cell_item.ngran_cgi = cell.cgi; - recommended_cells.push_back(cell_item); + // Clear recommended cells not matching any TAC in the tai_list_for_paging or that do not belong to this DU. + remove_non_applicable_recommended_cells(msg_filtered, *du_cfg); + + for (const du_cell_configuration& cell : du_cfg->served_cells) { + // Check if cell already exists in the list of recommended. + if (std::any_of(recommended_cells.begin(), recommended_cells.end(), [&cell](const auto& c) { + return c.ngran_cgi == cell.cgi; + })) { + continue; } + if (not is_tac_in_list(msg_filtered.tai_list_for_paging, cell.tac)) { + continue; + } + + // Setup recommended cell item to add in case it doesn't exist + cu_cp_recommended_cell_item cell_item; + cell_item.ngran_cgi = cell.cgi; + recommended_cells.push_back(cell_item); } if (recommended_cells.empty()) { @@ -79,7 +107,7 @@ bool paging_message_handler::handle_du_paging_message(du_index_t du_index, const } // Forward message to F1AP of the respective DU. - du.get_f1ap_handler().get_f1ap_paging_manager().handle_paging(msg_expanded); + du.get_f1ap_handler().get_f1ap_paging_manager().handle_paging(msg_filtered); return true; }