diff --git a/srsenb/test/mac/scheduler_test_common.cc b/srsenb/test/mac/scheduler_test_common.cc index 49d37f3a9..7122521da 100644 --- a/srsenb/test/mac/scheduler_test_common.cc +++ b/srsenb/test/mac/scheduler_test_common.cc @@ -318,6 +318,7 @@ int ue_state::set_cfg(const sched::ue_cfg_t& ue_cfg_) active_ccs.back().enb_cc_idx = cc.enb_cc_idx; for (size_t i = 0; i < active_ccs.back().dl_harqs.size(); ++i) { active_ccs.back().dl_harqs[i].pid = i; + active_ccs.back().ul_harqs[i].pid = i; } } else { CONDERROR(cc.enb_cc_idx != active_ccs[ue_cc_idx].enb_cc_idx, "changing ccs not supported\n"); @@ -348,7 +349,8 @@ int ue_state::fwd_pending_acks(sched* sched_ptr) { /* Ack DL HARQs */ // Checks: - // - Pending DL ACK {cc_idx,rnti,tb} exist in scheduler + // - Pending DL ACK {cc_idx,rnti,tb} exist in scheduler harqs + // - Pending DL ACK tti_ack correspond to the expected based on tti_tx_dl while (not pending_dl_acks.empty()) { auto& p = pending_dl_acks.top(); if (p.tti_ack > current_tti_rx) { @@ -356,6 +358,7 @@ int ue_state::fwd_pending_acks(sched* sched_ptr) } auto& h = active_ccs[p.ue_cc_idx].dl_harqs[p.pid]; CONDERROR(not h.active, "The ACKed DL Harq pid=%d is not active\n", h.pid); + CONDERROR(h.tti_tx + FDD_HARQ_DELAY_UL_MS != p.tti_ack, "dl ack hasn't arrived when expected\n"); CONDERROR(sched_ptr->dl_ack_info(current_tti_rx.to_uint(), rnti, p.cc_idx, p.tb, p.ack) <= 0, "The ACKed DL Harq pid=%d does not exist.\n", p.pid); @@ -368,10 +371,24 @@ int ue_state::fwd_pending_acks(sched* sched_ptr) } /* Ack UL HARQs */ - auto& p2 = pending_ul_acks[current_tti_rx.to_uint() % pending_ul_acks.size()]; - if (p2.tti_ack == current_tti_rx) { - TESTASSERT(sched_ptr->ul_crc_info(current_tti_rx.to_uint(), rnti, p2.cc_idx, p2.ack) == SRSLTE_SUCCESS); + while (not pending_ul_acks.empty()) { + auto& p = pending_ul_acks.top(); + if (p.tti_ack > current_tti_rx) { + break; + } + auto& h = active_ccs[p.ue_cc_idx].ul_harqs[p.pid]; + CONDERROR(not h.active, "The ACKed UL Harq pid=%d is not active\n", h.pid); + CONDERROR(h.tti_tx != p.tti_ack, "UL CRC wasn't set when expected\n"); + CONDERROR(sched_ptr->ul_crc_info(current_tti_rx.to_uint(), rnti, p.cc_idx, p.ack) != SRSLTE_SUCCESS, + "Failed UL ACK\n"); + + if (p.ack) { + h.active = false; + log_h->info("UL ACK tti=%u rnti=0x%x pid=%d\n", current_tti_rx.to_uint(), rnti, p.pid); + } + pending_ul_acks.pop(); } + return SRSLTE_SUCCESS; } @@ -398,6 +415,8 @@ int ue_state::test_harqs(cc_result result) // unsupported carrier return SRSLTE_SUCCESS; } + + /* Test DL Harqs */ for (uint32_t i = 0; i < result.dl_result->nof_data_elems; ++i) { const auto& data = result.dl_result->data[i]; if (data.dci.rnti != rnti) { @@ -422,19 +441,61 @@ int ue_state::test_harqs(cc_result result) CONDERROR(sched_utils::get_rvidx(h.nof_retxs + 1) != (uint32_t)data.dci.tb[0].rv, "Invalid rv index for retx\n"); CONDERROR(h.ndi != data.dci.tb[0].ndi, "Invalid ndi for retx\n"); CONDERROR(not h.active, "retx for inactive dl harq pid=%d\n", h.pid); - CONDERROR(h.tti_tx + FDD_HARQ_DELAY_UL_MS > current_tti_rx, "harq pid=%d reused too soon\n", h.pid); + CONDERROR(h.tti_tx > current_tti_rx, "harq pid=%d reused too soon\n", h.pid); h.nof_retxs++; h.tti_tx = srslte::to_tx_dl(current_tti_rx); } h.nof_txs++; } + + /* Test UL Harqs */ + for (uint32_t i = 0; i < result.ul_result->nof_dci_elems; ++i) { + const auto& pusch = result.ul_result->pusch[i]; + if (pusch.dci.rnti != rnti) { + continue; + } + + CONDERROR(pusch.dci.ue_cc_idx != cc->ue_cc_idx, "invalid ue_cc_idx=%d in sched result\n", pusch.dci.ue_cc_idx); + auto& h = cc->ul_harqs[srslte::to_tx_ul(current_tti_rx).to_uint() % cc->ul_harqs.size()]; + uint32_t nof_retx = sched_utils::get_nof_retx(pusch.dci.tb.rv); // 0..3 + + if (h.nof_txs == 0 or h.ndi != pusch.dci.tb.ndi) { + // newtx + CONDERROR(nof_retx != 0, "Invalid rv index for new tx\n"); + + h.active = true; + h.nof_retxs = 0; + h.ndi = pusch.dci.tb.ndi; + } else { + if (pusch.needs_pdcch) { + // adaptive retx + } else { + // non-adaptive retx + CONDERROR(pusch.dci.type2_alloc.riv != h.riv, "Non-adaptive retx must keep the same riv\n"); + } + CONDERROR(sched_utils::get_rvidx(h.nof_retxs + 1) != (uint32_t)pusch.dci.tb.rv, "Invalid rv index for retx\n"); + CONDERROR(h.ndi != pusch.dci.tb.ndi, "Invalid ndi for retx\n"); + CONDERROR(not h.active, "retx for inactive UL harq pid=%d\n", h.pid); + CONDERROR(h.tti_tx > current_tti_rx, "UL harq pid=%d was reused too soon\n", h.pid); + + h.nof_retxs++; + } + h.tti_tx = srslte::to_tx_ul(current_tti_rx); + h.riv = pusch.dci.type2_alloc.riv; + h.nof_txs++; + } + return SRSLTE_SUCCESS; } int ue_state::schedule_acks(cc_result result) { - // schedule future DL Acks + auto* cc = get_cc_state(result.enb_cc_idx); + if (cc == nullptr) { + return SRSLTE_SUCCESS; + } + /* Schedule DL ACKs */ for (uint32_t i = 0; i < result.dl_result->nof_data_elems; ++i) { const auto& data = result.dl_result->data[i]; if (data.dci.rnti != rnti) { @@ -452,23 +513,24 @@ int ue_state::schedule_acks(cc_result result) pending_dl_acks.push(ack_data); } - // /* Schedule UL ACKs */ - // for (uint32_t i = 0; i < tti_info.ul_sched_result[ccidx].nof_dci_elems; ++i) { - // const auto& pusch = tti_info.ul_sched_result[ccidx].pusch[i]; - // ul_ack_info_t ack_data; - // ack_data.rnti = pusch.dci.rnti; - // ack_data.enb_cc_idx = ccidx; - // ack_data.ue_cc_idx = ue_db[ack_data.rnti].get_cell_index(ccidx).second; - // ack_data.ul_harq = *ue_db[ack_data.rnti].get_ul_harq(tti_info.tti_params.tti_tx_ul, ack_data.ue_cc_idx); - // ack_data.tti_tx_ul = tti_info.tti_params.tti_tx_ul; - // ack_data.tti_ack = tti_info.tti_params.tti_tx_ul + FDD_HARQ_DELAY_UL_MS; - // if (ack_data.ul_harq.nof_retx(0) == 0) { - // ack_data.ack = randf() > sim_args0.P_retx; - // } else { - // ack_data.ack = ack_data.ul_harq.nof_retx(0) == 2; - // } - // to_ul_ack.insert(std::make_pair(ack_data.tti_tx_ul, ack_data)); - // } + /* Schedule UL ACKs */ + for (uint32_t i = 0; i < result.ul_result->nof_dci_elems; ++i) { + const auto& pusch = result.ul_result->pusch[i]; + if (pusch.dci.rnti != rnti) { + continue; + } + + pending_ack_t ack_data; + ack_data.tti_ack = srslte::to_tx_ul(current_tti_rx); + ack_data.cc_idx = result.enb_cc_idx; + ack_data.ue_cc_idx = pusch.dci.ue_cc_idx; + ack_data.tb = 0; + ack_data.pid = srslte::to_tx_ul(current_tti_rx).to_uint() % cc->ul_harqs.size(); + uint32_t nof_retx = sched_utils::get_nof_retx(pusch.dci.tb.rv); // 0..3 + ack_data.ack = randf() < prob_ul_ack_mask[nof_retx % prob_ul_ack_mask.size()]; + + pending_ul_acks.push(ack_data); + } return SRSLTE_SUCCESS; } @@ -883,75 +945,6 @@ void common_sched_tester::new_test_tti() tester_log->step(tti_info.tti_params.tti_rx); } -int common_sched_tester::process_ack_txs() -{ - /* check if user was removed. If so, clean respective acks */ - erase_if(to_ack, - [this](std::pair& elem) { return this->ue_db.count(elem.second.rnti) == 0; }); - erase_if(to_ul_ack, - [this](std::pair& elem) { return this->ue_db.count(elem.second.rnti) == 0; }); - - /* Ack UL HARQs */ - for (const auto& ack_it : to_ul_ack) { - if (ack_it.first != tti_info.tti_params.tti_rx) { - continue; - } - const ul_ack_info_t& ul_ack = ack_it.second; - - srsenb::ul_harq_proc* h = ue_db[ul_ack.rnti].get_ul_harq(tti_info.tti_params.tti_rx, ul_ack.ue_cc_idx); - const srsenb::ul_harq_proc& hack = ul_ack.ul_harq; - CONDERROR(h == nullptr or h->get_tti() != hack.get_tti(), "UL Harq TTI does not match the ACK TTI\n"); - CONDERROR(h->is_empty(0), "The acked UL harq is not active\n"); - CONDERROR(hack.is_empty(0), "The acked UL harq was not active\n"); - - ul_crc_info(tti_info.tti_params.tti_rx, ul_ack.rnti, ul_ack.enb_cc_idx, ul_ack.ack); - - CONDERROR(!h->get_pending_data(), "UL harq lost its pending data\n"); - CONDERROR(!h->has_pending_ack(), "ACK/NACKed UL harq should have a pending ACK\n"); - - if (ul_ack.ack) { - CONDERROR(!h->is_empty(), "ACKed UL harq did not get emptied\n"); - CONDERROR(h->has_pending_retx(), "ACKed UL harq still has pending retx\n"); - tester_log->info("UL ACK tti=%u rnti=0x%x pid=%d\n", tti_info.tti_params.tti_rx, ul_ack.rnti, hack.get_id()); - } else { - // NACK - tester_log->info("UL NACK tti=%u rnti=0x%x pid=%d\n", tti_info.tti_params.tti_rx, ul_ack.rnti, hack.get_id()); - CONDERROR(!h->is_empty() and !h->has_pending_retx(), "If NACKed, UL harq has to have pending retx\n"); - CONDERROR(h->is_empty() and hack.nof_retx(0) + 1 < hack.max_nof_retx(), "Nacked UL harq did get emptied\n"); - } - } - - // erase processed acks - to_ack.erase(tti_info.tti_params.tti_rx); - to_ul_ack.erase(tti_info.tti_params.tti_rx); - - return SRSLTE_SUCCESS; -} - -int common_sched_tester::schedule_acks() -{ - for (uint32_t ccidx = 0; ccidx < sched_cell_params.size(); ++ccidx) { - /* Schedule UL ACKs */ - for (uint32_t i = 0; i < tti_info.ul_sched_result[ccidx].nof_dci_elems; ++i) { - const auto& pusch = tti_info.ul_sched_result[ccidx].pusch[i]; - ul_ack_info_t ack_data; - ack_data.rnti = pusch.dci.rnti; - ack_data.enb_cc_idx = ccidx; - ack_data.ue_cc_idx = ue_db[ack_data.rnti].get_cell_index(ccidx).second; - ack_data.ul_harq = *ue_db[ack_data.rnti].get_ul_harq(tti_info.tti_params.tti_tx_ul, ack_data.ue_cc_idx); - ack_data.tti_tx_ul = tti_info.tti_params.tti_tx_ul; - ack_data.tti_ack = tti_info.tti_params.tti_tx_ul + FDD_HARQ_DELAY_UL_MS; - if (ack_data.ul_harq.nof_retx(0) == 0) { - ack_data.ack = randf() > sim_args0.P_retx; - } else { - ack_data.ack = ack_data.ul_harq.nof_retx(0) == 2; - } - to_ul_ack.insert(std::make_pair(ack_data.tti_tx_ul, ack_data)); - } - } - return SRSLTE_SUCCESS; -} - int common_sched_tester::process_results() { for (uint32_t i = 0; i < sched_cell_params.size(); ++i) { @@ -1047,7 +1040,6 @@ int common_sched_tester::run_tti(const tti_ev& tti_events) ue_tester->new_tti(this, tti_info.tti_params.tti_rx); process_tti_events(tti_events); - process_ack_txs(); before_sched(); // Call scheduler for all carriers @@ -1061,7 +1053,6 @@ int common_sched_tester::run_tti(const tti_ev& tti_events) } process_results(); - TESTASSERT(schedule_acks() == SRSLTE_SUCCESS); return SRSLTE_SUCCESS; } diff --git a/srsenb/test/mac/scheduler_test_common.h b/srsenb/test/mac/scheduler_test_common.h index 1d6850a3b..6776492ad 100644 --- a/srsenb/test/mac/scheduler_test_common.h +++ b/srsenb/test/mac/scheduler_test_common.h @@ -104,8 +104,10 @@ struct ue_state { bool ndi = false; uint32_t nof_retxs = 0; uint32_t nof_txs = 0; + uint32_t riv = 0; }; std::array dl_harqs = {}; + std::array ul_harqs = {}; }; std::vector active_ccs; @@ -142,8 +144,7 @@ private: bool ack; bool operator<(const pending_ack_t& other) const { return tti_ack > other.tti_ack; } }; - std::priority_queue pending_dl_acks; - std::array pending_ul_acks; + std::priority_queue pending_dl_acks, pending_ul_acks; }; class user_state_sched_tester @@ -235,8 +236,6 @@ public: int sim_cfg(sim_sched_args args); virtual int add_user(uint16_t rnti, const ue_cfg_t& ue_cfg_); virtual void rem_user(uint16_t rnti); - int process_ack_txs(); - int schedule_acks(); virtual int process_results(); int process_tti_events(const tti_ev& tti_ev); @@ -257,30 +256,8 @@ public: std::unique_ptr sched_stats; protected: - struct ack_info_t { - uint16_t rnti; - uint32_t tti; - uint32_t enb_cc_idx; - uint32_t ue_cc_idx; - bool ack = false; - uint32_t retx_delay = 0; - srsenb::dl_harq_proc dl_harq; - }; - struct ul_ack_info_t { - uint16_t rnti; - uint32_t tti_ack, tti_tx_ul; - uint32_t ue_cc_idx; - uint32_t enb_cc_idx; - bool ack = false; - srsenb::ul_harq_proc ul_harq; - }; - virtual void new_test_tti(); virtual void before_sched() {} - - // control params - std::multimap to_ack; - std::multimap to_ul_ack; }; } // namespace srsenb