From 2cdda3b6db78828969ea787135a686eb47b27170 Mon Sep 17 00:00:00 2001 From: Francisco Date: Mon, 31 May 2021 17:32:51 +0100 Subject: [PATCH] sched,enhancement: allow PUSCH allocations when PHICH falls in measurement Gap by resuming UL HARQ --- srsenb/hdr/stack/mac/sched_ue.h | 1 + .../hdr/stack/mac/sched_ue_ctrl/sched_harq.h | 8 ++- srsenb/src/stack/mac/sched_grid.cc | 37 ++++++---- srsenb/src/stack/mac/sched_ue.cc | 20 +++++- .../src/stack/mac/sched_ue_ctrl/sched_harq.cc | 64 ++++++++++------- .../stack/mac/sched_ue_ctrl/sched_ue_cell.cc | 2 +- srsenb/test/mac/sched_sim_ue.cc | 19 +++-- srsenb/test/mac/sched_test_rand.cc | 2 +- srsenb/test/mac/sched_ue_ded_test_suite.cc | 69 +++++++++++++------ 9 files changed, 148 insertions(+), 74 deletions(-) diff --git a/srsenb/hdr/stack/mac/sched_ue.h b/srsenb/hdr/stack/mac/sched_ue.h index 3b168080a..24b120cb4 100644 --- a/srsenb/hdr/stack/mac/sched_ue.h +++ b/srsenb/hdr/stack/mac/sched_ue.h @@ -138,6 +138,7 @@ public: bool pdsch_enabled(tti_point tti_rx, uint32_t enb_cc_idx) const; bool pusch_enabled(tti_point tti_rx, uint32_t enb_cc_idx, bool needs_pdcch) const; + bool phich_enabled(tti_point tti_rx, uint32_t enb_cc_idx) const; private: bool is_sr_triggered(); diff --git a/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_harq.h b/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_harq.h index d274296e9..7805a8b87 100644 --- a/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_harq.h +++ b/srsenb/hdr/stack/mac/sched_ue_ctrl/sched_harq.h @@ -106,12 +106,14 @@ public: uint32_t get_pending_data() const; bool has_pending_phich() const; bool pop_pending_phich(); + void phich_alloc_failed(); private: prb_interval allocation; int pending_data; - bool pending_phich = false; - bool is_msg3_ = false; + bool pending_phich = false; + bool is_msg3_ = false; + bool pdcch_required = false; }; class harq_entity @@ -161,7 +163,7 @@ public: int set_ul_crc(srsran::tti_point tti_tx_ul, uint32_t tb_idx, bool ack_); //! Resets pending harq ACKs and cleans UL Harqs with maxretx == 0 - void reset_pending_data(srsran::tti_point tti_rx); + void finish_tti(srsran::tti_point tti_rx); private: dl_harq_proc* get_oldest_dl_harq(tti_point tti_tx_dl); diff --git a/srsenb/src/stack/mac/sched_grid.cc b/srsenb/src/stack/mac/sched_grid.cc index 4d1905dbc..755feb496 100644 --- a/srsenb/src/stack/mac/sched_grid.cc +++ b/srsenb/src/stack/mac/sched_grid.cc @@ -623,12 +623,6 @@ alloc_result sf_sched::alloc_phich(sched_ue* user) { using phich_t = sched_interface::ul_sched_phich_t; - auto* ul_sf_result = &cc_results->get_cc(cc_cfg->enb_cc_idx)->ul_sched_result; - if (ul_sf_result->phich.full()) { - logger.warning("SCHED: Maximum number of PHICH allocations has been reached"); - return alloc_result::no_grant_space; - } - auto p = user->get_active_cell_index(cc_cfg->enb_cc_idx); if (not p.first) { // user does not support this carrier @@ -636,15 +630,32 @@ alloc_result sf_sched::alloc_phich(sched_ue* user) } ul_harq_proc* h = user->get_ul_harq(get_tti_tx_ul(), cc_cfg->enb_cc_idx); + if (not h->has_pending_phich()) { + // No PHICH pending + return alloc_result::no_rnti_opportunity; + } - /* Indicate PHICH acknowledgment if needed */ - if (h->has_pending_phich()) { - ul_sf_result->phich.emplace_back(); - ul_sf_result->phich.back().rnti = user->get_rnti(); - ul_sf_result->phich.back().phich = h->pop_pending_phich() ? phich_t::ACK : phich_t::NACK; - return alloc_result::success; + auto* ul_sf_result = &cc_results->get_cc(cc_cfg->enb_cc_idx)->ul_sched_result; + if (ul_sf_result->phich.full()) { + logger.warning("SCHED: Maximum number of PHICH allocations has been reached"); + h->phich_alloc_failed(); + return alloc_result::no_grant_space; } - return alloc_result::no_rnti_opportunity; + + if (not user->phich_enabled(get_tti_rx(), cc_cfg->enb_cc_idx)) { + // PHICH falls in measGap. PHICH hi=1 is assumed by UE. In case of NACK, the HARQ is going to be resumed later on. + logger.debug("SCHED: HARQ pid=%d for rnti=0x%x is being resumed due to PHICH - MeasGap collision", + h->get_id(), + user->get_rnti()); + h->phich_alloc_failed(); + return alloc_result::no_cch_space; + } + + /* Indicate PHICH acknowledgment if needed */ + ul_sf_result->phich.emplace_back(); + ul_sf_result->phich.back().rnti = user->get_rnti(); + ul_sf_result->phich.back().phich = h->pop_pending_phich() ? phich_t::ACK : phich_t::NACK; + return alloc_result::success; } void sf_sched::set_dl_data_sched_result(const sf_cch_allocator::alloc_result_t& dci_result, diff --git a/srsenb/src/stack/mac/sched_ue.cc b/srsenb/src/stack/mac/sched_ue.cc index bbc55a486..7f56d6b99 100644 --- a/srsenb/src/stack/mac/sched_ue.cc +++ b/srsenb/src/stack/mac/sched_ue.cc @@ -214,7 +214,7 @@ bool sched_ue::pusch_enabled(tti_point tti_rx, uint32_t enb_cc_idx, bool needs_p tti_interval meas_gap{mgap_tti, mgap_tti + 6}; // disable TTIs that leads to PUSCH tx or PHICH rx falling in measGap - if (meas_gap.contains(tti_tx_ul) or meas_gap.contains(to_tx_ul_ack(tti_rx))) { + if (meas_gap.contains(tti_tx_ul)) { return false; } // disable TTIs which respective PDCCH falls in measGap (in case PDCCH is needed) @@ -225,6 +225,24 @@ bool sched_ue::pusch_enabled(tti_point tti_rx, uint32_t enb_cc_idx, bool needs_p return true; } +bool sched_ue::phich_enabled(tti_point tti_rx, uint32_t enb_cc_idx) const +{ + if (cfg.supported_cc_list[0].enb_cc_idx != enb_cc_idx) { + return true; + } + + // Check measGap collision with PHICH + if (cfg.measgap_period > 0) { + tti_point tti_tx_dl = to_tx_dl(tti_rx); + tti_point mgap_tti = nearest_meas_gap(tti_tx_dl, cfg.measgap_period, cfg.measgap_offset); + tti_interval meas_gap{mgap_tti, mgap_tti + 6}; + if (meas_gap.contains(tti_tx_dl)) { + return false; + } + } + return true; +} + int sched_ue::set_ack_info(tti_point tti_rx, uint32_t enb_cc_idx, uint32_t tb_idx, bool ack) { return cells[enb_cc_idx].set_ack_info(tti_rx, tb_idx, ack); diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_harq.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_harq.cc index eb39f1bb2..fc7ab9c8d 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_harq.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_harq.cc @@ -112,11 +112,8 @@ void harq_proc::new_retx_common(uint32_t tb_idx, tti_point tti_, int* mcs, int* void harq_proc::reset_pending_data_common() { - // reuse harqs with no retxs - if (max_retx == 0 and not is_empty()) { - for (bool& tb : active) { - tb = false; - } + for (bool& tb : active) { + tb = false; } } @@ -250,9 +247,10 @@ void ul_harq_proc::new_tx(tti_point tti_, int mcs, int tbs, prb_interval alloc, { allocation = alloc; new_tx_common(0, tti_point{tti_}, mcs, tbs, max_retx_); - pending_data = tbs; - pending_phich = true; - is_msg3_ = is_msg3; + pending_data = tbs; + pending_phich = true; + is_msg3_ = is_msg3; + pdcch_required = false; } void ul_harq_proc::new_retx(tti_point tti_, int* mcs, int* tbs, prb_interval alloc) @@ -260,12 +258,15 @@ void ul_harq_proc::new_retx(tti_point tti_, int* mcs, int* tbs, prb_interval all // If PRBs changed, or there was no tx in last oportunity (e.g. HARQ is being resumed) allocation = alloc; new_retx_common(0, tti_point{tti_}, mcs, tbs); - pending_phich = true; + pending_phich = true; + pdcch_required = false; } -bool ul_harq_proc::retx_requires_pdcch(srsran::tti_point tti_, prb_interval alloc) const +bool ul_harq_proc::retx_requires_pdcch(tti_point tti_, prb_interval alloc) const { - return alloc != allocation or tti_ != to_tx_ul(tti); + // Adaptive retx if: (1) PRBs changed, (2) HARQ resumed due to last PUSCH retx being skipped (3) HARQ resumed due to + // last PHICH alloc being skipped (e.g. due to measGaps) + return alloc != allocation or tti_ != to_tx_ul(tti) or pdcch_required; } bool ul_harq_proc::set_ack(uint32_t tb_idx, bool ack_) @@ -282,15 +283,23 @@ bool ul_harq_proc::has_pending_phich() const return pending_phich; } +void ul_harq_proc::phich_alloc_failed() +{ + pop_pending_phich(); + if (not is_empty(0)) { + // HARQ needs to be resumed. This is signalled by pending_phich flag + pdcch_required = true; + } +} + bool ul_harq_proc::pop_pending_phich() { - assert(pending_phich); + srsran_assert(pending_phich, "pop_pending_phich called for HARQ with no pending PHICH"); bool ret = ack_state[0]; pending_phich = false; if (is_empty(0)) { - // fully reset UL HARQ once PHICH is dispatched - is_msg3_ = false; - pending_data = 0; + // fully reset HARQ info once PHICH is dispatched for an acked / maxretx reached HARQ + reset_pending_data(); } return ret; } @@ -298,10 +307,9 @@ bool ul_harq_proc::pop_pending_phich() void ul_harq_proc::reset_pending_data() { reset_pending_data_common(); - if (is_empty(0)) { - pending_data = 0; - is_msg3_ = false; - } + pending_data = 0; + is_msg3_ = false; + pdcch_required = false; } uint32_t ul_harq_proc::get_pending_data() const @@ -391,16 +399,20 @@ int harq_entity::set_ul_crc(tti_point tti_rx, uint32_t tb_idx, bool ack_) return h->set_ack(tb_idx, ack_) ? pid : -1; } -void harq_entity::reset_pending_data(tti_point tti_rx) +void harq_entity::finish_tti(tti_point tti_rx) { - tti_point tti_tx_ul = to_tx_ul(tti_rx); - - // Reset ACK state of UL Harq - get_ul_harq(tti_tx_ul)->reset_pending_data(); + // Reset UL HARQ if no retxs + auto* hul = get_ul_harq(to_tx_ul(tti_rx)); + if (not hul->is_empty() and hul->max_nof_retx() == 0) { + hul->reset_pending_data(); + } - // Reset any DL harq which has 0 retxs + // Reset DL harq which has 0 retxs for (auto& h : dl_harqs) { - h.reset_pending_data(); + if (not h.is_empty() and h.max_nof_retx() == 0) { + // reuse harqs with no retxs + h.reset_pending_data(); + } } } diff --git a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc index 1a6bd1294..01e9d7efd 100644 --- a/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc +++ b/srsenb/src/stack/mac/sched_ue_ctrl/sched_ue_cell.cc @@ -160,7 +160,7 @@ void sched_ue_cell::clear_feedback() void sched_ue_cell::finish_tti(tti_point tti_rx) { // clear_feedback PIDs with pending data or blocked - harq_ent.reset_pending_data(tti_rx); + harq_ent.finish_tti(tti_rx); } int sched_ue_cell::set_dl_wb_cqi(tti_point tti_rx, uint32_t dl_cqi_) diff --git a/srsenb/test/mac/sched_sim_ue.cc b/srsenb/test/mac/sched_sim_ue.cc index f359961b3..c510d6750 100644 --- a/srsenb/test/mac/sched_sim_ue.cc +++ b/srsenb/test/mac/sched_sim_ue.cc @@ -106,17 +106,19 @@ void ue_sim::update_ul_harqs(const sf_output_res_t& sf_out) { uint32_t pid = to_tx_ul(sf_out.tti_rx).to_uint() % (FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS); for (uint32_t cc = 0; cc < sf_out.cc_params.size(); ++cc) { + const auto *cc_cfg = ctxt.get_cc_cfg(cc), *start = &ctxt.ue_cfg.supported_cc_list[0]; + uint32_t ue_cc_idx = std::distance(start, cc_cfg); + auto& ue_cc_ctxt = ctxt.cc_list[ue_cc_idx]; + auto& h = ue_cc_ctxt.ul_harqs[pid]; + // Update UL harqs with PHICH info + bool found_phich = false; for (uint32_t i = 0; i < sf_out.ul_cc_result[cc].phich.size(); ++i) { const auto& phich = sf_out.ul_cc_result[cc].phich[i]; if (phich.rnti != ctxt.rnti) { continue; } - - const auto *cc_cfg = ctxt.get_cc_cfg(cc), *start = &ctxt.ue_cfg.supported_cc_list[0]; - uint32_t ue_cc_idx = std::distance(start, cc_cfg); - auto& ue_cc_ctxt = ctxt.cc_list[ue_cc_idx]; - auto& h = ue_cc_ctxt.ul_harqs[pid]; + found_phich = true; bool is_ack = phich.phich == phich_t::ACK; bool is_msg3 = @@ -126,6 +128,11 @@ void ue_sim::update_ul_harqs(const sf_output_res_t& sf_out) h.active = false; } } + if (h.active and not found_phich) { + // HARQ being resumed. Possibly due to measGap, PHICH may not be allocated. + logger.info("TESTER: rnti=0x%x, HARQ pid=%d being resumed.", ctxt.rnti, pid); + h.active = false; + } // Update UL harqs with PUSCH grants for (uint32_t i = 0; i < sf_out.ul_cc_result[cc].pusch.size(); ++i) { @@ -133,8 +140,6 @@ void ue_sim::update_ul_harqs(const sf_output_res_t& sf_out) if (data.dci.rnti != ctxt.rnti) { continue; } - auto& ue_cc_ctxt = ctxt.cc_list[data.dci.ue_cc_idx]; - auto& h = ue_cc_ctxt.ul_harqs[to_tx_ul(sf_out.tti_rx).to_uint() % ue_cc_ctxt.ul_harqs.size()]; if (h.nof_txs == 0 or h.ndi != data.dci.tb.ndi) { // newtx diff --git a/srsenb/test/mac/sched_test_rand.cc b/srsenb/test/mac/sched_test_rand.cc index 7fea30e46..76f56cc87 100644 --- a/srsenb/test/mac/sched_test_rand.cc +++ b/srsenb/test/mac/sched_test_rand.cc @@ -285,7 +285,7 @@ sched_sim_events rand_sim_params(uint32_t nof_ttis) sim_gen.sim_args.default_ue_sim_cfg.prob_ul_ack_mask.back() = 1; sim_gen.sim_args.default_ue_sim_cfg.ue_cfg.measgap_period = pick_random_uniform({0, 40, 80}); sim_gen.sim_args.default_ue_sim_cfg.ue_cfg.measgap_offset = std::uniform_int_distribution{ - 0, sim_gen.sim_args.default_ue_sim_cfg.ue_cfg.measgap_period}(srsenb::get_rand_gen()); + 0, std::max(sim_gen.sim_args.default_ue_sim_cfg.ue_cfg.measgap_period, 1u) - 1}(srsenb::get_rand_gen()); sim_gen.sim_args.default_ue_sim_cfg.ue_cfg.pucch_cfg.n_pucch_sr = std::uniform_int_distribution{0, 2047}(srsenb::get_rand_gen()); diff --git a/srsenb/test/mac/sched_ue_ded_test_suite.cc b/srsenb/test/mac/sched_ue_ded_test_suite.cc index 526a73ec3..63fc56b87 100644 --- a/srsenb/test/mac/sched_ue_ded_test_suite.cc +++ b/srsenb/test/mac/sched_ue_ded_test_suite.cc @@ -41,6 +41,13 @@ int sim_ue_ctxt_t::enb_to_ue_cc_idx(uint32_t enb_cc_idx) const return it == ue_cfg.supported_cc_list.end() ? -1 : std::distance(ue_cfg.supported_cc_list.begin(), it); } +const phich_t* find_phich_grant(uint16_t rnti, const sched_interface::ul_sched_res_t& ul_cc_res) +{ + const phich_t* phich_ptr = std::find_if( + ul_cc_res.phich.begin(), ul_cc_res.phich.end(), [rnti](const phich_t& phich) { return phich.rnti == rnti; }); + return phich_ptr == ul_cc_res.phich.end() ? nullptr : phich_ptr; +} + const pusch_t* find_pusch_grant(uint16_t rnti, const sched_interface::ul_sched_res_t& ul_cc_res) { const pusch_t* ptr = std::find_if( @@ -129,6 +136,22 @@ int test_dl_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& return SRSRAN_SUCCESS; } +bool is_in_measgap(srsran::tti_point tti, uint32_t period, uint32_t offset) +{ + if (period == 0) { + return false; + } + uint32_t T = period / 10; + for (uint32_t i = 0; i < 6; ++i) { + tti_point tti_gap_start = tti - i; + bool is_gap_start = (tti_gap_start.sfn() % T == offset / 10) and (tti_gap_start.sf_idx() == offset % 10); + if (is_gap_start) { + return true; + } + } + return false; +} + int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out) { uint32_t pid = to_tx_ul(sf_out.tti_rx).to_uint() % (FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS); @@ -156,9 +179,7 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& uint16_t rnti = ue.rnti; int ue_cc_idx = ue.enb_to_ue_cc_idx(cc); - const phich_t* phich_ptr = - std::find_if(phich_begin, phich_end, [rnti](const phich_t& phich) { return phich.rnti == rnti; }); - phich_ptr = phich_ptr == phich_end ? nullptr : phich_ptr; + const phich_t* phich_ptr = find_phich_grant(rnti, sf_out.ul_cc_result[cc]); const pusch_t* pusch_ptr = find_pusch_grant(rnti, sf_out.ul_cc_result[cc]); // TEST: Check that idle CCs do not receive PUSCH grants or PHICH @@ -171,19 +192,26 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& const auto& h = ue.cc_list[ue_cc_idx].ul_harqs[pid]; bool phich_ack = phich_ptr != nullptr and phich_ptr->phich == phich_t::ACK; bool is_msg3 = h.first_tti_rx == ue.msg3_tti_rx and h.nof_txs == h.nof_retxs + 1; - bool last_retx = h.nof_retxs + 1 >= (is_msg3 ? sf_out.cc_params[0].cfg.maxharq_msg3tx : ue.ue_cfg.maxharq_tx); - bool h_inactive = (not h.active) or (phich_ack or last_retx); - - // TEST: Already active UL HARQs have to receive PHICH - CONDERROR(h.active and phich_ptr == nullptr, "PHICH not received for rnti=0x%x active UL HARQ pid=%d", rnti, pid); + bool last_retx = h.nof_retxs + 1 >= (is_msg3 ? sf_out.cc_params[0].cfg.maxharq_msg3tx : ue.ue_cfg.maxharq_tx); + tti_point tti_tx_phich = to_tx_dl(sf_out.tti_rx); + bool phich_in_meas_gap = is_in_measgap(tti_tx_phich, ue.ue_cfg.measgap_period, ue.ue_cfg.measgap_offset); + bool h_inactive_now = (not h.active) or (phich_ack or last_retx or phich_in_meas_gap); + + // TEST: Already active UL HARQs have to receive PHICH (unless MeasGap collision) + CONDERROR(h.active and phich_ptr == nullptr and not phich_in_meas_gap, + "PHICH not received for rnti=0x%x active UL HARQ pid=%d", + rnti, + pid); CONDERROR(not h.active and phich_ptr != nullptr, "PHICH for rnti=0x%x corresponds to inactive UL HARQ pid=%d", rnti, pid); // TEST: absent PUSCH grants for active UL HARQs must be either ACKs, last retx, or interrupted HARQs - if ((phich_ptr != nullptr) and (pusch_ptr == nullptr)) { - CONDERROR(not h_inactive, "PHICH NACK received for rnti=0x%x but no PUSCH retx reallocated", rnti); + if (phich_ptr != nullptr) { + CONDERROR(not h_inactive_now and pusch_ptr == nullptr, + "PHICH NACK received for rnti=0x%x but no PUSCH retx reallocated", + rnti); } if (pusch_ptr != nullptr) { @@ -196,7 +224,7 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& // newtx CONDERROR(nof_retx != 0, "Invalid rv index for new UL tx"); CONDERROR(pusch_ptr->current_tx_nb != 0, "UL HARQ retxs need to have been previously transmitted"); - CONDERROR(not h_inactive, "New tx for already active UL HARQ"); + CONDERROR(not h_inactive_now, "New tx for already active UL HARQ"); CONDERROR(not pusch_ptr->needs_pdcch and ue.msg3_tti_rx.is_valid() and sf_out.tti_rx > ue.msg3_tti_rx, "In case of newtx, PDCCH allocation is required, unless it is Msg3"); } else { @@ -211,11 +239,11 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& } else { // non-adaptive retx CONDERROR(pusch_ptr->dci.type2_alloc.riv != h.riv, "Non-adaptive retx must keep the same riv"); + CONDERROR(to_tx_ul(h.last_tti_rx) > sf_out.tti_rx, "UL harq pid=%d was reused too soon", h.pid); } } CONDERROR(get_rvidx(h.nof_retxs + 1) != (uint32_t)pusch_ptr->dci.tb.rv, "Invalid rv index for retx"); CONDERROR(h.tbs != pusch_ptr->tbs, "TBS changed during HARQ retx"); - CONDERROR(to_tx_ul(h.last_tti_rx) > sf_out.tti_rx, "UL harq pid=%d was reused too soon", h.pid); } } } @@ -355,12 +383,6 @@ int test_ra(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out) return SRSRAN_SUCCESS; } -bool is_in_measgap(srsran::tti_point tti, uint32_t period, uint32_t offset) -{ - uint32_t T = period / 10; - return (tti.sfn() % T == offset / 10) and (tti.sf_idx() == offset % 10); -} - int test_meas_gaps(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out) { for (uint32_t cc = 0; cc < enb_ctxt.cell_params.size(); ++cc) { @@ -371,16 +393,19 @@ int test_meas_gaps(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out uint16_t rnti = ue.rnti; uint32_t ue_cc_idx = ue.enb_to_ue_cc_idx(cc); srsran::tti_point tti_tx_ul = to_tx_ul(sf_out.tti_rx), tti_tx_dl = to_tx_dl(sf_out.tti_rx), - tti_tx_dl_ack = to_tx_dl_ack(sf_out.tti_rx), tti_tx_phich = to_tx_ul_ack(sf_out.tti_rx); + tti_tx_dl_ack = to_tx_dl_ack(sf_out.tti_rx); if (ue_cc_idx != 0 or ue.ue_cfg.measgap_period == 0) { continue; } - if (is_in_measgap(tti_tx_ul, ue.ue_cfg.measgap_period, ue.ue_cfg.measgap_offset) or - is_in_measgap(tti_tx_phich, ue.ue_cfg.measgap_period, ue.ue_cfg.measgap_offset)) { + if (is_in_measgap(tti_tx_dl, ue.ue_cfg.measgap_period, ue.ue_cfg.measgap_offset)) { + const phich_t* phich_ptr = find_phich_grant(rnti, ul_cc_res); + CONDERROR(phich_ptr != nullptr, "PHICH grants cannot fall in UE measGap"); + } + if (is_in_measgap(tti_tx_ul, ue.ue_cfg.measgap_period, ue.ue_cfg.measgap_offset)) { const pusch_t* pusch_ptr = find_pusch_grant(rnti, ul_cc_res); - CONDERROR(pusch_ptr != nullptr, "PUSCH grants and PHICH cannot fall in UE measGap"); + CONDERROR(pusch_ptr != nullptr, "PUSCH grants cannot fall in UE measGap"); } if (is_in_measgap(tti_tx_dl, ue.ue_cfg.measgap_period, ue.ue_cfg.measgap_offset) or is_in_measgap(tti_tx_dl_ack, ue.ue_cfg.measgap_period, ue.ue_cfg.measgap_offset)) {