Commit 50b1fba1 authored by Robert Schmidt's avatar Robert Schmidt

DL HARQ feedback processing: check frame/slot

Due to real-time issue, we might miss HARQ feedbacks. Similarly, I
observed that we get feedback for HARQ processes scheduled for a future
frame (don't know how this can happen).

This commit introduces a function that checks whether the first HARQ
process in the queue corresponds due the current frame/slot combination.
If not, it marks old feedbacks for retransmission.  Furthermore, it also
checks whether the feedback is too early, by not considering this
feedback.
parent e57ed9f4
...@@ -748,6 +748,7 @@ void nr_schedule_ue_spec(module_id_t module_id, ...@@ -748,6 +748,7 @@ void nr_schedule_ue_spec(module_id_t module_id,
DevAssert(!harq->is_waiting); DevAssert(!harq->is_waiting);
add_tail_nr_list(&sched_ctrl->feedback_dl_harq, current_harq_pid); add_tail_nr_list(&sched_ctrl->feedback_dl_harq, current_harq_pid);
NR_sched_pucch_t *pucch = &sched_ctrl->sched_pucch[0]; NR_sched_pucch_t *pucch = &sched_ctrl->sched_pucch[0];
harq->feedback_frame = pucch->frame;
harq->feedback_slot = pucch->ul_slot; harq->feedback_slot = pucch->ul_slot;
harq->is_waiting = true; harq->is_waiting = true;
UE_info->mac_stats[UE_id].dlsch_rounds[harq->round]++; UE_info->mac_stats[UE_id].dlsch_rounds[harq->round]++;
......
...@@ -948,7 +948,50 @@ void extract_pucch_csi_report (NR_CSI_MeasConfig_t *csi_MeasConfig, ...@@ -948,7 +948,50 @@ void extract_pucch_csi_report (NR_CSI_MeasConfig_t *csi_MeasConfig,
if ( !(reportQuantity_type)) if ( !(reportQuantity_type))
AssertFatal(reportQuantity_type, "reportQuantity is not configured"); AssertFatal(reportQuantity_type, "reportQuantity is not configured");
}
static NR_UE_harq_t *find_harq(module_id_t mod_id, frame_t frame, sub_frame_t slot, int UE_id)
{
/* In case of realtime problems: we can only identify a HARQ process by
* timing. If the HARQ process's feedback_frame/feedback_slot is not the one we
* expected, we assume that processing has been aborted and we need to
* skip this HARQ process, which is what happens in the loop below.
* Similarly, we might be "in advance", in which case we need to skip
* this result. */
NR_UE_sched_ctrl_t *sched_ctrl = &RC.nrmac[mod_id]->UE_info.UE_sched_ctrl[UE_id];
int8_t pid = sched_ctrl->feedback_dl_harq.head;
if (pid < 0)
return NULL;
NR_UE_harq_t *harq = &sched_ctrl->harq_processes[pid];
/* old feedbacks we missed: mark for retransmission */
while (harq->feedback_frame != frame
|| (harq->feedback_frame == frame && harq->feedback_slot < slot)) {
LOG_W(MAC,
"expected HARQ pid %d feedback at %d.%d, but is at %d.%d instead (HARQ feedback is in the past)\n",
pid,
harq->feedback_frame,
harq->feedback_slot,
frame,
slot);
remove_front_nr_list(&sched_ctrl->feedback_dl_harq);
handle_dl_harq(mod_id, UE_id, pid, 0);
pid = sched_ctrl->feedback_dl_harq.head;
if (pid < 0)
return NULL;
harq = &sched_ctrl->harq_processes[pid];
}
/* feedbacks that we wait for in the future: don't do anything */
if (harq->feedback_slot > slot) {
LOG_W(MAC,
"expected HARQ pid %d feedback at %d.%d, but is at %d.%d instead (HARQ feedback is in the future)\n",
pid,
harq->feedback_frame,
harq->feedback_slot,
frame,
slot);
return NULL;
}
return harq;
} }
void handle_nr_uci_pucch_0_1(module_id_t mod_id, void handle_nr_uci_pucch_0_1(module_id_t mod_id,
...@@ -976,28 +1019,14 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, ...@@ -976,28 +1019,14 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id,
for (int harq_bit = 0; harq_bit < uci_01->harq->num_harq; harq_bit++) { for (int harq_bit = 0; harq_bit < uci_01->harq->num_harq; harq_bit++) {
const uint8_t harq_value = uci_01->harq->harq_list[harq_bit].harq_value; const uint8_t harq_value = uci_01->harq->harq_list[harq_bit].harq_value;
const uint8_t harq_confidence = uci_01->harq->harq_confidence_level; const uint8_t harq_confidence = uci_01->harq->harq_confidence_level;
const int feedback_frame = slot == 0 ? (frame - 1 + 1024) % 1024 : frame;
const int feedback_slot = (slot - 1 + num_slots) % num_slots; const int feedback_slot = (slot - 1 + num_slots) % num_slots;
/* In case of realtime problems: we can only identify a HARQ process by NR_UE_harq_t *harq = find_harq(mod_id, feedback_frame, feedback_slot, UE_id);
* timing. If the HARQ process's feedback_slot is not the one we if (!harq)
* expected, we assume that processing has been aborted and we need to break;
* skip this HARQ process, which is what happens in the loop below. If
* you don't experience real-time problems, you might simply revert the
* commit that introduced these changes. */
int8_t pid = sched_ctrl->feedback_dl_harq.head;
DevAssert(pid >= 0);
while (sched_ctrl->harq_processes[pid].feedback_slot != feedback_slot) {
LOG_W(MAC,
"expected feedback slot %d, but found %d instead\n",
sched_ctrl->harq_processes[pid].feedback_slot,
feedback_slot);
remove_front_nr_list(&sched_ctrl->feedback_dl_harq);
handle_dl_harq(mod_id, UE_id, pid, 0);
pid = sched_ctrl->feedback_dl_harq.head;
DevAssert(pid >= 0);
}
remove_front_nr_list(&sched_ctrl->feedback_dl_harq);
NR_UE_harq_t *harq = &sched_ctrl->harq_processes[pid];
DevAssert(harq->is_waiting); DevAssert(harq->is_waiting);
const int8_t pid = sched_ctrl->feedback_dl_harq.head;
remove_front_nr_list(&sched_ctrl->feedback_dl_harq);
handle_dl_harq(mod_id, UE_id, pid, harq_value == 1 && harq_confidence == 0); handle_dl_harq(mod_id, UE_id, pid, harq_value == 1 && harq_confidence == 0);
} }
} }
...@@ -1028,28 +1057,14 @@ void handle_nr_uci_pucch_2_3_4(module_id_t mod_id, ...@@ -1028,28 +1057,14 @@ void handle_nr_uci_pucch_2_3_4(module_id_t mod_id,
// iterate over received harq bits // iterate over received harq bits
for (int harq_bit = 0; harq_bit < uci_234->harq.harq_bit_len; harq_bit++) { for (int harq_bit = 0; harq_bit < uci_234->harq.harq_bit_len; harq_bit++) {
const int acknack = ((uci_234->harq.harq_payload[harq_bit >> 3]) >> harq_bit) & 0x01; const int acknack = ((uci_234->harq.harq_payload[harq_bit >> 3]) >> harq_bit) & 0x01;
const int feedback_frame = slot == 0 ? (frame - 1 + 1024) % 1024 : frame;
const int feedback_slot = (slot - 1 + num_slots) % num_slots; const int feedback_slot = (slot - 1 + num_slots) % num_slots;
/* In case of realtime problems: we can only identify a HARQ process by NR_UE_harq_t *harq = find_harq(mod_id, feedback_frame, feedback_slot, UE_id);
* timing. If the HARQ process's feedback_slot is not the one we if (!harq)
* expected, we assume that processing has been aborted and we need to break;
* skip this HARQ process, which is what happens in the loop below. If
* you don't experience real-time problems, you might simply revert the
* commit that introduced these changes. */
int8_t pid = sched_ctrl->feedback_dl_harq.head;
DevAssert(pid >= 0);
while (sched_ctrl->harq_processes[pid].feedback_slot != feedback_slot) {
LOG_W(MAC,
"expected feedback slot %d, but found %d instead\n",
sched_ctrl->harq_processes[pid].feedback_slot,
feedback_slot);
remove_front_nr_list(&sched_ctrl->feedback_dl_harq);
handle_dl_harq(mod_id, UE_id, pid, 0);
pid = sched_ctrl->feedback_dl_harq.head;
DevAssert(pid >= 0);
}
remove_front_nr_list(&sched_ctrl->feedback_dl_harq);
NR_UE_harq_t *harq = &sched_ctrl->harq_processes[pid];
DevAssert(harq->is_waiting); DevAssert(harq->is_waiting);
const int8_t pid = sched_ctrl->feedback_dl_harq.head;
remove_front_nr_list(&sched_ctrl->feedback_dl_harq);
handle_dl_harq(mod_id, UE_id, pid, uci_234->harq.harq_crc != 1 && acknack); handle_dl_harq(mod_id, UE_id, pid, uci_234->harq.harq_crc != 1 && acknack);
} }
} }
......
...@@ -356,6 +356,7 @@ typedef struct NR_UE_harq { ...@@ -356,6 +356,7 @@ typedef struct NR_UE_harq {
bool is_waiting; bool is_waiting;
uint8_t ndi; uint8_t ndi;
uint8_t round; uint8_t round;
uint16_t feedback_frame;
uint16_t feedback_slot; uint16_t feedback_slot;
/* Transport block to be sent using this HARQ process */ /* Transport block to be sent using this HARQ process */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment