sched,enhancement: allow PUSCH allocations when PHICH falls in measurement Gap by resuming UL HARQ

master
Francisco 4 years ago committed by Francisco Paisana
parent f36f5271d3
commit 2cdda3b6db

@ -138,6 +138,7 @@ public:
bool pdsch_enabled(tti_point tti_rx, uint32_t enb_cc_idx) const; 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 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: private:
bool is_sr_triggered(); bool is_sr_triggered();

@ -106,12 +106,14 @@ public:
uint32_t get_pending_data() const; uint32_t get_pending_data() const;
bool has_pending_phich() const; bool has_pending_phich() const;
bool pop_pending_phich(); bool pop_pending_phich();
void phich_alloc_failed();
private: private:
prb_interval allocation; prb_interval allocation;
int pending_data; int pending_data;
bool pending_phich = false; bool pending_phich = false;
bool is_msg3_ = false; bool is_msg3_ = false;
bool pdcch_required = false;
}; };
class harq_entity class harq_entity
@ -161,7 +163,7 @@ public:
int set_ul_crc(srsran::tti_point tti_tx_ul, uint32_t tb_idx, bool ack_); 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 //! 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: private:
dl_harq_proc* get_oldest_dl_harq(tti_point tti_tx_dl); dl_harq_proc* get_oldest_dl_harq(tti_point tti_tx_dl);

@ -623,12 +623,6 @@ alloc_result sf_sched::alloc_phich(sched_ue* user)
{ {
using phich_t = sched_interface::ul_sched_phich_t; 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); auto p = user->get_active_cell_index(cc_cfg->enb_cc_idx);
if (not p.first) { if (not p.first) {
// user does not support this carrier // 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); 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 */ auto* ul_sf_result = &cc_results->get_cc(cc_cfg->enb_cc_idx)->ul_sched_result;
if (h->has_pending_phich()) { if (ul_sf_result->phich.full()) {
ul_sf_result->phich.emplace_back(); logger.warning("SCHED: Maximum number of PHICH allocations has been reached");
ul_sf_result->phich.back().rnti = user->get_rnti(); h->phich_alloc_failed();
ul_sf_result->phich.back().phich = h->pop_pending_phich() ? phich_t::ACK : phich_t::NACK; return alloc_result::no_grant_space;
return alloc_result::success;
} }
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, void sf_sched::set_dl_data_sched_result(const sf_cch_allocator::alloc_result_t& dci_result,

@ -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}; tti_interval meas_gap{mgap_tti, mgap_tti + 6};
// disable TTIs that leads to PUSCH tx or PHICH rx falling in measGap // 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; return false;
} }
// disable TTIs which respective PDCCH falls in measGap (in case PDCCH is needed) // 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; 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) 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); return cells[enb_cc_idx].set_ack_info(tti_rx, tb_idx, ack);

@ -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() void harq_proc::reset_pending_data_common()
{ {
// reuse harqs with no retxs for (bool& tb : active) {
if (max_retx == 0 and not is_empty()) { 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; allocation = alloc;
new_tx_common(0, tti_point{tti_}, mcs, tbs, max_retx_); new_tx_common(0, tti_point{tti_}, mcs, tbs, max_retx_);
pending_data = tbs; pending_data = tbs;
pending_phich = true; pending_phich = true;
is_msg3_ = is_msg3; is_msg3_ = is_msg3;
pdcch_required = false;
} }
void ul_harq_proc::new_retx(tti_point tti_, int* mcs, int* tbs, prb_interval alloc) 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) // If PRBs changed, or there was no tx in last oportunity (e.g. HARQ is being resumed)
allocation = alloc; allocation = alloc;
new_retx_common(0, tti_point{tti_}, mcs, tbs); 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_) 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; 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() 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]; bool ret = ack_state[0];
pending_phich = false; pending_phich = false;
if (is_empty(0)) { if (is_empty(0)) {
// fully reset UL HARQ once PHICH is dispatched // fully reset HARQ info once PHICH is dispatched for an acked / maxretx reached HARQ
is_msg3_ = false; reset_pending_data();
pending_data = 0;
} }
return ret; return ret;
} }
@ -298,10 +307,9 @@ bool ul_harq_proc::pop_pending_phich()
void ul_harq_proc::reset_pending_data() void ul_harq_proc::reset_pending_data()
{ {
reset_pending_data_common(); reset_pending_data_common();
if (is_empty(0)) { pending_data = 0;
pending_data = 0; is_msg3_ = false;
is_msg3_ = false; pdcch_required = false;
}
} }
uint32_t ul_harq_proc::get_pending_data() const 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; 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 UL HARQ if no retxs
auto* hul = get_ul_harq(to_tx_ul(tti_rx));
// Reset ACK state of UL Harq if (not hul->is_empty() and hul->max_nof_retx() == 0) {
get_ul_harq(tti_tx_ul)->reset_pending_data(); hul->reset_pending_data();
}
// Reset any DL harq which has 0 retxs // Reset DL harq which has 0 retxs
for (auto& h : dl_harqs) { 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();
}
} }
} }

