harq ack state can now only be NACK or ACK. The ul_harq pending phich flag is now reset after phich scheduling. Thus, the existence of a crc_info(...) signal from the PHY is not required.

This commit is contained in:
Francisco 2020-11-24 18:27:04 +00:00 committed by Andre Puschmann
parent 53d8319d2b
commit fc81a5c6ba
6 changed files with 38 additions and 65 deletions

View File

@ -54,7 +54,7 @@ protected:
enum ack_t { NULL_ACK, NACK, ACK };
ack_t ack_state[SRSLTE_MAX_TB];
bool ack_state[SRSLTE_MAX_TB];
bool active[SRSLTE_MAX_TB];
std::array<bool, SRSLTE_MAX_TB> ndi = {};
uint32_t id;
@ -95,8 +95,8 @@ private:
class ul_harq_proc : public harq_proc
{
public:
void new_tx(uint32_t tti, int mcs, int tbs, prb_interval alloc, uint32_t max_retx_);
void new_retx(uint32_t tb_idx, uint32_t tti_, int* mcs, int* tbs, prb_interval alloc);
void new_tx(srslte::tti_point tti, int mcs, int tbs, prb_interval alloc, uint32_t max_retx_);
void new_retx(srslte::tti_point tti_, int* mcs, int* tbs, prb_interval alloc);
bool set_ack(uint32_t tb_idx, bool ack);
prb_interval get_alloc() const;
@ -104,15 +104,15 @@ public:
bool is_adaptive_retx() const;
void reset_pending_data();
bool has_pending_ack() const;
bool get_pending_ack() const;
uint32_t get_pending_data() const;
bool has_pending_phich() const;
bool pop_pending_phich();
private:
prb_interval allocation;
int pending_data;
bool is_adaptive;
ack_t pending_ack;
bool pending_phich = false;
};
class harq_entity

View File

