mirror of https://github.com/PentHertz/srsLTE.git
moved UE-dedicated RA sched test to separate test suite file.
This commit is contained in:
parent
d5f6ccc0c4
commit
992ea7fd29
|
@ -20,23 +20,52 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "sched_sim_ue.h"
|
#include "sched_sim_ue.h"
|
||||||
|
#include "lib/include/srslte/mac/pdu.h"
|
||||||
|
|
||||||
namespace srsenb {
|
namespace srsenb {
|
||||||
|
|
||||||
using phich_t = sched_interface::ul_sched_phich_t;
|
using phich_t = sched_interface::ul_sched_phich_t;
|
||||||
|
|
||||||
ue_sim::ue_sim(uint16_t rnti_, const sched_interface::ue_cfg_t& ue_cfg_, srslte::tti_point prach_tti_rx_)
|
bool sim_ue_ctxt_t::is_msg3_harq(uint32_t ue_cc_idx, uint32_t pid) const
|
||||||
|
{
|
||||||
|
auto& h = cc_list.at(ue_cc_idx).ul_harqs[pid];
|
||||||
|
return h.first_tti_rx == msg3_tti_rx and h.nof_txs == h.nof_retxs + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sim_ue_ctxt_t::is_last_ul_retx(uint32_t ue_cc_idx, uint32_t pid, uint32_t maxharq_msg3tx) const
|
||||||
|
{
|
||||||
|
bool is_msg3 = is_msg3_harq(ue_cc_idx, pid);
|
||||||
|
auto& h = cc_list.at(ue_cc_idx).ul_harqs[pid];
|
||||||
|
return h.nof_retxs + 1 >= (is_msg3 ? maxharq_msg3tx : ue_cfg.maxharq_tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sim_ue_ctxt_t::is_last_dl_retx(uint32_t ue_cc_idx, uint32_t pid) const
|
||||||
|
{
|
||||||
|
auto& h = cc_list.at(ue_cc_idx).dl_harqs[pid];
|
||||||
|
return h.nof_retxs + 1 >= ue_cfg.maxharq_tx;
|
||||||
|
}
|
||||||
|
|
||||||
|
ue_sim::ue_sim(uint16_t rnti_,
|
||||||
|
const sched_interface::ue_cfg_t& ue_cfg_,
|
||||||
|
srslte::tti_point prach_tti_rx_,
|
||||||
|
uint32_t preamble_idx)
|
||||||
{
|
{
|
||||||
ctxt.rnti = rnti_;
|
ctxt.rnti = rnti_;
|
||||||
ctxt.ue_cfg = ue_cfg_;
|
|
||||||
ctxt.prach_tti_rx = prach_tti_rx_;
|
ctxt.prach_tti_rx = prach_tti_rx_;
|
||||||
ctxt.cc_list.resize(ue_cfg_.supported_cc_list.size());
|
ctxt.preamble_idx = preamble_idx;
|
||||||
|
set_cfg(ue_cfg_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ue_sim::set_cfg(const sched_interface::ue_cfg_t& ue_cfg_)
|
void ue_sim::set_cfg(const sched_interface::ue_cfg_t& ue_cfg_)
|
||||||
{
|
{
|
||||||
ctxt.ue_cfg = ue_cfg_;
|
ctxt.ue_cfg = ue_cfg_;
|
||||||
ctxt.cc_list.resize(ue_cfg_.supported_cc_list.size());
|
ctxt.cc_list.resize(ue_cfg_.supported_cc_list.size());
|
||||||
|
for (auto& cc : ctxt.cc_list) {
|
||||||
|
for (size_t pid = 0; pid < (FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS); ++pid) {
|
||||||
|
cc.ul_harqs[pid].pid = pid;
|
||||||
|
cc.dl_harqs[pid].pid = pid;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ue_sim::enqueue_pending_acks(srslte::tti_point tti_rx,
|
bool ue_sim::enqueue_pending_acks(srslte::tti_point tti_rx,
|
||||||
|
@ -92,14 +121,16 @@ void ue_sim::update_dl_harqs(const sf_output_res_t& sf_out)
|
||||||
auto& h = ctxt.cc_list[data.dci.ue_cc_idx].dl_harqs[data.dci.pid];
|
auto& h = ctxt.cc_list[data.dci.ue_cc_idx].dl_harqs[data.dci.pid];
|
||||||
if (h.nof_txs == 0 or h.ndi != data.dci.tb[0].ndi) {
|
if (h.nof_txs == 0 or h.ndi != data.dci.tb[0].ndi) {
|
||||||
// It is newtx
|
// It is newtx
|
||||||
h.active = true;
|
|
||||||
h.nof_retxs = 0;
|
h.nof_retxs = 0;
|
||||||
h.ndi = data.dci.tb[0].ndi;
|
h.ndi = data.dci.tb[0].ndi;
|
||||||
|
h.first_tti_rx = sf_out.tti_rx;
|
||||||
} else {
|
} else {
|
||||||
// it is retx
|
// it is retx
|
||||||
h.nof_retxs++;
|
h.nof_retxs++;
|
||||||
}
|
}
|
||||||
|
h.active = true;
|
||||||
h.last_tti_rx = sf_out.tti_rx;
|
h.last_tti_rx = sf_out.tti_rx;
|
||||||
|
h.nof_txs++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,19 +187,68 @@ void ue_sim::update_ul_harqs(const sf_output_res_t& sf_out)
|
||||||
|
|
||||||
void ue_sim::update_conn_state(const sf_output_res_t& sf_out)
|
void ue_sim::update_conn_state(const sf_output_res_t& sf_out)
|
||||||
{
|
{
|
||||||
if (not ctxt.msg3_tti_rx.is_valid()) {
|
if (ctxt.msg4_tti_rx.is_valid()) {
|
||||||
auto& cc_result = sf_out.ul_cc_result[ctxt.ue_cfg.supported_cc_list[0].enb_cc_idx];
|
return;
|
||||||
for (uint32_t i = 0; i < cc_result.nof_dci_elems; ++i) {
|
}
|
||||||
if (cc_result.pusch[i].dci.rnti == ctxt.rnti) {
|
|
||||||
|
// only check for RAR/Msg3 presence for a UE's PCell
|
||||||
|
uint32_t cc = ctxt.ue_cfg.supported_cc_list[0].enb_cc_idx;
|
||||||
|
const auto& dl_cc_result = sf_out.dl_cc_result[cc];
|
||||||
|
const auto& ul_cc_result = sf_out.ul_cc_result[cc];
|
||||||
|
srslte::tti_point tti_tx_dl = to_tx_dl(sf_out.tti_rx);
|
||||||
|
|
||||||
|
if (not ctxt.rar_tti_rx.is_valid()) {
|
||||||
|
// RAR not yet found
|
||||||
|
uint32_t rar_win_size = sf_out.cc_params[cc].cfg.prach_rar_window;
|
||||||
|
srslte::tti_interval rar_window{ctxt.prach_tti_rx + 3, ctxt.prach_tti_rx + 3 + rar_win_size};
|
||||||
|
|
||||||
|
if (rar_window.contains(tti_tx_dl)) {
|
||||||
|
for (uint32_t i = 0; i < dl_cc_result.nof_rar_elems; ++i) {
|
||||||
|
for (uint32_t j = 0; j < dl_cc_result.rar[i].nof_grants; ++j) {
|
||||||
|
const auto& data = dl_cc_result.rar[i].msg3_grant[j].data;
|
||||||
|
if (data.prach_tti == (uint32_t)ctxt.prach_tti_rx.to_uint() and data.preamble_idx == ctxt.preamble_idx) {
|
||||||
|
ctxt.rar_tti_rx = sf_out.tti_rx;
|
||||||
|
ctxt.msg3_riv = dl_cc_result.rar[i].msg3_grant[j].grant.rba;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxt.rar_tti_rx.is_valid() and not ctxt.msg3_tti_rx.is_valid()) {
|
||||||
|
// RAR scheduled, Msg3 not yet scheduled
|
||||||
|
srslte::tti_point expected_msg3_tti_rx = ctxt.rar_tti_rx + MSG3_DELAY_MS;
|
||||||
|
if (expected_msg3_tti_rx == sf_out.tti_rx) {
|
||||||
|
// Msg3 should exist
|
||||||
|
for (uint32_t i = 0; i < ul_cc_result.nof_dci_elems; ++i) {
|
||||||
|
if (ul_cc_result.pusch[i].dci.rnti == ctxt.rnti) {
|
||||||
ctxt.msg3_tti_rx = sf_out.tti_rx;
|
ctxt.msg3_tti_rx = sf_out.tti_rx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ue_db_sim::add_user(uint16_t rnti, const sched_interface::ue_cfg_t& ue_cfg_, srslte::tti_point prach_tti_rx_)
|
if (ctxt.msg3_tti_rx.is_valid() and not ctxt.msg4_tti_rx.is_valid()) {
|
||||||
|
// Msg3 scheduled, but Msg4 not yet scheduled
|
||||||
|
for (uint32_t i = 0; i < dl_cc_result.nof_data_elems; ++i) {
|
||||||
|
if (dl_cc_result.data[i].dci.rnti == ctxt.rnti) {
|
||||||
|
for (uint32_t j = 0; j < dl_cc_result.data[i].nof_pdu_elems[0]; ++j) {
|
||||||
|
if (dl_cc_result.data[i].pdu[0][j].lcid == (uint32_t)srslte::dl_sch_lcid::CON_RES_ID) {
|
||||||
|
// ConRes found
|
||||||
|
ctxt.msg4_tti_rx = sf_out.tti_rx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ue_db_sim::add_user(uint16_t rnti,
|
||||||
|
const sched_interface::ue_cfg_t& ue_cfg_,
|
||||||
|
srslte::tti_point prach_tti_rx_,
|
||||||
|
uint32_t preamble_idx)
|
||||||
{
|
{
|
||||||
ue_db.insert(std::make_pair(rnti, ue_sim(rnti, ue_cfg_, prach_tti_rx_)));
|
ue_db.insert(std::make_pair(rnti, ue_sim(rnti, ue_cfg_, prach_tti_rx_, preamble_idx)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ue_db_sim::ue_recfg(uint16_t rnti, const sched_interface::ue_cfg_t& ue_cfg_)
|
void ue_db_sim::ue_recfg(uint16_t rnti, const sched_interface::ue_cfg_t& ue_cfg_)
|
||||||
|
|
|
@ -43,12 +43,16 @@ struct ue_cc_ctxt_t {
|
||||||
};
|
};
|
||||||
struct sim_ue_ctxt_t {
|
struct sim_ue_ctxt_t {
|
||||||
uint16_t rnti;
|
uint16_t rnti;
|
||||||
srslte::tti_point prach_tti_rx, msg3_tti_rx;
|
uint32_t preamble_idx, msg3_riv;
|
||||||
|
srslte::tti_point prach_tti_rx, rar_tti_rx, msg3_tti_rx, msg4_tti_rx;
|
||||||
sched_interface::ue_cfg_t ue_cfg;
|
sched_interface::ue_cfg_t ue_cfg;
|
||||||
std::vector<ue_cc_ctxt_t> cc_list;
|
std::vector<ue_cc_ctxt_t> cc_list;
|
||||||
|
|
||||||
const sched_interface::ue_cfg_t::cc_cfg_t* get_cc_cfg(uint32_t enb_cc_idx) const;
|
const sched_interface::ue_cfg_t::cc_cfg_t* get_cc_cfg(uint32_t enb_cc_idx) const;
|
||||||
int enb_to_ue_cc_idx(uint32_t enb_cc_idx) const;
|
int enb_to_ue_cc_idx(uint32_t enb_cc_idx) const;
|
||||||
|
bool is_msg3_harq(uint32_t ue_cc_idx, uint32_t pid) const;
|
||||||
|
bool is_last_ul_retx(uint32_t ue_cc_idx, uint32_t pid, uint32_t maxharq_msg3tx) const;
|
||||||
|
bool is_last_dl_retx(uint32_t ue_cc_idx, uint32_t pid) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sim_enb_ctxt_t {
|
struct sim_enb_ctxt_t {
|
||||||
|
@ -68,7 +72,10 @@ struct pucch_feedback {
|
||||||
class ue_sim
|
class ue_sim
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ue_sim(uint16_t rnti_, const sched_interface::ue_cfg_t& ue_cfg_, srslte::tti_point prach_tti_rx);
|
ue_sim(uint16_t rnti_,
|
||||||
|
const sched_interface::ue_cfg_t& ue_cfg_,
|
||||||
|
srslte::tti_point prach_tti_rx,
|
||||||
|
uint32_t preamble_idx);
|
||||||
|
|
||||||
void set_cfg(const sched_interface::ue_cfg_t& ue_cfg_);
|
void set_cfg(const sched_interface::ue_cfg_t& ue_cfg_);
|
||||||
|
|
||||||
|
@ -92,12 +99,17 @@ private:
|
||||||
class ue_db_sim
|
class ue_db_sim
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void add_user(uint16_t rnti, const sched_interface::ue_cfg_t& ue_cfg_, srslte::tti_point prach_tti_rx_);
|
void add_user(uint16_t rnti,
|
||||||
|
const sched_interface::ue_cfg_t& ue_cfg_,
|
||||||
|
srslte::tti_point prach_tti_rx_,
|
||||||
|
uint32_t preamble_idx);
|
||||||
void ue_recfg(uint16_t rnti, const sched_interface::ue_cfg_t& ue_cfg_);
|
void ue_recfg(uint16_t rnti, const sched_interface::ue_cfg_t& ue_cfg_);
|
||||||
void rem_user(uint16_t rnti);
|
void rem_user(uint16_t rnti);
|
||||||
|
|
||||||
void update(const sf_output_res_t& sf_out);
|
void update(const sf_output_res_t& sf_out);
|
||||||
std::map<uint16_t, const sim_ue_ctxt_t*> get_ues_ctxt() const;
|
std::map<uint16_t, const sim_ue_ctxt_t*> get_ues_ctxt() const;
|
||||||
|
ue_sim& at(uint16_t rnti) { return ue_db.at(rnti); }
|
||||||
|
const ue_sim& at(uint16_t rnti) const { return ue_db.at(rnti); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<uint16_t, ue_sim> ue_db;
|
std::map<uint16_t, ue_sim> ue_db;
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "sched_ue_ded_test_suite.h"
|
#include "sched_ue_ded_test_suite.h"
|
||||||
|
#include "lib/include/srslte/mac/pdu.h"
|
||||||
#include "srslte/common/test_common.h"
|
#include "srslte/common/test_common.h"
|
||||||
|
|
||||||
namespace srsenb {
|
namespace srsenb {
|
||||||
|
@ -64,6 +65,7 @@ int test_pdsch_grant(const sim_ue_ctxt_t& ue_ctxt,
|
||||||
if (h.nof_txs == 0 or h.ndi != pdsch.dci.tb[0].ndi) {
|
if (h.nof_txs == 0 or h.ndi != pdsch.dci.tb[0].ndi) {
|
||||||
// It is newtx
|
// It is newtx
|
||||||
CONDERROR(nof_retx != 0, "Invalid rv index for new tx\n");
|
CONDERROR(nof_retx != 0, "Invalid rv index for new tx\n");
|
||||||
|
CONDERROR(h.active, "DL newtx for already active DL harq pid=%d\n", h.pid);
|
||||||
} else {
|
} else {
|
||||||
// it is retx
|
// it is retx
|
||||||
CONDERROR(sched_utils::get_rvidx(h.nof_retxs + 1) != (uint32_t)pdsch.dci.tb[0].rv, "Invalid rv index for retx\n");
|
CONDERROR(sched_utils::get_rvidx(h.nof_retxs + 1) != (uint32_t)pdsch.dci.tb[0].rv, "Invalid rv index for retx\n");
|
||||||
|
@ -104,6 +106,7 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t&
|
||||||
const auto& ue = *ue_pair.second;
|
const auto& ue = *ue_pair.second;
|
||||||
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 auto& h = ue.cc_list[ue_cc_idx].ul_harqs[pid];
|
||||||
|
|
||||||
// TEST: Check if CC is configured and active
|
// TEST: Check if CC is configured and active
|
||||||
CONDERROR(ue_cc_idx < 0 or not ue.ue_cfg.supported_cc_list[ue_cc_idx].active,
|
CONDERROR(ue_cc_idx < 0 or not ue.ue_cfg.supported_cc_list[ue_cc_idx].active,
|
||||||
|
@ -116,8 +119,12 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t&
|
||||||
std::find_if(pusch_begin, pusch_end, [rnti](const pusch_t& pusch) { return pusch.dci.rnti == rnti; });
|
std::find_if(pusch_begin, pusch_end, [rnti](const pusch_t& pusch) { return pusch.dci.rnti == rnti; });
|
||||||
pusch_ptr = pusch_ptr == pusch_end ? nullptr : pusch_ptr;
|
pusch_ptr = pusch_ptr == pusch_end ? nullptr : pusch_ptr;
|
||||||
|
|
||||||
|
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
|
// TEST: Already active UL HARQs have to receive PHICH
|
||||||
const auto& h = ue.cc_list[ue_cc_idx].ul_harqs[pid];
|
|
||||||
CONDERROR(
|
CONDERROR(
|
||||||
h.active and phich_ptr == nullptr, "PHICH not received for rnti=0x%x active UL HARQ pid=%d\n", rnti, pid);
|
h.active and phich_ptr == nullptr, "PHICH not received for rnti=0x%x active UL HARQ pid=%d\n", rnti, pid);
|
||||||
CONDERROR(not h.active and phich_ptr != nullptr,
|
CONDERROR(not h.active and phich_ptr != nullptr,
|
||||||
|
@ -127,11 +134,7 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t&
|
||||||
|
|
||||||
// TEST: absent PUSCH grants for active DL HARQs must be either ACKs, last retx, or interrupted HARQs
|
// TEST: absent PUSCH grants for active DL HARQs must be either ACKs, last retx, or interrupted HARQs
|
||||||
if (phich_ptr != nullptr and pusch_ptr == nullptr) {
|
if (phich_ptr != nullptr and pusch_ptr == nullptr) {
|
||||||
bool is_ack = phich_ptr->phich == phich_t::ACK;
|
CONDERROR(not h_inactive, "PHICH NACK received for rnti=0x%x but no PUSCH retx reallocated\n", rnti);
|
||||||
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);
|
|
||||||
CONDERROR(
|
|
||||||
not is_ack and not last_retx, "PHICH NACK received for rnti=0x%x but no PUSCH retx reallocated\n", rnti);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pusch_ptr != nullptr) {
|
if (pusch_ptr != nullptr) {
|
||||||
|
@ -144,6 +147,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 tx\n");
|
CONDERROR(nof_retx != 0, "Invalid rv index for new tx\n");
|
||||||
CONDERROR(pusch_ptr->current_tx_nb != 0, "UL HARQ retxs need to have been previously transmitted\n");
|
CONDERROR(pusch_ptr->current_tx_nb != 0, "UL HARQ retxs need to have been previously transmitted\n");
|
||||||
|
CONDERROR(not h_inactive, "New tx for already active UL HARQ\n");
|
||||||
} else {
|
} else {
|
||||||
CONDERROR(pusch_ptr->current_tx_nb == 0, "UL retx has to have nof tx > 0\n");
|
CONDERROR(pusch_ptr->current_tx_nb == 0, "UL retx has to have nof tx > 0\n");
|
||||||
if (not h.active) {
|
if (not h.active) {
|
||||||
|
@ -169,20 +173,135 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t&
|
||||||
return SRSLTE_SUCCESS;
|
return SRSLTE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int test_ra(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 (const auto& ue_pair : enb_ctxt.ue_db) {
|
||||||
|
const auto& ue = *ue_pair.second;
|
||||||
|
const auto& dl_cc_res = sf_out.dl_cc_result[cc];
|
||||||
|
const auto& ul_cc_res = sf_out.ul_cc_result[cc];
|
||||||
|
uint16_t rnti = ue.rnti;
|
||||||
|
uint32_t ue_cc_idx = ue.enb_to_ue_cc_idx(cc);
|
||||||
|
|
||||||
|
if (ue_cc_idx != 0) {
|
||||||
|
// only check for RAR/Msg3/Msg4 presence for a UE's PCell
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEST: RAR allocation
|
||||||
|
uint32_t rar_win_size = (*enb_ctxt.cell_params)[cc].prach_rar_window;
|
||||||
|
srslte::tti_interval rar_window{ue.prach_tti_rx + 3, ue.prach_tti_rx + 3 + rar_win_size};
|
||||||
|
srslte::tti_point tti_tx_dl = to_tx_dl(sf_out.tti_rx);
|
||||||
|
|
||||||
|
if (not rar_window.contains(tti_tx_dl)) {
|
||||||
|
CONDERROR(not ue.rar_tti_rx.is_valid() and tti_tx_dl > rar_window.stop(),
|
||||||
|
"rnti=0x%x RAR not scheduled within the RAR Window\n",
|
||||||
|
rnti);
|
||||||
|
for (uint32_t i = 0; i < sf_out.dl_cc_result[cc].nof_rar_elems; ++i) {
|
||||||
|
CONDERROR(sf_out.dl_cc_result[cc].rar[i].dci.rnti == rnti,
|
||||||
|
"No RAR allocations allowed outside of user RAR window\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Inside RAR window
|
||||||
|
uint32_t nof_rars = ue.rar_tti_rx.is_valid() ? 1 : 0;
|
||||||
|
for (uint32_t i = 0; i < dl_cc_res.nof_rar_elems; ++i) {
|
||||||
|
for (uint32_t j = 0; j < dl_cc_res.rar[i].nof_grants; ++j) {
|
||||||
|
const auto& data = dl_cc_res.rar[i].msg3_grant[j].data;
|
||||||
|
if (data.prach_tti == (uint32_t)ue.prach_tti_rx.to_uint() and data.preamble_idx == ue.preamble_idx) {
|
||||||
|
CONDERROR(rnti != data.temp_crnti, "RAR grant C-RNTI does not match the expected.\n");
|
||||||
|
nof_rars++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CONDERROR(nof_rars > 1, "There was more than one RAR for the same user\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEST: Msg3 was allocated
|
||||||
|
if (ue.rar_tti_rx.is_valid() and not ue.msg3_tti_rx.is_valid()) {
|
||||||
|
// RAR scheduled, Msg3 not yet scheduled
|
||||||
|
srslte::tti_point expected_msg3_tti_rx = ue.rar_tti_rx + MSG3_DELAY_MS;
|
||||||
|
CONDERROR(expected_msg3_tti_rx < sf_out.tti_rx, "No UL msg3 alloc was made\n");
|
||||||
|
|
||||||
|
if (expected_msg3_tti_rx == sf_out.tti_rx) {
|
||||||
|
// Msg3 should exist
|
||||||
|
uint32_t msg3_count = 0;
|
||||||
|
for (uint32_t i = 0; i < ul_cc_res.nof_dci_elems; ++i) {
|
||||||
|
if (ul_cc_res.pusch[i].dci.rnti == rnti) {
|
||||||
|
msg3_count++;
|
||||||
|
CONDERROR(ul_cc_res.pusch[i].needs_pdcch, "Msg3 allocations do not require PDCCH\n");
|
||||||
|
CONDERROR(ue.msg3_riv != ul_cc_res.pusch[i].dci.type2_alloc.riv,
|
||||||
|
"The Msg3 was not allocated in the expected PRBs.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CONDERROR(msg3_count == 0, "Msg3 was not transmitted.\n");
|
||||||
|
CONDERROR(msg3_count > 1, "Only one Msg3 allower per user.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEST: Check Msg4
|
||||||
|
if (ue.msg3_tti_rx.is_valid() and not ue.msg4_tti_rx.is_valid()) {
|
||||||
|
// Msg3 scheduled, but Msg4 not yet scheduled
|
||||||
|
uint32_t msg4_count = 0;
|
||||||
|
for (uint32_t i = 0; i < dl_cc_res.nof_data_elems; ++i) {
|
||||||
|
if (dl_cc_res.data[i].dci.rnti == rnti) {
|
||||||
|
CONDERROR(to_tx_dl(sf_out.tti_rx) < to_tx_ul(ue.msg3_tti_rx),
|
||||||
|
"Msg4 cannot be scheduled without Msg3 being tx\n");
|
||||||
|
for (uint32_t j = 0; j < dl_cc_res.data[i].nof_pdu_elems[0]; ++j) {
|
||||||
|
if (dl_cc_res.data[i].pdu[0][j].lcid == (uint32_t)srslte::dl_sch_lcid::CON_RES_ID) {
|
||||||
|
// ConRes found
|
||||||
|
CONDERROR(dl_cc_res.data[i].dci.format != SRSLTE_DCI_FORMAT1, "ConRes must be format1\n");
|
||||||
|
msg4_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CONDERROR(msg4_count == 0, "No ConRes CE was scheduled in Msg4\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CONDERROR(msg4_count > 1, "Duplicate ConRes CE for the same rnti\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not ue.msg4_tti_rx.is_valid()) {
|
||||||
|
// TEST: No UL allocs except for Msg3 before Msg4
|
||||||
|
for (uint32_t i = 0; i < ul_cc_res.nof_dci_elems; ++i) {
|
||||||
|
if (ul_cc_res.pusch[i].dci.rnti == rnti) {
|
||||||
|
CONDERROR(not ue.rar_tti_rx.is_valid(), "No UL allocs before RAR allowed\n");
|
||||||
|
srslte::tti_point expected_msg3_tti = ue.rar_tti_rx + MSG3_DELAY_MS;
|
||||||
|
CONDERROR(expected_msg3_tti > sf_out.tti_rx, "No UL allocs before Msg3 is scheduled\n");
|
||||||
|
if (expected_msg3_tti < sf_out.tti_rx) {
|
||||||
|
bool msg3_retx =
|
||||||
|
((ue.msg3_tti_rx - expected_msg3_tti) % (FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS)) == 0;
|
||||||
|
CONDERROR(not msg3_retx, "No UL txs allowed except for Msg3 before user received Msg4\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEST: No DL allocs before Msg3
|
||||||
|
if (not ue.msg3_tti_rx.is_valid()) {
|
||||||
|
for (uint32_t i = 0; i < dl_cc_res.nof_data_elems; ++i) {
|
||||||
|
CONDERROR(dl_cc_res.data[i].dci.rnti == rnti, "No DL data allocs allowed before Msg3 is scheduled\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SRSLTE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
int test_all_ues(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out)
|
int test_all_ues(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) {
|
||||||
// for (uint32_t i = 0; i < sf_out.dl_cc_result[cc].nof_data_elems; ++i) {
|
for (uint32_t i = 0; i < sf_out.dl_cc_result[cc].nof_data_elems; ++i) {
|
||||||
// const sched_interface::dl_sched_data_t& data = sf_out.dl_cc_result[cc].data[i];
|
const sched_interface::dl_sched_data_t& data = sf_out.dl_cc_result[cc].data[i];
|
||||||
// CONDERROR(
|
CONDERROR(
|
||||||
// enb_ctxt.ue_db.count(data.dci.rnti) == 0, "Allocated DL grant for non-existent rnti=0x%x\n",
|
enb_ctxt.ue_db.count(data.dci.rnti) == 0, "Allocated DL grant for non-existent rnti=0x%x\n", data.dci.rnti);
|
||||||
// data.dci.rnti);
|
TESTASSERT(test_pdsch_grant(*enb_ctxt.ue_db.at(data.dci.rnti), sf_out.tti_rx, cc, data) == SRSLTE_SUCCESS);
|
||||||
// TESTASSERT(test_pdsch_grant(*enb_ctxt.ue_db.at(data.dci.rnti), sf_out.tti_rx, cc, data) == SRSLTE_SUCCESS);
|
}
|
||||||
// }
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
TESTASSERT(test_ul_sched_result(enb_ctxt, sf_out) == SRSLTE_SUCCESS);
|
TESTASSERT(test_ul_sched_result(enb_ctxt, sf_out) == SRSLTE_SUCCESS);
|
||||||
|
|
||||||
|
TESTASSERT(test_ra(enb_ctxt, sf_out) == SRSLTE_SUCCESS);
|
||||||
|
|
||||||
return SRSLTE_SUCCESS;
|
return SRSLTE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,16 @@ int test_pdsch_grant(const sim_ue_ctxt_t& ue_ctxt,
|
||||||
*/
|
*/
|
||||||
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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the RAR, Msg3, Msg4 were scheduled within the expected windows. Current tests:
|
||||||
|
* - RAR alloc falls within RAR window and only takes place once per user
|
||||||
|
* - No UL allocs before Msg4 that are not Msg3
|
||||||
|
* - Msg3 is allocated in expected TTI, without PDCCH, and PRBs advertised in RAR
|
||||||
|
* - First Data allocation happens after Msg3 is ACKed, and contains a ConRes CE
|
||||||
|
* - No RARs are allocated with wrong enb_cc_idx, preamble_idx or wrong user
|
||||||
|
*/
|
||||||
|
int test_ra(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t& sf_out);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call all tests that depend on the UE internal state for all registered UEs in the eNB
|
* Call all tests that depend on the UE internal state for all registered UEs in the eNB
|
||||||
* @param enb_ctxt current eNB state, including list of UEs
|
* @param enb_ctxt current eNB state, including list of UEs
|
||||||
|
|
|
@ -60,13 +60,15 @@ ue_ctxt_test::ue_ctxt_test(uint16_t rnti_,
|
||||||
uint32_t preamble_idx_,
|
uint32_t preamble_idx_,
|
||||||
srslte::tti_point prach_tti_,
|
srslte::tti_point prach_tti_,
|
||||||
const ue_ctxt_test_cfg& cfg_,
|
const ue_ctxt_test_cfg& cfg_,
|
||||||
const std::vector<srsenb::sched::cell_cfg_t>& cell_params_) :
|
const std::vector<srsenb::sched::cell_cfg_t>& cell_params_,
|
||||||
|
ue_sim& ue_ctxt_) :
|
||||||
sim_cfg(cfg_),
|
sim_cfg(cfg_),
|
||||||
rnti(rnti_),
|
rnti(rnti_),
|
||||||
prach_tti(prach_tti_),
|
prach_tti(prach_tti_),
|
||||||
preamble_idx(preamble_idx_),
|
preamble_idx(preamble_idx_),
|
||||||
cell_params(cell_params_),
|
cell_params(cell_params_),
|
||||||
current_tti_rx(prach_tti_)
|
current_tti_rx(prach_tti_),
|
||||||
|
ue_ctxt(&ue_ctxt_)
|
||||||
{
|
{
|
||||||
set_cfg(cfg_.ue_cfg);
|
set_cfg(cfg_.ue_cfg);
|
||||||
}
|
}
|
||||||
|
@ -80,10 +82,6 @@ int ue_ctxt_test::set_cfg(const sched::ue_cfg_t& ue_cfg_)
|
||||||
active_ccs.emplace_back();
|
active_ccs.emplace_back();
|
||||||
active_ccs.back().ue_cc_idx = active_ccs.size() - 1;
|
active_ccs.back().ue_cc_idx = active_ccs.size() - 1;
|
||||||
active_ccs.back().enb_cc_idx = cc.enb_cc_idx;
|
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 {
|
} else {
|
||||||
CONDERROR(cc.enb_cc_idx != active_ccs[ue_cc_idx].enb_cc_idx, "changing ccs not supported\n");
|
CONDERROR(cc.enb_cc_idx != active_ccs[ue_cc_idx].enb_cc_idx, "changing ccs not supported\n");
|
||||||
}
|
}
|
||||||
|
@ -129,17 +127,19 @@ int ue_ctxt_test::fwd_pending_acks(sched* sched_ptr)
|
||||||
if (p.tti_ack > current_tti_rx) {
|
if (p.tti_ack > current_tti_rx) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
auto& h = active_ccs[p.ue_cc_idx].dl_harqs[p.pid];
|
auto& h = ue_ctxt->get_ctxt().cc_list[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(not h.active, "The ACKed DL Harq pid=%d is not active\n", h.pid);
|
||||||
CONDERROR(h.tti_tx + FDD_HARQ_DELAY_DL_MS != p.tti_ack, "dl ack hasn't arrived when expected\n");
|
CONDERROR(to_tx_dl(h.last_tti_rx) + FDD_HARQ_DELAY_DL_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,
|
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",
|
"The ACKed DL Harq pid=%d does not exist.\n",
|
||||||
p.pid);
|
p.pid);
|
||||||
|
|
||||||
if (p.ack) {
|
if (p.ack) {
|
||||||
h.active = false;
|
|
||||||
log_h->info("DL ACK tti=%u rnti=0x%x pid=%d\n", current_tti_rx.to_uint(), rnti, p.pid);
|
log_h->info("DL ACK tti=%u rnti=0x%x pid=%d\n", current_tti_rx.to_uint(), rnti, p.pid);
|
||||||
}
|
}
|
||||||
|
if (p.ack or ue_ctxt->get_ctxt().is_last_dl_retx(p.ue_cc_idx, p.pid)) {
|
||||||
|
h.active = false;
|
||||||
|
}
|
||||||
pending_dl_acks.pop();
|
pending_dl_acks.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,14 +149,13 @@ int ue_ctxt_test::fwd_pending_acks(sched* sched_ptr)
|
||||||
if (p.tti_ack > current_tti_rx) {
|
if (p.tti_ack > current_tti_rx) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
auto& h = active_ccs[p.ue_cc_idx].ul_harqs[p.pid];
|
auto& h = ue_ctxt->get_ctxt().cc_list[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(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(to_tx_ul(h.last_tti_rx) != 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,
|
CONDERROR(sched_ptr->ul_crc_info(current_tti_rx.to_uint(), rnti, p.cc_idx, p.ack) != SRSLTE_SUCCESS,
|
||||||
"Failed UL ACK\n");
|
"Failed UL ACK\n");
|
||||||
|
|
||||||
if (p.ack) {
|
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);
|
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();
|
pending_ul_acks.pop();
|
||||||
|
@ -170,123 +169,11 @@ int ue_ctxt_test::test_sched_result(uint32_t enb_cc_idx,
|
||||||
const sched::ul_sched_res_t& ul_result)
|
const sched::ul_sched_res_t& ul_result)
|
||||||
{
|
{
|
||||||
cc_result result{enb_cc_idx, &dl_result, &ul_result};
|
cc_result result{enb_cc_idx, &dl_result, &ul_result};
|
||||||
TESTASSERT(test_harqs(result) == SRSLTE_SUCCESS);
|
|
||||||
TESTASSERT(test_ra(result) == SRSLTE_SUCCESS);
|
|
||||||
TESTASSERT(test_scell_activation(result) == SRSLTE_SUCCESS);
|
TESTASSERT(test_scell_activation(result) == SRSLTE_SUCCESS);
|
||||||
TESTASSERT(schedule_acks(result) == SRSLTE_SUCCESS);
|
TESTASSERT(schedule_acks(result) == SRSLTE_SUCCESS);
|
||||||
return SRSLTE_SUCCESS;
|
return SRSLTE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests whether the RAR and Msg3 were scheduled within the expected windows. Individual tests:
|
|
||||||
* - No UL allocs before Msg3
|
|
||||||
* - No DL data allocs before Msg3 is correctly ACKed
|
|
||||||
* - RAR alloc falls within RAR window and is unique per user
|
|
||||||
* - Msg3 is allocated in expected TTI, without PDCCH, and correct rnti
|
|
||||||
* - First Data allocation happens after Msg3, and contains a ConRes
|
|
||||||
* - No RARs are allocated with wrong enb_cc_idx, preamble_idx or wrong user
|
|
||||||
* TODO:
|
|
||||||
* - check Msg3 PRBs match the ones advertised in the RAR
|
|
||||||
*/
|
|
||||||
int ue_ctxt_test::test_ra(cc_result result)
|
|
||||||
{
|
|
||||||
if (result.enb_cc_idx != active_ccs[0].enb_cc_idx) {
|
|
||||||
// only check for RAR/Msg3 presence for a UE's PCell
|
|
||||||
return SRSLTE_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TEST: RAR allocation */
|
|
||||||
uint32_t rar_win_size = cell_params[result.enb_cc_idx].prach_rar_window;
|
|
||||||
std::array<srslte::tti_point, 2> rar_window = {prach_tti + 3, prach_tti + 3 + rar_win_size};
|
|
||||||
srslte::tti_point tti_tx_dl = to_tx_dl(current_tti_rx);
|
|
||||||
srslte::tti_point tti_tx_ul = to_tx_ul(current_tti_rx);
|
|
||||||
bool is_in_rar_window = tti_tx_dl >= rar_window[0] and tti_tx_dl <= rar_window[1];
|
|
||||||
|
|
||||||
if (not is_in_rar_window) {
|
|
||||||
CONDERROR(not rar_tti.is_valid() and tti_tx_dl > rar_window[1],
|
|
||||||
"rnti=0x%x RAR not scheduled within the RAR Window\n",
|
|
||||||
rnti);
|
|
||||||
for (uint32_t i = 0; i < result.dl_result->nof_rar_elems; ++i) {
|
|
||||||
CONDERROR(result.dl_result->rar[i].dci.rnti == rnti, "No RAR allocations allowed outside of user RAR window\n");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Inside RAR window
|
|
||||||
for (uint32_t i = 0; i < result.dl_result->nof_rar_elems; ++i) {
|
|
||||||
for (uint32_t j = 0; j < result.dl_result->rar[i].nof_grants; ++j) {
|
|
||||||
const auto& data = result.dl_result->rar[i].msg3_grant[j].data;
|
|
||||||
if (data.prach_tti == (uint32_t)prach_tti.to_uint() and data.preamble_idx == preamble_idx) {
|
|
||||||
CONDERROR(rar_tti.is_valid(), "There was more than one RAR for the same user\n");
|
|
||||||
CONDERROR(rnti != data.temp_crnti, "RAR grant C-RNTI does not match the expected.\n");
|
|
||||||
msg3_riv = result.dl_result->rar[i].msg3_grant[j].grant.rba;
|
|
||||||
rar_tti = tti_tx_dl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TEST: Check Msg3 */
|
|
||||||
if (rar_tti.is_valid() and not msg3_tti.is_valid()) {
|
|
||||||
// RAR scheduled, Msg3 not yet scheduled
|
|
||||||
srslte::tti_point expected_msg3_tti = rar_tti + FDD_HARQ_DELAY_DL_MS + MSG3_DELAY_MS;
|
|
||||||
CONDERROR(expected_msg3_tti < tti_tx_ul and not msg3_tti.is_valid(), "No UL msg3 alloc was made\n");
|
|
||||||
|
|
||||||
if (expected_msg3_tti == tti_tx_ul) {
|
|
||||||
// Msg3 should exist
|
|
||||||
for (uint32_t i = 0; i < result.ul_result->nof_dci_elems; ++i) {
|
|
||||||
if (result.ul_result->pusch[i].dci.rnti == rnti) {
|
|
||||||
CONDERROR(msg3_tti.is_valid(), "Only one Msg3 allowed per user\n");
|
|
||||||
CONDERROR(result.ul_result->pusch[i].needs_pdcch, "Msg3 allocations do not require PDCCH\n");
|
|
||||||
CONDERROR(msg3_riv != result.ul_result->pusch[i].dci.type2_alloc.riv,
|
|
||||||
"The Msg3 was not allocated in the expected PRBs.\n");
|
|
||||||
msg3_tti = tti_tx_ul;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TEST: Check Msg4 */
|
|
||||||
if (msg3_tti.is_valid() and not msg4_tti.is_valid()) {
|
|
||||||
// Msg3 scheduled, but Msg4 not yet scheduled
|
|
||||||
for (uint32_t i = 0; i < result.dl_result->nof_data_elems; ++i) {
|
|
||||||
if (result.dl_result->data[i].dci.rnti == rnti) {
|
|
||||||
CONDERROR(current_tti_rx < msg3_tti, "Msg4 cannot be scheduled without Msg3 being tx\n");
|
|
||||||
for (uint32_t j = 0; j < result.dl_result->data[i].nof_pdu_elems[0]; ++j) {
|
|
||||||
if (result.dl_result->data[i].pdu[0][j].lcid == (uint32_t)srslte::dl_sch_lcid::CON_RES_ID) {
|
|
||||||
// ConRes found
|
|
||||||
CONDERROR(result.dl_result->data[i].dci.format != SRSLTE_DCI_FORMAT1, "ConRes must be format1\n");
|
|
||||||
CONDERROR(msg4_tti.is_valid(), "Duplicate ConRes CE for the same rnti\n");
|
|
||||||
msg4_tti = tti_tx_dl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TEST: Txs out of place */
|
|
||||||
if (not msg4_tti.is_valid()) {
|
|
||||||
// Msg4 not yet received by user
|
|
||||||
for (uint32_t i = 0; i < result.dl_result->nof_data_elems; ++i) {
|
|
||||||
CONDERROR(result.dl_result->data[i].dci.rnti == rnti, "No DL data allocs allowed before Msg4 is scheduled\n");
|
|
||||||
}
|
|
||||||
if (msg3_tti.is_valid() and msg3_tti != tti_tx_ul) {
|
|
||||||
// Msg3 scheduled. No UL alloc allowed unless it is a newtx (the Msg3 itself)
|
|
||||||
for (uint32_t i = 0; i < result.ul_result->nof_dci_elems; ++i) {
|
|
||||||
// Needs PDCCH - filters out UL retxs
|
|
||||||
bool msg3_retx = ((tti_tx_ul - msg3_tti) % (FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS)) == 0;
|
|
||||||
CONDERROR(result.ul_result->pusch[i].dci.rnti == rnti and not msg3_retx,
|
|
||||||
"No UL txs allowed except for Msg3 before user received Msg4\n");
|
|
||||||
}
|
|
||||||
} else if (not msg3_tti.is_valid()) {
|
|
||||||
// No Msg3 sched TTI
|
|
||||||
for (uint32_t i = 0; i < result.ul_result->nof_dci_elems; ++i) {
|
|
||||||
CONDERROR(result.ul_result->pusch[i].dci.rnti == rnti, "No UL newtxs allowed before user received Msg4\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return SRSLTE_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests whether the SCells are correctly activated. Individual tests:
|
* Tests whether the SCells are correctly activated. Individual tests:
|
||||||
* - no DL and UL allocations in inactive carriers
|
* - no DL and UL allocations in inactive carriers
|
||||||
|
@ -323,99 +210,6 @@ int ue_ctxt_test::test_scell_activation(cc_result result)
|
||||||
return SRSLTE_SUCCESS;
|
return SRSLTE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sanity checks of the DCI values in the scheduling result for a given user. Current checks:
|
|
||||||
* - invalid ue_cc_idx<->enb_cc_idx matching in dl_result
|
|
||||||
* - reusing same pid too early (ACK still didn't arrive yet)
|
|
||||||
* - invalid rv value (nof retxs is incorrect) and ndi value
|
|
||||||
*/
|
|
||||||
int ue_ctxt_test::test_harqs(cc_result result)
|
|
||||||
{
|
|
||||||
cc_ue_ctxt_test* cc = get_cc_state(result.enb_cc_idx);
|
|
||||||
if (cc == nullptr) {
|
|
||||||
// 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) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
CONDERROR(data.dci.ue_cc_idx != cc->ue_cc_idx, "invalid ue_cc_idx=%d in sched result\n", data.dci.ue_cc_idx);
|
|
||||||
CONDERROR(data.dci.pid >= cc->dl_harqs.size(), "invalid pid\n");
|
|
||||||
auto& h = cc->dl_harqs[data.dci.pid];
|
|
||||||
uint32_t nof_retx = sched_utils::get_nof_retx(data.dci.tb[0].rv); // 0..3
|
|
||||||
|
|
||||||
if (h.nof_txs == 0 or h.ndi != data.dci.tb[0].ndi) {
|
|
||||||
// It is newtx
|
|
||||||
CONDERROR(nof_retx != 0, "Invalid rv index for new tx\n");
|
|
||||||
|
|
||||||
h.active = true;
|
|
||||||
h.nof_retxs = 0;
|
|
||||||
h.ndi = data.dci.tb[0].ndi;
|
|
||||||
h.tti_tx = to_tx_dl(current_tti_rx);
|
|
||||||
} else {
|
|
||||||
// it is retx
|
|
||||||
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 > current_tti_rx, "harq pid=%d reused too soon\n", h.pid);
|
|
||||||
CONDERROR(h.nof_retxs + 1 > sim_cfg.ue_cfg.maxharq_tx,
|
|
||||||
"The number of retx=%d exceeded its max=%d\n",
|
|
||||||
h.nof_retxs + 1,
|
|
||||||
sim_cfg.ue_cfg.maxharq_tx);
|
|
||||||
|
|
||||||
h.nof_retxs++;
|
|
||||||
h.tti_tx = 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[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");
|
|
||||||
}
|
|
||||||
if (pusch.tbs > 0) {
|
|
||||||
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, "Re-tx allocated for rnti=0x%x inactive UL harq pid=%d\n", rnti, 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 = to_tx_ul(current_tti_rx);
|
|
||||||
h.riv = pusch.dci.type2_alloc.riv;
|
|
||||||
h.nof_txs++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SRSLTE_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ue_ctxt_test::schedule_acks(cc_result result)
|
int ue_ctxt_test::schedule_acks(cc_result result)
|
||||||
{
|
{
|
||||||
auto* cc = get_cc_state(result.enb_cc_idx);
|
auto* cc = get_cc_state(result.enb_cc_idx);
|
||||||
|
@ -452,7 +246,7 @@ int ue_ctxt_test::schedule_acks(cc_result result)
|
||||||
ack_data.cc_idx = result.enb_cc_idx;
|
ack_data.cc_idx = result.enb_cc_idx;
|
||||||
ack_data.ue_cc_idx = pusch.dci.ue_cc_idx;
|
ack_data.ue_cc_idx = pusch.dci.ue_cc_idx;
|
||||||
ack_data.tb = 0;
|
ack_data.tb = 0;
|
||||||
ack_data.pid = to_tx_ul(current_tti_rx).to_uint() % cc->ul_harqs.size();
|
ack_data.pid = to_tx_ul(current_tti_rx).to_uint() % (FDD_HARQ_DELAY_DL_MS + FDD_HARQ_DELAY_UL_MS);
|
||||||
uint32_t nof_retx = sched_utils::get_nof_retx(pusch.dci.tb.rv); // 0..3
|
uint32_t nof_retx = sched_utils::get_nof_retx(pusch.dci.tb.rv); // 0..3
|
||||||
ack_data.ack = randf() < sim_cfg.prob_ul_ack_mask[nof_retx % sim_cfg.prob_ul_ack_mask.size()];
|
ack_data.ack = randf() < sim_cfg.prob_ul_ack_mask[nof_retx % sim_cfg.prob_ul_ack_mask.size()];
|
||||||
|
|
||||||
|
@ -475,10 +269,11 @@ int user_state_sched_tester::add_user(uint16_t rnti, uint32_t preamble_idx, cons
|
||||||
cell_params[cfg_.ue_cfg.supported_cc_list[0].enb_cc_idx].prach_config, tic.to_uint(), -1),
|
cell_params[cfg_.ue_cfg.supported_cc_list[0].enb_cc_idx].prach_config, tic.to_uint(), -1),
|
||||||
"New user added in a non-PRACH TTI\n");
|
"New user added in a non-PRACH TTI\n");
|
||||||
TESTASSERT(users.count(rnti) == 0);
|
TESTASSERT(users.count(rnti) == 0);
|
||||||
ue_ctxt_test ue{rnti, preamble_idx, srslte::tti_point{tic.to_uint()}, cfg_, cell_params};
|
sim_users.add_user(rnti, cfg_.ue_cfg, tic, preamble_idx);
|
||||||
|
|
||||||
|
ue_ctxt_test ue{rnti, preamble_idx, tic, cfg_, cell_params, sim_users.at(rnti)};
|
||||||
users.insert(std::make_pair(rnti, ue));
|
users.insert(std::make_pair(rnti, ue));
|
||||||
|
|
||||||
sim_users.add_user(rnti, cfg_.ue_cfg, tic);
|
|
||||||
return SRSLTE_SUCCESS;
|
return SRSLTE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,24 +330,12 @@ int user_state_sched_tester::test_ctrl_info(uint32_t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TEST: All DL allocs have a correct rnti */
|
|
||||||
for (uint32_t i = 0; i < dl_result.nof_data_elems; ++i) {
|
|
||||||
uint16_t rnti = dl_result.data[i].dci.rnti;
|
|
||||||
CONDERROR(users.count(rnti) == 0, "The user rnti=0x%x allocated in DL does not exist\n", rnti);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TEST: All UL allocs have a correct rnti */
|
|
||||||
for (uint32_t i = 0; i < ul_result.nof_dci_elems; ++i) {
|
|
||||||
uint16_t rnti = ul_result.pusch[i].dci.rnti;
|
|
||||||
CONDERROR(users.count(rnti) == 0, "The user rnti=0x%x allocated in UL does not exist\n", rnti);
|
|
||||||
}
|
|
||||||
|
|
||||||
return SRSLTE_SUCCESS;
|
return SRSLTE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int user_state_sched_tester::test_all(const sf_output_res_t& sf_out, uint32_t enb_cc_idx)
|
int user_state_sched_tester::test_all(const sf_output_res_t& sf_out, uint32_t enb_cc_idx)
|
||||||
{
|
{
|
||||||
// Perform UE-dedicated result tests
|
// Perform UE-dedicated sched result tests
|
||||||
sim_enb_ctxt_t enb_ctxt;
|
sim_enb_ctxt_t enb_ctxt;
|
||||||
enb_ctxt.cell_params = &cell_params;
|
enb_ctxt.cell_params = &cell_params;
|
||||||
enb_ctxt.ue_db = sim_users.get_ues_ctxt();
|
enb_ctxt.ue_db = sim_users.get_ues_ctxt();
|
||||||
|
|
|
@ -64,18 +64,6 @@ struct ue_ctxt_test {
|
||||||
struct cc_ue_ctxt_test {
|
struct cc_ue_ctxt_test {
|
||||||
uint32_t ue_cc_idx = 0;
|
uint32_t ue_cc_idx = 0;
|
||||||
uint32_t enb_cc_idx = 0;
|
uint32_t enb_cc_idx = 0;
|
||||||
// Harq State
|
|
||||||
struct harq_state_t {
|
|
||||||
uint32_t pid = 0;
|
|
||||||
srslte::tti_point tti_tx;
|
|
||||||
bool active = false;
|
|
||||||
bool ndi = false;
|
|
||||||
uint32_t nof_retxs = 0;
|
|
||||||
uint32_t nof_txs = 0;
|
|
||||||
uint32_t riv = 0;
|
|
||||||
};
|
|
||||||
std::array<harq_state_t, cc_sched_ue::SCHED_MAX_HARQ_PROC> dl_harqs = {};
|
|
||||||
std::array<harq_state_t, cc_sched_ue::SCHED_MAX_HARQ_PROC> ul_harqs = {};
|
|
||||||
};
|
};
|
||||||
std::vector<cc_ue_ctxt_test> active_ccs;
|
std::vector<cc_ue_ctxt_test> active_ccs;
|
||||||
|
|
||||||
|
@ -85,7 +73,8 @@ struct ue_ctxt_test {
|
||||||
uint32_t preamble_idx_,
|
uint32_t preamble_idx_,
|
||||||
srslte::tti_point prach_tti,
|
srslte::tti_point prach_tti,
|
||||||
const ue_ctxt_test_cfg& cfg_,
|
const ue_ctxt_test_cfg& cfg_,
|
||||||
const std::vector<srsenb::sched::cell_cfg_t>& cell_params_);
|
const std::vector<srsenb::sched::cell_cfg_t>& cell_params_,
|
||||||
|
ue_sim& ue_ctxt_);
|
||||||
|
|
||||||
int set_cfg(const sched::ue_cfg_t& ue_cfg_);
|
int set_cfg(const sched::ue_cfg_t& ue_cfg_);
|
||||||
cc_ue_ctxt_test* get_cc_state(uint32_t enb_cc_idx);
|
cc_ue_ctxt_test* get_cc_state(uint32_t enb_cc_idx);
|
||||||
|
@ -104,9 +93,6 @@ private:
|
||||||
const sched::dl_sched_res_t* dl_result;
|
const sched::dl_sched_res_t* dl_result;
|
||||||
const sched::ul_sched_res_t* ul_result;
|
const sched::ul_sched_res_t* ul_result;
|
||||||
};
|
};
|
||||||
//! Test the timing of RAR, Msg3, Msg4
|
|
||||||
int test_ra(cc_result result);
|
|
||||||
int test_harqs(cc_result result);
|
|
||||||
//! Test correct activation of SCells
|
//! Test correct activation of SCells
|
||||||
int test_scell_activation(cc_result result);
|
int test_scell_activation(cc_result result);
|
||||||
int schedule_acks(cc_result result);
|
int schedule_acks(cc_result result);
|
||||||
|
@ -120,6 +106,7 @@ private:
|
||||||
bool operator<(const pending_ack_t& other) const { return tti_ack > other.tti_ack; }
|
bool operator<(const pending_ack_t& other) const { return tti_ack > other.tti_ack; }
|
||||||
};
|
};
|
||||||
std::priority_queue<pending_ack_t> pending_dl_acks, pending_ul_acks;
|
std::priority_queue<pending_ack_t> pending_dl_acks, pending_ul_acks;
|
||||||
|
ue_sim* ue_ctxt;
|
||||||
};
|
};
|
||||||
|
|
||||||
class user_state_sched_tester
|
class user_state_sched_tester
|
||||||
|
|
|
@ -440,7 +440,7 @@ int main()
|
||||||
srsenb::set_randseed(seed);
|
srsenb::set_randseed(seed);
|
||||||
printf("This is the chosen seed: %u\n", seed);
|
printf("This is the chosen seed: %u\n", seed);
|
||||||
|
|
||||||
srslte::logmap::set_default_log_level(srslte::LOG_LEVEL_INFO);
|
srslte::logmap::set_default_log_level(srslte::LOG_LEVEL_DEBUG);
|
||||||
uint32_t N_runs = 1, nof_ttis = 10240 + 10;
|
uint32_t N_runs = 1, nof_ttis = 10240 + 10;
|
||||||
|
|
||||||
for (uint32_t n = 0; n < N_runs; ++n) {
|
for (uint32_t n = 0; n < N_runs; ++n) {
|
||||||
|
|
Loading…
Reference in New Issue