@ -160,7 +160,7 @@ void sched_ue_cell::clear_feedback()
void sched_ue_cell::finish_tti(tti_point tti_rx) void sched_ue_cell::finish_tti(tti_point tti_rx)
{ {
// clear_feedback PIDs with pending data or blocked // 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_) int sched_ue_cell::set_dl_wb_cqi(tti_point tti_rx, uint32_t dl_cqi_)

@ -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); 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) { 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 // 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) { 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]; const auto& phich = sf_out.ul_cc_result[cc].phich[i];
if (phich.rnti != ctxt.rnti) { if (phich.rnti != ctxt.rnti) {
continue; continue;
} }
found_phich = true;
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];
bool is_ack = phich.phich == phich_t::ACK; bool is_ack = phich.phich == phich_t::ACK;
bool is_msg3 = bool is_msg3 =
@ -126,6 +128,11 @@ void ue_sim::update_ul_harqs(const sf_output_res_t& sf_out)
h.active = false; 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 // Update UL harqs with PUSCH grants
for (uint32_t i = 0; i < sf_out.ul_cc_result[cc].pusch.size(); ++i) { 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) { if (data.dci.rnti != ctxt.rnti) {
continue; 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) { if (h.nof_txs == 0 or h.ndi != data.dci.tb.ndi) {
// newtx // newtx

@ -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.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_period = pick_random_uniform({0, 40, 80});
sim_gen.sim_args.default_ue_sim_cfg.ue_cfg.measgap_offset = std::uniform_int_distribution<uint32_t>{ sim_gen.sim_args.default_ue_sim_cfg.ue_cfg.measgap_offset = std::uniform_int_distribution<uint32_t>{
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 = sim_gen.sim_args.default_ue_sim_cfg.ue_cfg.pucch_cfg.n_pucch_sr =
std::uniform_int_distribution<uint32_t>{0, 2047}(srsenb::get_rand_gen()); std::uniform_int_distribution<uint32_t>{0, 2047}(srsenb::get_rand_gen());

@ -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); 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* find_pusch_grant(uint16_t rnti, const sched_interface::ul_sched_res_t& ul_cc_res)
{ {
const pusch_t* ptr = std::find_if( 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; 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) 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); 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; uint16_t rnti = ue.rnti;
int ue_cc_idx = ue.enb_to_ue_cc_idx(cc); int ue_cc_idx = ue.enb_to_ue_cc_idx(cc);
const phich_t* phich_ptr = const phich_t* phich_ptr = find_phich_grant(rnti, sf_out.ul_cc_result[cc]);
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 pusch_t* pusch_ptr = find_pusch_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 // 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]; 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 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 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 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); 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);
// TEST: Already active UL HARQs have to receive PHICH bool h_inactive_now = (not h.active) or (phich_ack or last_retx or phich_in_meas_gap);
CONDERROR(h.active and phich_ptr == nullptr, "PHICH not received for rnti=0x%x active UL HARQ pid=%d", rnti, pid);
// 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, CONDERROR(not h.active and phich_ptr != nullptr,
"PHICH for rnti=0x%x corresponds to inactive UL HARQ pid=%d", "PHICH for rnti=0x%x corresponds to inactive UL HARQ pid=%d",
rnti, rnti,
pid); pid);
// TEST: absent PUSCH grants for active UL HARQs must be either ACKs, last retx, or interrupted HARQs // 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)) { if (phich_ptr != nullptr) {
CONDERROR(not h_inactive, "PHICH NACK received for rnti=0x%x but no PUSCH retx reallocated", rnti); 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) { 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 // newtx
CONDERROR(nof_retx != 0, "Invalid rv index for new UL tx"); 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(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, 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"); "In case of newtx, PDCCH allocation is required, unless it is Msg3");
} else { } else {
@ -211,11 +239,11 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t&
} else { } else {
// non-adaptive retx // non-adaptive retx
CONDERROR(pusch_ptr->dci.type2_alloc.riv != h.riv, "Non-adaptive retx must keep the same riv"); 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(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(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; 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) 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) { 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; uint16_t rnti = ue.rnti;
uint32_t ue_cc_idx = ue.enb_to_ue_cc_idx(cc); 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), 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) { if (ue_cc_idx != 0 or ue.ue_cfg.measgap_period == 0) {
continue; continue;
} }
if (is_in_measgap(tti_tx_ul, ue.ue_cfg.measgap_period, ue.ue_cfg.measgap_offset) or if (is_in_measgap(tti_tx_dl, ue.ue_cfg.measgap_period, ue.ue_cfg.measgap_offset)) {
is_in_measgap(tti_tx_phich, 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); 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 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)) { is_in_measgap(tti_tx_dl_ack, ue.ue_cfg.measgap_period, ue.ue_cfg.measgap_offset)) {

Loading…
Cancel
Save