diff --git a/srsgnb/hdr/stack/mac/sched_nr_pdcch.h b/srsgnb/hdr/stack/mac/sched_nr_pdcch.h index 070671b5c..48daac54c 100644 --- a/srsgnb/hdr/stack/mac/sched_nr_pdcch.h +++ b/srsgnb/hdr/stack/mac/sched_nr_pdcch.h @@ -13,6 +13,7 @@ #ifndef SRSRAN_SCHED_NR_PDCCH_H #define SRSRAN_SCHED_NR_PDCCH_H +#include "srsenb/hdr/stack/mac/sched_common.h" #include "srsgnb/hdr/stack/mac/sched_nr_cfg.h" #include "srsran/adt/bounded_bitset.h" #include "srsran/adt/bounded_vector.h" @@ -83,6 +84,9 @@ private: bool get_next_dfs(); }; +using pdcch_dl_alloc_result = srsran::expected; +using pdcch_ul_alloc_result = srsran::expected; + /** * Class to handle the allocation of REs for a BWP PDCCH in a specific slot */ @@ -106,7 +110,7 @@ public: * @param aggr_idx Aggregation level index (0..4) * @return PDCCH object with dci context filled if the allocation was successful. nullptr otherwise */ - pdcch_dl_t* alloc_rar_pdcch(uint16_t ra_rnti, uint32_t aggr_idx); + pdcch_dl_alloc_result alloc_rar_pdcch(uint16_t ra_rnti, uint32_t aggr_idx); /** * Allocates RE space for SI DCI in PDCCH, avoiding in the process collisions with other PDCCH allocations @@ -115,7 +119,7 @@ public: * @param aggr_idx Aggregation level index (0..4) * @return PDCCH object with dci context filled if the allocation was successful. nullptr otherwise */ - pdcch_dl_t* alloc_si_pdcch(uint32_t ss_id, uint32_t aggr_idx); + pdcch_dl_alloc_result alloc_si_pdcch(uint32_t ss_id, uint32_t aggr_idx); /** * Allocates RE space for UE DL DCI in PDCCH, avoiding in the process collisions with other PDCCH allocations @@ -126,18 +130,18 @@ public: * @param user UE object parameters * @return PDCCH object with dci context filled if the allocation was successful. nullptr otherwise */ - pdcch_dl_t* + pdcch_dl_alloc_result alloc_dl_pdcch(srsran_rnti_type_t rnti_type, uint32_t ss_id, uint32_t aggr_idx, const ue_carrier_params_t& user); /** - * Allocates RE space for UL DCI in PDCCH, avoiding in the process collisions with other PDCCH allocations + * @brief Allocates RE space for UL DCI in PDCCH, avoiding in the process collisions with other PDCCH allocations * Fills DCI context with PDCCH allocation information * @param ss_id Search space ID * @param aggr_idx Aggregation level index (0..4) * @param user UE object parameters * @return PDCCH object with dci context filled if the allocation was successful. nullptr otherwise */ - pdcch_ul_t* alloc_ul_pdcch(uint32_t ss_id, uint32_t aggr_idx, const ue_carrier_params_t& user); + pdcch_ul_alloc_result alloc_ul_pdcch(uint32_t ss_id, uint32_t aggr_idx, const ue_carrier_params_t& user); /** * Cancel and remove last PDCCH allocation. It should only be called once after each alloc_dl_pdcch/alloc_ul_pdcch @@ -156,21 +160,21 @@ public: private: using slot_coreset_list = srsran::optional_array; - pdcch_dl_t* alloc_dl_pdcch_common(srsran_rnti_type_t rnti_type, - uint16_t rnti, - uint32_t ss_id, - uint32_t aggr_idx, - srsran_dci_format_nr_t dci_fmt, - const ue_carrier_params_t* user = nullptr); + pdcch_dl_alloc_result alloc_dl_pdcch_common(srsran_rnti_type_t rnti_type, + uint16_t rnti, + uint32_t ss_id, + uint32_t aggr_idx, + srsran_dci_format_nr_t dci_fmt, + const ue_carrier_params_t* user = nullptr); /// Helper function to verify valid inputs - bool check_args_valid(srsran_rnti_type_t rnti_type, - uint16_t rnti, - uint32_t ss_id, - uint32_t aggr_idx, - srsran_dci_format_nr_t dci_fmt, - const ue_carrier_params_t* user, - bool is_dl) const; + alloc_result check_args_valid(srsran_rnti_type_t rnti_type, + uint16_t rnti, + uint32_t ss_id, + uint32_t aggr_idx, + srsran_dci_format_nr_t dci_fmt, + const ue_carrier_params_t* user, + bool is_dl) const; /// Fill DCI context of allocated PDCCH void fill_dci_ctx_common(srsran_dci_ctx_t& dci, diff --git a/srsgnb/src/stack/mac/sched_nr_grant_allocator.cc b/srsgnb/src/stack/mac/sched_nr_grant_allocator.cc index ad1aff562..40b2414fb 100644 --- a/srsgnb/src/stack/mac/sched_nr_grant_allocator.cc +++ b/srsgnb/src/stack/mac/sched_nr_grant_allocator.cc @@ -130,12 +130,13 @@ alloc_result bwp_slot_allocator::alloc_si(uint32_t aggr_idx, return alloc_result::sch_collision; } - const uint32_t ss_id = 0; - pdcch_dl_t* pdcch = bwp_pdcch_slot.pdcchs.alloc_si_pdcch(ss_id, aggr_idx); - if (pdcch == nullptr) { + const uint32_t ss_id = 0; + auto pdcch_result = bwp_pdcch_slot.pdcchs.alloc_si_pdcch(ss_id, aggr_idx); + if (pdcch_result.is_error()) { logger.warning("SCHED: Cannot allocate SIB1 due to lack of PDCCH space."); - return alloc_result::no_cch_space; + return pdcch_result.error(); } + pdcch_dl_t* pdcch = pdcch_result.value(); // RAR allocation successful. bwp_pdcch_slot.dl_prbs |= prbs; @@ -220,12 +221,13 @@ alloc_result bwp_slot_allocator::alloc_rar_and_msg3(uint16_t } // Find PDCCH position - pdcch_dl_t* pdcch = bwp_pdcch_slot.pdcchs.alloc_rar_pdcch(ra_rnti, aggr_idx); - if (pdcch == nullptr) { + auto pdcch_result = bwp_pdcch_slot.pdcchs.alloc_rar_pdcch(ra_rnti, aggr_idx); + if (pdcch_result.is_error()) { // Could not find space in PDCCH logger.debug("SCHED: No space in PDCCH for DL tx."); - return alloc_result::no_cch_space; + return pdcch_result.error(); } + pdcch_dl_t* pdcch = pdcch_result.value(); // RAR allocation successful. bwp_pdcch_slot.dl_prbs |= interv; @@ -322,12 +324,12 @@ alloc_result bwp_slot_allocator::alloc_pdsch(slot_ue& ue, prb_grant dl_grant) const srsran_search_space_t& ss = *ss_candidates[0]; // Find space and allocate PDCCH - pdcch_dl_t* pdcch = bwp_pdcch_slot.pdcchs.alloc_dl_pdcch(rnti_type, ss.id, aggr_idx, ue.cfg()); - if (pdcch == nullptr) { + auto pdcch_result = bwp_pdcch_slot.pdcchs.alloc_dl_pdcch(rnti_type, ss.id, aggr_idx, ue.cfg()); + if (pdcch_result.is_error()) { // Could not find space in PDCCH - logger.debug("Could not find PDCCH space for rnti=0x%x PDSCH allocation", ue->rnti); - return alloc_result::no_cch_space; + return pdcch_result.error(); } + pdcch_dl_t* pdcch = pdcch_result.value(); // Update PRB grant based on the start and end of CORESET RBs reduce_to_dl_coreset_bw(cfg, ss.id, srsran_dci_format_nr_1_0, dl_grant); @@ -428,12 +430,13 @@ alloc_result bwp_slot_allocator::alloc_pusch(slot_ue& ue, prb_grant ul_grant) } const srsran_search_space_t& ss = *ss_candidates[0]; - pdcch_ul_t* pdcch = bwp_pdcch_slot.pdcchs.alloc_ul_pdcch(ss.id, aggr_idx, ue.cfg()); - if (pdcch == nullptr) { + auto pdcch_result = bwp_pdcch_slot.pdcchs.alloc_ul_pdcch(ss.id, aggr_idx, ue.cfg()); + if (pdcch_result.is_error()) { // Could not find space in PDCCH logger.debug("Could not find PDCCH space for rnti=0x%x PUSCH allocation", ue->rnti); - return alloc_result::no_cch_space; + return pdcch_result.error(); } + pdcch_ul_t* pdcch = pdcch_result.value(); // Allocation Successful diff --git a/srsgnb/src/stack/mac/sched_nr_pdcch.cc b/srsgnb/src/stack/mac/sched_nr_pdcch.cc index bd05d0e5c..edcb4c592 100644 --- a/srsgnb/src/stack/mac/sched_nr_pdcch.cc +++ b/srsgnb/src/stack/mac/sched_nr_pdcch.cc @@ -191,7 +191,7 @@ srsran::span coreset_region::get_cce_loc_table(const alloc_recor void coreset_region::print_allocations(fmt::memory_buffer& fmtbuf) const { if (not dci_list.empty()) { - fmt::format_to(fmtbuf, "CORESET#{}:\n", coreset_id); + fmt::format_to(fmtbuf, "CORESET#{} (#CCEs={}):\n", coreset_id, nof_cces()); } for (const alloc_record& dci : dci_list) { fmt::format_to(fmtbuf, @@ -236,22 +236,22 @@ void bwp_pdcch_allocator::fill_dci_ctx_common(srsran_dci_ctx_t& dci, dci.format = dci_fmt; } -pdcch_dl_t* bwp_pdcch_allocator::alloc_rar_pdcch(uint16_t ra_rnti, uint32_t aggr_idx) +pdcch_dl_alloc_result bwp_pdcch_allocator::alloc_rar_pdcch(uint16_t ra_rnti, uint32_t aggr_idx) { srsran_assert(bwp_cfg.cfg.pdcch.ra_search_space_present, "Allocating RAR PDCCH in BWP without RA SearchSpace"); return alloc_dl_pdcch_common( srsran_rnti_type_ra, ra_rnti, bwp_cfg.cfg.pdcch.ra_search_space.id, aggr_idx, srsran_dci_format_nr_1_0, nullptr); } -pdcch_dl_t* bwp_pdcch_allocator::alloc_si_pdcch(uint32_t ss_id, uint32_t aggr_idx) +pdcch_dl_alloc_result bwp_pdcch_allocator::alloc_si_pdcch(uint32_t ss_id, uint32_t aggr_idx) { return alloc_dl_pdcch_common(srsran_rnti_type_si, SRSRAN_SIRNTI, ss_id, aggr_idx, srsran_dci_format_nr_1_0, nullptr); } -pdcch_dl_t* bwp_pdcch_allocator::alloc_dl_pdcch(srsran_rnti_type_t rnti_type, - uint32_t ss_id, - uint32_t aggr_idx, - const ue_carrier_params_t& user) +pdcch_dl_alloc_result bwp_pdcch_allocator::alloc_dl_pdcch(srsran_rnti_type_t rnti_type, + uint32_t ss_id, + uint32_t aggr_idx, + const ue_carrier_params_t& user) { static const srsran_dci_format_nr_t dci_fmt = srsran_dci_format_nr_1_0; // TODO: make it configurable srsran_assert(rnti_type == srsran_rnti_type_c or rnti_type == srsran_rnti_type_tc, @@ -260,15 +260,16 @@ pdcch_dl_t* bwp_pdcch_allocator::alloc_dl_pdcch(srsran_rnti_type_t rnti_ return alloc_dl_pdcch_common(rnti_type, user.rnti, ss_id, aggr_idx, dci_fmt, &user); } -pdcch_dl_t* bwp_pdcch_allocator::alloc_dl_pdcch_common(srsran_rnti_type_t rnti_type, - uint16_t rnti, - uint32_t ss_id, - uint32_t aggr_idx, - srsran_dci_format_nr_t dci_fmt, - const ue_carrier_params_t* user) +pdcch_dl_alloc_result bwp_pdcch_allocator::alloc_dl_pdcch_common(srsran_rnti_type_t rnti_type, + uint16_t rnti, + uint32_t ss_id, + uint32_t aggr_idx, + srsran_dci_format_nr_t dci_fmt, + const ue_carrier_params_t* user) { - if (not check_args_valid(rnti_type, rnti, ss_id, aggr_idx, dci_fmt, user, true)) { - return nullptr; + alloc_result r = check_args_valid(rnti_type, rnti, ss_id, aggr_idx, dci_fmt, user, true); + if (r != alloc_result::success) { + return {r}; } const srsran_search_space_t& ss = (user == nullptr) ? *bwp_cfg.get_ss(ss_id) : *user->get_ss(ss_id); @@ -286,7 +287,7 @@ pdcch_dl_t* bwp_pdcch_allocator::alloc_dl_pdcch_common(srsran_rnti_type_t srslog::log_channel& ch = user == nullptr ? logger.warning : logger.debug; log_pdcch_alloc_failure(ch, rnti_type, ss_id, rnti, "No available PDCCH position"); - return nullptr; + return {alloc_result::no_cch_space}; } // Fill DCI context information @@ -295,14 +296,16 @@ pdcch_dl_t* bwp_pdcch_allocator::alloc_dl_pdcch_common(srsran_rnti_type_t // register last PDCCH coreset, in case it needs to be aborted pending_dci = &pdcch_dl_list.back().dci.ctx; - return &pdcch_dl_list.back(); + return {&pdcch_dl_list.back()}; } -pdcch_ul_t* bwp_pdcch_allocator::alloc_ul_pdcch(uint32_t ss_id, uint32_t aggr_idx, const ue_carrier_params_t& user) +pdcch_ul_alloc_result +bwp_pdcch_allocator::alloc_ul_pdcch(uint32_t ss_id, uint32_t aggr_idx, const ue_carrier_params_t& user) { static const srsran_dci_format_nr_t dci_fmt = srsran_dci_format_nr_0_0; // TODO: make it configurable - if (not check_args_valid(srsran_rnti_type_c, user.rnti, ss_id, aggr_idx, dci_fmt, &user, false)) { - return nullptr; + alloc_result r = check_args_valid(srsran_rnti_type_c, user.rnti, ss_id, aggr_idx, dci_fmt, &user, false); + if (r != alloc_result::success) { + return {r}; } const srsran_search_space_t& ss = *user.get_ss(ss_id); @@ -319,7 +322,7 @@ pdcch_ul_t* bwp_pdcch_allocator::alloc_ul_pdcch(uint32_t ss_id, uint32_t aggr_id // Log PDCCH allocation failure log_pdcch_alloc_failure(logger.debug, srsran_rnti_type_c, ss_id, user.rnti, "No available PDCCH position"); - return nullptr; + return {alloc_result::no_cch_space}; } // Fill DCI context information @@ -328,7 +331,7 @@ pdcch_ul_t* bwp_pdcch_allocator::alloc_ul_pdcch(uint32_t ss_id, uint32_t aggr_id // register last PDCCH coreset, in case it needs to be aborted pending_dci = &pdcch_ul_list.back().dci.ctx; - return &pdcch_ul_list.back(); + return {&pdcch_ul_list.back()}; } void bwp_pdcch_allocator::cancel_last_pdcch() @@ -372,13 +375,13 @@ uint32_t bwp_pdcch_allocator::nof_cces(uint32_t coreset_id) const return coresets[coreset_id].nof_cces(); } -bool bwp_pdcch_allocator::check_args_valid(srsran_rnti_type_t rnti_type, - uint16_t rnti, - uint32_t ss_id, - uint32_t aggr_idx, - srsran_dci_format_nr_t dci_fmt, - const ue_carrier_params_t* user, - bool is_dl) const +alloc_result bwp_pdcch_allocator::check_args_valid(srsran_rnti_type_t rnti_type, + uint16_t rnti, + uint32_t ss_id, + uint32_t aggr_idx, + srsran_dci_format_nr_t dci_fmt, + const ue_carrier_params_t* user, + bool is_dl) const { srsran_assert(ss_id < SRSRAN_UE_DL_NR_MAX_NOF_SEARCH_SPACE, "Invalid SearchSpace#%d", ss_id); srsran_assert( @@ -387,7 +390,7 @@ bool bwp_pdcch_allocator::check_args_valid(srsran_rnti_type_t rnti_type, // DL must be active in given slot if (not bwp_cfg.slots[slot_idx].is_dl) { log_pdcch_alloc_failure(logger.error, rnti_type, ss_id, rnti, "DL is disabled for slot={}", slot_idx); - return false; + return alloc_result::no_cch_space; } // Verify SearchSpace validity @@ -395,19 +398,23 @@ bool bwp_pdcch_allocator::check_args_valid(srsran_rnti_type_t rnti_type, if (ss == nullptr) { // Couldn't find SearchSpace log_pdcch_alloc_failure(logger.error, rnti_type, ss_id, rnti, "SearchSpace has not been configured"); - return false; + return alloc_result::invalid_grant_params; } if (ss->nof_candidates[aggr_idx] == 0) { // No valid DCI position candidates given aggregation level log_pdcch_alloc_failure( logger.warning, rnti_type, ss_id, rnti, "Chosen SearchSpace doesn't have CCE candidates for L={}", aggr_idx); - return false; + return alloc_result::invalid_grant_params; } if (not is_rnti_type_valid_in_search_space(rnti_type, ss->type)) { // RNTI type doesnt match SearchSpace type - log_pdcch_alloc_failure( - logger.warning, rnti_type, ss_id, rnti, "Chosen SearchSpace type={} does not match rnti_type.", ss->type); - return false; + log_pdcch_alloc_failure(logger.warning, + rnti_type, + ss_id, + rnti, + "Chosen SearchSpace type \"{}\" does not match rnti_type.", + srsran_ss_type_str(ss->type)); + return alloc_result::invalid_grant_params; } auto dci_fmt_equal = [dci_fmt](srsran_dci_format_nr_t f) { return f == dci_fmt; }; if (std::none_of(&ss->formats[0], &ss->formats[ss->nof_formats], dci_fmt_equal)) { @@ -417,29 +424,29 @@ bool bwp_pdcch_allocator::check_args_valid(srsran_rnti_type_t rnti_type, rnti, "Chosen SearchSpace does not support chosen dci format={}", srsran_dci_format_nr_string(dci_fmt)); - return false; + return alloc_result::invalid_grant_params; } if (is_dl) { if (pdcch_dl_list.full()) { log_pdcch_alloc_failure( logger.warning, rnti_type, ss_id, rnti, "Maximum number of allocations={} reached", pdcch_dl_list.size()); - return false; + return alloc_result::no_cch_space; } } else if (pdcch_ul_list.full()) { log_pdcch_alloc_failure( logger.warning, rnti_type, ss_id, rnti, "Maximum number of UL allocations={} reached", pdcch_ul_list.size()); - return false; + return alloc_result::no_cch_space; } srsran_sanity_check(pdcch_dl_list.size() + pdcch_ul_list.size() == nof_allocations(), "Invalid PDCCH state"); - return true; + return alloc_result::success; } void bwp_pdcch_allocator::print_allocations(fmt::memory_buffer& fmtbuf) const { fmt::format_to( - fmtbuf, "PDCCH allocations ({} active coresets):{}\n", coresets.size(), nof_allocations() == 0 ? " None" : ""); + fmtbuf, "PDCCH allocations: ({} active coresets):{}\n", coresets.size(), nof_allocations() == 0 ? " None" : ""); for (const coreset_region& cs : coresets) { cs.print_allocations(fmtbuf); } diff --git a/srsgnb/src/stack/mac/test/sched_nr_pdcch_test.cc b/srsgnb/src/stack/mac/test/sched_nr_pdcch_test.cc index 823b2fcf4..3c5cbe563 100644 --- a/srsgnb/src/stack/mac/test/sched_nr_pdcch_test.cc +++ b/srsgnb/src/stack/mac/test/sched_nr_pdcch_test.cc @@ -41,10 +41,12 @@ void test_coreset0_cfg() uecfg.phy_cfg.pdcch = cell_cfg.bwps[0].pdcch; // Starts without UE-specific PDCCH ue_carrier_params_t ue_cc{0x46, bwp_params, uecfg}; - pdcch_dl_list_t dl_pdcchs; - pdcch_ul_list_t ul_pdcchs; - pdcch_dl_t* dl_pdcch = nullptr; - pdcch_ul_t* ul_pdcch = nullptr; + pdcch_dl_list_t dl_pdcchs; + pdcch_ul_list_t ul_pdcchs; + pdcch_dl_alloc_result dl_pdcch_result; + pdcch_ul_alloc_result ul_pdcch_result; + pdcch_dl_t* dl_pdcch = nullptr; + pdcch_ul_t* ul_pdcch = nullptr; bwp_pdcch_allocator pdcch_sched(bwp_params, 0, dl_pdcchs, ul_pdcchs); for (const srsran_coreset_t& cs : view_active_coresets(cell_cfg.bwps[0].pdcch)) { @@ -56,17 +58,18 @@ void test_coreset0_cfg() TESTASSERT_EQ(0, pdcch_sched.nof_allocations()); // SIB1 allocation should be successful - dl_pdcch = pdcch_sched.alloc_si_pdcch(0, aggr_idx); - TESTASSERT(dl_pdcch != nullptr); + dl_pdcch_result = pdcch_sched.alloc_si_pdcch(0, aggr_idx); + TESTASSERT(dl_pdcch_result.has_value()); + dl_pdcch = dl_pdcch_result.value(); TESTASSERT_EQ(1, pdcch_sched.nof_allocations()); TESTASSERT_EQ(srsran_rnti_type_si, dl_pdcch->dci.ctx.rnti_type); TESTASSERT_EQ(0, dl_pdcch->dci.ctx.coreset_id); test_dci_ctx_consistency(bwp_params.cfg.pdcch, dl_pdcch->dci.ctx); // No space for RAR, UE PDSCH/PUSCH - TESTASSERT(pdcch_sched.alloc_rar_pdcch(0x2, aggr_idx) == nullptr); - TESTASSERT(pdcch_sched.alloc_dl_pdcch(srsran_rnti_type_c, 1, aggr_idx, ue_cc) == nullptr); - TESTASSERT(pdcch_sched.alloc_ul_pdcch(1, aggr_idx, ue_cc) == nullptr); + TESTASSERT(pdcch_sched.alloc_rar_pdcch(0x2, aggr_idx).error() == alloc_result::no_cch_space); + TESTASSERT(pdcch_sched.alloc_dl_pdcch(srsran_rnti_type_c, 1, aggr_idx, ue_cc).error() == alloc_result::no_cch_space); + TESTASSERT(pdcch_sched.alloc_ul_pdcch(1, aggr_idx, ue_cc).error() == alloc_result::no_cch_space); srslog::fetch_basic_logger("TEST").info("%s", pdcch_sched.print_allocations()); @@ -74,8 +77,9 @@ void test_coreset0_cfg() pdcch_sched.reset(); // RAR allocation should be successful - dl_pdcch = pdcch_sched.alloc_rar_pdcch(0x2, aggr_idx); - TESTASSERT(dl_pdcch != nullptr); + dl_pdcch_result = pdcch_sched.alloc_rar_pdcch(0x2, aggr_idx); + TESTASSERT(dl_pdcch_result.has_value()); + dl_pdcch = dl_pdcch_result.value(); TESTASSERT_EQ(1, pdcch_sched.nof_allocations()); TESTASSERT_EQ(srsran_rnti_type_ra, dl_pdcch->dci.ctx.rnti_type); TESTASSERT_EQ(0, dl_pdcch->dci.ctx.coreset_id); @@ -83,8 +87,8 @@ void test_coreset0_cfg() test_dci_ctx_consistency(bwp_params.cfg.pdcch, dl_pdcch->dci.ctx); // No space for RAR, UE PDSCH/PUSCH - TESTASSERT(pdcch_sched.alloc_dl_pdcch(srsran_rnti_type_c, 1, aggr_idx, ue_cc) == nullptr); - TESTASSERT(pdcch_sched.alloc_ul_pdcch(1, aggr_idx, ue_cc) == nullptr); + TESTASSERT(pdcch_sched.alloc_dl_pdcch(srsran_rnti_type_c, 1, aggr_idx, ue_cc).error() == alloc_result::no_cch_space); + TESTASSERT(pdcch_sched.alloc_ul_pdcch(1, aggr_idx, ue_cc).error() == alloc_result::no_cch_space); srslog::fetch_basic_logger("TEST").info("%s", pdcch_sched.print_allocations()); @@ -92,8 +96,9 @@ void test_coreset0_cfg() pdcch_sched.reset(); // 1st PDCCH allocation for DL should be successful - dl_pdcch = pdcch_sched.alloc_dl_pdcch(srsran_rnti_type_c, 1, aggr_idx, ue_cc); - TESTASSERT(dl_pdcch != nullptr); + dl_pdcch_result = pdcch_sched.alloc_dl_pdcch(srsran_rnti_type_c, 1, aggr_idx, ue_cc); + TESTASSERT(dl_pdcch_result.has_value()); + dl_pdcch = dl_pdcch_result.value(); TESTASSERT_EQ(1, pdcch_sched.nof_allocations()); TESTASSERT_EQ(srsran_rnti_type_c, dl_pdcch->dci.ctx.rnti_type); TESTASSERT_EQ(0u, dl_pdcch->dci.ctx.coreset_id); @@ -101,7 +106,7 @@ void test_coreset0_cfg() test_dci_ctx_consistency(bwp_params.cfg.pdcch, dl_pdcch->dci.ctx); // No space for 2nd PDCCH allocation - TESTASSERT(pdcch_sched.alloc_ul_pdcch(1, aggr_idx, ue_cc) == nullptr); + TESTASSERT(pdcch_sched.alloc_ul_pdcch(1, aggr_idx, ue_cc).error() == alloc_result::no_cch_space); srslog::fetch_basic_logger("TEST").info("%s", pdcch_sched.print_allocations()); @@ -109,8 +114,9 @@ void test_coreset0_cfg() pdcch_sched.reset(); // 1st PDCCH allocation for UL should be successful - ul_pdcch = pdcch_sched.alloc_ul_pdcch(1, aggr_idx, ue_cc); - TESTASSERT(ul_pdcch != nullptr); + ul_pdcch_result = pdcch_sched.alloc_ul_pdcch(1, aggr_idx, ue_cc); + TESTASSERT(ul_pdcch_result.has_value()); + ul_pdcch = ul_pdcch_result.value(); TESTASSERT_EQ(1, pdcch_sched.nof_allocations()); TESTASSERT_EQ(srsran_rnti_type_c, ul_pdcch->dci.ctx.rnti_type); TESTASSERT_EQ(0u, ul_pdcch->dci.ctx.coreset_id); @@ -118,7 +124,7 @@ void test_coreset0_cfg() test_dci_ctx_consistency(bwp_params.cfg.pdcch, ul_pdcch->dci.ctx); // No space for 2nd PDCCH allocation - TESTASSERT(pdcch_sched.alloc_dl_pdcch(srsran_rnti_type_c, 1, aggr_idx, ue_cc) == nullptr); + TESTASSERT(pdcch_sched.alloc_dl_pdcch(srsran_rnti_type_c, 1, aggr_idx, ue_cc).error() == alloc_result::no_cch_space); srslog::fetch_basic_logger("TEST").info("%s", pdcch_sched.print_allocations()); } @@ -164,7 +170,7 @@ void test_coreset2_cfg() TESTASSERT_EQ(0, pdcch_sched.nof_allocations()); // SIB1 allocation should be successful - dl_pdcch = pdcch_sched.alloc_si_pdcch(0, aggr_idx); + dl_pdcch = pdcch_sched.alloc_si_pdcch(0, aggr_idx).value(); TESTASSERT(dl_pdcch != nullptr); TESTASSERT_EQ(1, pdcch_sched.nof_allocations()); TESTASSERT_EQ(srsran_rnti_type_si, dl_pdcch->dci.ctx.rnti_type); @@ -174,12 +180,12 @@ void test_coreset2_cfg() test_dci_ctx_consistency(bwp_params.cfg.pdcch, dl_pdcch->dci.ctx); // No space for RAR or PDSCH in SS#1 - TESTASSERT(pdcch_sched.alloc_rar_pdcch(0x2, aggr_idx) == nullptr); - TESTASSERT(pdcch_sched.alloc_dl_pdcch(srsran_rnti_type_c, 1, aggr_idx, ue_cc) == nullptr); - TESTASSERT(pdcch_sched.alloc_ul_pdcch(1, aggr_idx, ue_cc) == nullptr); + TESTASSERT(pdcch_sched.alloc_rar_pdcch(0x2, aggr_idx).error() == alloc_result::no_cch_space); + TESTASSERT(pdcch_sched.alloc_dl_pdcch(srsran_rnti_type_c, 1, aggr_idx, ue_cc).error() == alloc_result::no_cch_space); + TESTASSERT(pdcch_sched.alloc_ul_pdcch(1, aggr_idx, ue_cc).error() == alloc_result::no_cch_space); // there is space for UE DL PDCCH in SS#2 - dl_pdcch = pdcch_sched.alloc_dl_pdcch(srsran_rnti_type_c, 2, aggr_idx, ue_cc); + dl_pdcch = pdcch_sched.alloc_dl_pdcch(srsran_rnti_type_c, 2, aggr_idx, ue_cc).value(); TESTASSERT(dl_pdcch != nullptr); TESTASSERT_EQ(2, pdcch_sched.nof_allocations()); TESTASSERT_EQ(srsran_rnti_type_c, dl_pdcch->dci.ctx.rnti_type); @@ -190,7 +196,7 @@ void test_coreset2_cfg() test_dci_ctx_consistency(bwp_params.cfg.pdcch, dl_pdcch->dci.ctx); // there is space for UE UL PDCCH in SS#2 - ul_pdcch = pdcch_sched.alloc_ul_pdcch(2, aggr_idx, ue_cc); + ul_pdcch = pdcch_sched.alloc_ul_pdcch(2, aggr_idx, ue_cc).value(); TESTASSERT(ul_pdcch != nullptr); TESTASSERT_EQ(3, pdcch_sched.nof_allocations()); TESTASSERT_EQ(srsran_rnti_type_c, ul_pdcch->dci.ctx.rnti_type); @@ -202,7 +208,7 @@ void test_coreset2_cfg() test_dci_ctx_consistency(bwp_params.cfg.pdcch, ul_pdcch->dci.ctx); // No space for 3rd PDCCH allocation in SS#2 - TESTASSERT(pdcch_sched.alloc_dl_pdcch(srsran_rnti_type_c, 2, aggr_idx, ue_cc) == nullptr); + TESTASSERT(pdcch_sched.alloc_dl_pdcch(srsran_rnti_type_c, 2, aggr_idx, ue_cc).error() == alloc_result::no_cch_space); // Verify there are no PDCCH collisions TESTASSERT_EQ(3, pdcch_sched.nof_allocations()); @@ -219,6 +225,71 @@ void test_coreset2_cfg() TESTASSERT_EQ(0, ul_pdcchs.size()); } +void test_invalid_params() +{ + const uint32_t aggr_idx = 2; + + srsran::test_delimit_logger delimiter{"Test PDCCH Allocation with Invalid Arguments"}; + + sched_nr_impl::cell_cfg_t cell_cfg = get_default_sa_cell_cfg_common(); + cell_cfg.bwps[0].pdcch.search_space_present[2] = true; + cell_cfg.bwps[0].pdcch.search_space[2] = get_default_ue_specific_search_space(2, 2); + cell_cfg.bwps[0].pdcch.coreset_present[2] = true; + cell_cfg.bwps[0].pdcch.coreset[2] = get_default_ue_specific_coreset(2, cell_cfg.carrier.pci); + cell_cfg.bwps[0].pdcch.search_space_present[3] = true; + cell_cfg.bwps[0].pdcch.search_space[3] = get_default_ue_specific_search_space(3, 2); + cell_cfg.bwps[0].pdcch.search_space[3].nof_formats = 1; // only DL + cell_cfg.bwps[0].pdcch.search_space[3].formats[0] = srsran_dci_format_nr_1_0; + sched_nr_interface::sched_args_t sched_args; + bwp_params_t bwp_params{cell_cfg, sched_args, 0, 0}; + + // UE config + ue_cfg_t uecfg = get_rach_ue_cfg(0); + uecfg.phy_cfg = get_common_ue_phy_cfg(cell_cfg); + uecfg.phy_cfg.pdcch = cell_cfg.bwps[0].pdcch; // Starts with UE-specific PDCCH + ue_carrier_params_t ue_cc{0x46, bwp_params, uecfg}; + + pdcch_dl_list_t dl_pdcchs; + pdcch_ul_list_t ul_pdcchs; + pdcch_dl_alloc_result dl_res; + pdcch_ul_alloc_result ul_res; + + bwp_pdcch_allocator pdcch_sched(bwp_params, 0, dl_pdcchs, ul_pdcchs); + + // Slot with SIB1 + DL PDCCH and UL PDCCH + TESTASSERT_EQ(0, pdcch_sched.nof_allocations()); + + // Pass UE search space for SI alloc + dl_res = pdcch_sched.alloc_si_pdcch(2, aggr_idx); + TESTASSERT(dl_res.is_error() and dl_res.error() == alloc_result::invalid_grant_params); + + // Pass aggregation index for which there are no candidates + dl_res = pdcch_sched.alloc_si_pdcch(2, 4); + TESTASSERT(dl_res.is_error() and dl_res.error() == alloc_result::invalid_grant_params); + + // SearchSpace must exist + dl_res = pdcch_sched.alloc_dl_pdcch(srsran_rnti_type_c, 4, aggr_idx, ue_cc); + TESTASSERT(dl_res.is_error() and dl_res.error() == alloc_result::invalid_grant_params); + + // TC-RNTI cannot be allocated in Common SearchSpace Type1 + dl_res = pdcch_sched.alloc_dl_pdcch(srsran_rnti_type_tc, 2, aggr_idx, ue_cc); + TESTASSERT(dl_res.is_error() and dl_res.error() == alloc_result::invalid_grant_params); + + // C-RNTI cannot be allocated in Common SearchSpace Type0 + dl_res = pdcch_sched.alloc_dl_pdcch(srsran_rnti_type_c, 0, aggr_idx, ue_cc); + TESTASSERT(dl_res.is_error() and dl_res.error() == alloc_result::invalid_grant_params); + + // UL allocation cannot be made in SearchSpace without DCI format 0_0 + ul_res = pdcch_sched.alloc_ul_pdcch(3, aggr_idx, ue_cc); + TESTASSERT(ul_res.is_error() and ul_res.error() == alloc_result::invalid_grant_params); + + // Success case + TESTASSERT(pdcch_sched.nof_allocations() == 0); + ul_res = pdcch_sched.alloc_ul_pdcch(2, aggr_idx, ue_cc); + TESTASSERT(ul_res.has_value() and ul_res.value()->dci.ctx.format == srsran_dci_format_nr_0_0); + TESTASSERT(pdcch_sched.nof_allocations() == 1); +} + } // namespace srsenb int main() @@ -235,4 +306,5 @@ int main() srsenb::test_coreset0_cfg(); srsenb::test_coreset2_cfg(); + srsenb::test_invalid_params(); } \ No newline at end of file