@ -866,7 +866,7 @@ alloc_outcome_t sf_sched::alloc_ul_user(sched_ue* user, prb_interval alloc)
bool has_retx = h->has_pending_retx();
if (has_retx) {
prb_interval prev_alloc = h->get_alloc();
if (prev_alloc == alloc and h->has_pending_ack()) {
if (prev_alloc == alloc and h->has_pending_phich()) {
alloc_type = ul_alloc_t::NOADAPT_RETX;
} else {
alloc_type = ul_alloc_t::ADAPT_RETX;
@ -893,8 +893,8 @@ bool sf_sched::alloc_phich(sched_ue* user, sched_interface::ul_sched_res_t* ul_s
ul_harq_proc* h = user->get_ul_harq(tti_params.tti_tx_ul, cell_index);
/* Indicate PHICH acknowledgment if needed */
if (h->has_pending_ack()) {
phich_list.phich = h->get_pending_ack() ? phich_t::ACK : phich_t::NACK;
if (h->has_pending_phich()) {
phich_list.phich = h->pop_pending_phich() ? phich_t::ACK : phich_t::NACK;
phich_list.rnti = user->get_rnti();
log_h->debug("SCHED: Allocated PHICH for rnti=0x%x, value=%s\n",
user->get_rnti(),

View File

@ -45,7 +45,7 @@ void harq_proc::init(uint32_t id_)
void harq_proc::reset(uint32_t tb_idx)
{
ack_state[tb_idx] = NULL_ACK;
ack_state[tb_idx] = false;
active[tb_idx] = false;
n_rtx[tb_idx] = 0;
tti = tti_point{0};
@ -76,7 +76,7 @@ bool harq_proc::is_empty(uint32_t tb_idx) const
bool harq_proc::has_pending_retx_common(uint32_t tb_idx) const
{
return !is_empty(tb_idx) && ack_state[tb_idx] == NACK;
return active[tb_idx] && not ack_state[tb_idx];
}
tti_point harq_proc::get_tti() const
@ -90,7 +90,7 @@ int harq_proc::set_ack_common(uint32_t tb_idx, bool ack_)
log_h->warning("Received ACK for inactive harq\n");
return SRSLTE_ERROR;
}
ack_state[tb_idx] = ack_ ? ACK : NACK;
ack_state[tb_idx] = ack_;
log_h->debug("ACK=%d received pid=%d, tb_idx=%d, n_rtx=%d, max_retx=%d\n", ack_, id, tb_idx, n_rtx[tb_idx], max_retx);
if (!ack_ && (n_rtx[tb_idx] + 1 >= max_retx)) {
Info("SCHED: discarding TB=%d pid=%d, tti=%d, maximum number of retx exceeded (%d)\n",
@ -120,7 +120,7 @@ void harq_proc::new_tx_common(uint32_t tb_idx, tti_point tti_, int mcs, int tbs,
void harq_proc::new_retx_common(uint32_t tb_idx, tti_point tti_, int* mcs, int* tbs)
{
ack_state[tb_idx] = NACK;
ack_state[tb_idx] = false;
tti = tti_;
n_rtx[tb_idx]++;
if (mcs) {
@ -212,8 +212,7 @@ rbgmask_t dl_harq_proc::get_rbgmask() const
bool dl_harq_proc::has_pending_retx(uint32_t tb_idx, uint32_t tti_tx_dl) const
{
return (tti_point{tti_tx_dl} >= tti + FDD_HARQ_DELAY_UL_MS + FDD_HARQ_DELAY_DL_MS) and
has_pending_retx_common(tb_idx);
return (tti_point{tti_tx_dl} >= to_tx_dl_ack(tti)) and has_pending_retx_common(tb_idx);
}
int dl_harq_proc::get_tbs(uint32_t tb_idx) const
@ -245,21 +244,22 @@ bool ul_harq_proc::is_adaptive_retx() const
return is_adaptive and has_pending_retx();
}
void ul_harq_proc::new_tx(uint32_t tti_, int mcs, int tbs, prb_interval alloc, uint32_t max_retx_)
void ul_harq_proc::new_tx(tti_point tti_, int mcs, int tbs, prb_interval alloc, uint32_t max_retx_)
{
is_adaptive = false;
allocation = alloc;
new_tx_common(0, tti_point{tti_}, mcs, tbs, max_retx_);
pending_data = tbs;
pending_ack = NULL_ACK;
pending_phich = true;
}
void ul_harq_proc::new_retx(uint32_t tb_idx, uint32_t tti_, int* mcs, int* tbs, prb_interval alloc)
void ul_harq_proc::new_retx(tti_point tti_, int* mcs, int* tbs, prb_interval alloc)
{
// If PRBs changed, or there was no CRC (e.g. HARQ is being resumed)
is_adaptive = alloc != allocation or not has_pending_ack();
// If PRBs changed, or there was no tx in last oportunity (e.g. HARQ is being resumed)
is_adaptive = alloc != allocation or tti_ != to_tx_ul(tti);
allocation = alloc;
new_retx_common(tb_idx, tti_point{tti_}, mcs, tbs);
new_retx_common(0, tti_point{tti_}, mcs, tbs);
pending_phich = true;
}
bool ul_harq_proc::set_ack(uint32_t tb_idx, bool ack_)
@ -267,25 +267,25 @@ bool ul_harq_proc::set_ack(uint32_t tb_idx, bool ack_)
if (is_empty()) {
return false;
}
pending_ack = ack_ ? ACK : NACK;
set_ack_common(tb_idx, ack_);
return true;
}
bool ul_harq_proc::has_pending_ack() const
bool ul_harq_proc::has_pending_phich() const
{
return pending_ack != NULL_ACK;
return pending_phich;
}
bool ul_harq_proc::get_pending_ack() const
bool ul_harq_proc::pop_pending_phich()
{
return pending_ack == ACK;
bool ret = ack_state[0];
pending_phich = false;
return ret;
}
void ul_harq_proc::reset_pending_data()
{
reset_pending_data_common();
pending_ack = NULL_ACK;
if (is_empty(0)) {
pending_data = 0;
}
@ -301,9 +301,7 @@ uint32_t ul_harq_proc::get_pending_data() const
*******************/
harq_entity::harq_entity(size_t nof_dl_harqs, size_t nof_ul_harqs) :
dl_harqs(nof_dl_harqs),
ul_harqs(nof_ul_harqs),
log_h(srslte::logmap::get("MAC "))
dl_harqs(nof_dl_harqs), ul_harqs(nof_ul_harqs), log_h(srslte::logmap::get("MAC "))
{
for (uint32_t i = 0; i < dl_harqs.size(); ++i) {
dl_harqs[i].init(i);

View File

@ -785,14 +785,14 @@ int sched_ue::generate_format0(sched_interface::ul_sched_data_t* data,
// NOTE: if (nof_re < nof_uci_re) we should set TBS=0
}
}
h->new_tx(tti, mcs, tbs, alloc, nof_retx);
h->new_tx(tti_point{tti}, mcs, tbs, alloc, nof_retx);
// Un-trigger the SR if data is allocated
if (tbs > 0) {
unset_sr();
}
} else {
// retx
h->new_retx(0, tti, &mcs, nullptr, alloc);
h->new_retx(tti_point{tti}, &mcs, nullptr, alloc);
tbs = srslte_ra_tbs_from_idx(srslte_ra_tbs_idx_from_mcs(mcs, false, true), alloc.length()) / 8;
}

View File

@ -250,35 +250,12 @@ int sched_tester::test_harqs()
CONDERROR(h.get_n_cce() != data.dci.location.ncce, "Harq DCI location does not match with result\n");
}
for (uint32_t i = 0; i < tti_info.ul_sched_result[CARRIER_IDX].nof_dci_elems; ++i) {
const auto& pusch = tti_info.ul_sched_result[CARRIER_IDX].pusch[i];
uint16_t rnti = pusch.dci.rnti;
const auto& ue_data = tti_data.ue_data[rnti];
const srsenb::ul_harq_proc* h = ue_db[rnti].get_ul_harq(tti_info.tti_params.tti_tx_ul, CARRIER_IDX);
CONDERROR(h == nullptr or h->is_empty(), "scheduled UL harq does not exist or is empty\n");
CONDERROR(h->get_tti() != tti_point{tti_info.tti_params.tti_tx_ul},
"The scheduled UL harq does not a valid tti=%u\n",
tti_info.tti_params.tti_tx_ul);
CONDERROR(h->has_pending_ack(), "At the end of the TTI, there shouldnt be any pending ACKs\n");
if (h->has_pending_retx()) {
// retx
CONDERROR(ue_data.ul_harq.is_empty(0), "reTx in an UL harq that was empty\n");
CONDERROR(h->nof_retx(0) != ue_data.ul_harq.nof_retx(0) + 1,
"A retx UL harq was scheduled but with invalid number of retxs\n");
CONDERROR(h->is_adaptive_retx() and not pusch.needs_pdcch, "Adaptive retxs need PDCCH alloc\n");
} else {
CONDERROR(h->nof_retx(0) != 0, "A new harq was scheduled but with invalid number of retxs\n");
CONDERROR(not ue_data.ul_harq.is_empty(0), "UL new tx in a UL harq that was not empty\n");
}
}
/* Check PHICH allocations */
for (uint32_t i = 0; i < tti_info.ul_sched_result[CARRIER_IDX].nof_phich_elems; ++i) {
const auto& phich = tti_info.ul_sched_result[CARRIER_IDX].phich[i];
const auto& hprev = tti_data.ue_data[phich.rnti].ul_harq;
const auto* h = ue_db[phich.rnti].get_ul_harq(tti_info.tti_params.tti_tx_ul, CARRIER_IDX);
CONDERROR(not hprev.has_pending_ack(), "Alloc PHICH did not have any pending ack\n");
CONDERROR(not hprev.has_pending_phich(), "Alloc PHICH did not have any pending ack\n");
bool maxretx_flag = hprev.nof_retx(0) + 1 >= hprev.max_nof_retx();
if (phich.phich == sched_interface::ul_sched_phich_t::ACK) {
// The harq can be either ACKed or Resumed

View File

@ -165,7 +165,7 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t&
rnti,
pid);
// TEST: absent PUSCH grants for active DL 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)) {
CONDERROR(not h_inactive, "PHICH NACK received for rnti=0x%x but no PUSCH retx reallocated\n", rnti);
}
@ -187,15 +187,13 @@ int test_ul_sched_result(const sim_enb_ctxt_t& enb_ctxt, const sf_output_res_t&
// the HARQ is being resumed
CONDERROR(not pusch_ptr->needs_pdcch, "Resumed UL HARQs need to be signalled in PDCCH\n");
}
if (pusch_ptr->needs_pdcch) {
// adaptive retx
CONDERROR(h.tbs != pusch_ptr->tbs, "TBS changed during HARQ retx\n");
CONDERROR(sched_utils::get_rvidx(h.nof_retxs + 1) != (uint32_t)pusch_ptr->dci.tb.rv,
"Invalid rv index for retx\n");
} else {
if (not pusch_ptr->needs_pdcch) {
// non-adaptive retx
CONDERROR(pusch_ptr->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_ptr->dci.tb.rv,
"Invalid rv index for retx\n");
CONDERROR(h.tbs != pusch_ptr->tbs, "TBS changed during HARQ retx\n");
CONDERROR(to_tx_ul(h.last_tti_rx) > sf_out.tti_rx, "UL harq pid=%d was reused too soon\n", h.pid);
}
}