diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 5b17bac1c5a7841c964564aa8d0825bca102606a..d5d46432f2498e93e112c47afedcc3e7f6df458f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -419,14 +419,14 @@ void nr_simple_dlsch_preprocessor(module_id_t module_id, } uint16_t *vrb_map = RC.nrmac[module_id]->common_channels[CC_id].vrb_map; - // for now HARQ PID is fixed and should be the same as in post-processor - const int current_harq_pid = slot % 8; - NR_UE_harq_t *harq = &sched_ctrl->harq_processes[current_harq_pid]; - NR_UE_ret_info_t *retInfo = &sched_ctrl->retInfo[current_harq_pid]; + /* get the PID of a HARQ process awaiting retransmission, or -1 otherwise */ + sched_ctrl->dl_harq_pid = sched_ctrl->retrans_dl_harq.head; + NR_UE_harq_t *harq = &sched_ctrl->harq_processes[sched_ctrl->dl_harq_pid]; const uint16_t bwpSize = NRRIV2BW(sched_ctrl->active_bwp->bwp_Common->genericParameters.locationAndBandwidth, 275); int rbStart = NRRIV2PRBOFFSET(sched_ctrl->active_bwp->bwp_Common->genericParameters.locationAndBandwidth, 275); - if (harq->round != 0) { /* retransmission */ + if (sched_ctrl->dl_harq_pid >= 0) { /* retransmission */ + NR_UE_ret_info_t *retInfo = &sched_ctrl->retInfo[sched_ctrl->dl_harq_pid]; sched_ctrl->time_domain_allocation = retInfo->time_domain_allocation; /* ensure that there is a free place for RB allocation */ @@ -564,11 +564,29 @@ void nr_schedule_ue_spec(module_id_t module_id, nrOfLayers) >> 3; - const int current_harq_pid = slot % 8; + int8_t current_harq_pid = sched_ctrl->dl_harq_pid; + if (current_harq_pid < 0) { + /* PP has not selected a specific HARQ Process, get a new one */ + current_harq_pid = sched_ctrl->available_dl_harq.head; + AssertFatal(current_harq_pid >= 0, + "no free HARQ process available for UE %d\n", + UE_id); + remove_front_nr_list(&sched_ctrl->available_dl_harq); + } else { + /* PP selected a specific HARQ process. Check whether it will be a new + * transmission or a retransmission, and remove from the corresponding + * list */ + if (sched_ctrl->harq_processes[current_harq_pid].round == 0) + remove_nr_list(&sched_ctrl->available_dl_harq, current_harq_pid); + else + remove_nr_list(&sched_ctrl->retrans_dl_harq, current_harq_pid); + } NR_UE_harq_t *harq = &sched_ctrl->harq_processes[current_harq_pid]; + DevAssert(!harq->is_waiting); + add_tail_nr_list(&sched_ctrl->feedback_dl_harq, current_harq_pid); NR_sched_pucch_t *pucch = &sched_ctrl->sched_pucch[0]; harq->feedback_slot = pucch->ul_slot; - harq->is_waiting = 1; + harq->is_waiting = true; UE_info->mac_stats[UE_id].dlsch_rounds[harq->round]++; LOG_D(MAC, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index d2d7e30385b7a047ed9e71013d080c028b7cbec2..65a586d3bb449df9681001bdb37c469303a31604 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -360,6 +360,8 @@ void nr_preprocessor_phytest(module_id_t module_id, } sched_ctrl->mcs = 9; sched_ctrl->numDmrsCdmGrpsNoData = 1; + /* get the PID of a HARQ process awaiting retransmission, or -1 otherwise */ + sched_ctrl->dl_harq_pid = sched_ctrl->retrans_dl_harq.head; /* mark the corresponding RBs as used */ for (int rb = 0; rb < sched_ctrl->rbSize; rb++) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 84489083c5dd4987eb27bf34142a5015042c980b..025f59487dd23b397158d5b2e3396acad4bd5cf3 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -291,6 +291,31 @@ void nr_csi_meas_reporting(int Mod_idP, } } +inline void handle_dl_harq(module_id_t mod_id, + int UE_id, + int8_t harq_pid, + bool success) +{ + NR_UE_info_t *UE_info = &RC.nrmac[mod_id]->UE_info; + NR_UE_harq_t *harq = &UE_info->UE_sched_ctrl[UE_id].harq_processes[harq_pid]; + harq->feedback_slot = -1; + harq->is_waiting = false; + if (success) { + add_tail_nr_list(&UE_info->UE_sched_ctrl[UE_id].available_dl_harq, harq_pid); + harq->round = 0; + harq->ndi ^= 1; + } else if (harq->round == MAX_HARQ_ROUNDS) { + add_tail_nr_list(&UE_info->UE_sched_ctrl[UE_id].available_dl_harq, harq_pid); + harq->round = 0; + harq->ndi ^= 1; + NR_mac_stats_t *stats = &UE_info->mac_stats[UE_id]; + stats->dlsch_errors++; + LOG_D(MAC, "retransmission error for UE %d (total %d)\n", UE_id, stats->dlsch_errors); + } else { + add_tail_nr_list(&UE_info->UE_sched_ctrl[UE_id].retrans_dl_harq, harq_pid); + harq->round++; + } +} void handle_nr_uci_pucch_0_1(module_id_t mod_id, frame_t frame, @@ -310,50 +335,23 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, uci_01->ul_cqi, 30); - // TODO - int max_harq_rounds = 4; // TODO define macro + NR_ServingCellConfigCommon_t *scc = RC.nrmac[mod_id]->common_channels->ServingCellConfigCommon; + const int num_slots = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; if (((uci_01->pduBitmap >> 1) & 0x01)) { - // handle harq - int harq_idx_s = 0; - // iterate over received harq bits for (int harq_bit = 0; harq_bit < uci_01->harq->num_harq; harq_bit++) { - // search for the right harq process - for (int harq_idx = harq_idx_s; harq_idx < NR_MAX_NB_HARQ_PROCESSES; harq_idx++) { - // if the gNB received ack with a good confidence - if ((slot - 1) == sched_ctrl->harq_processes[harq_idx].feedback_slot) { - sched_ctrl->harq_processes[harq_idx].feedback_slot = -1; - if ((uci_01->harq->harq_list[harq_bit].harq_value == 1) && - (uci_01->harq->harq_confidence_level == 0)) { - // toggle NDI and reset round - sched_ctrl->harq_processes[harq_idx].ndi ^= 1; - sched_ctrl->harq_processes[harq_idx].round = 0; - } - else - sched_ctrl->harq_processes[harq_idx].round++; - sched_ctrl->harq_processes[harq_idx].is_waiting = 0; - harq_idx_s = harq_idx + 1; - // if the max harq rounds was reached - if (sched_ctrl->harq_processes[harq_idx].round == max_harq_rounds) { - sched_ctrl->harq_processes[harq_idx].ndi ^= 1; - sched_ctrl->harq_processes[harq_idx].round = 0; - UE_info->mac_stats[UE_id].dlsch_errors++; - } - break; - } - // if feedback slot processing is aborted - else if (sched_ctrl->harq_processes[harq_idx].feedback_slot != -1 - && (slot - 1) > sched_ctrl->harq_processes[harq_idx].feedback_slot - && sched_ctrl->harq_processes[harq_idx].is_waiting) { - sched_ctrl->harq_processes[harq_idx].feedback_slot = -1; - sched_ctrl->harq_processes[harq_idx].round++; - if (sched_ctrl->harq_processes[harq_idx].round == max_harq_rounds) { - sched_ctrl->harq_processes[harq_idx].ndi ^= 1; - sched_ctrl->harq_processes[harq_idx].round = 0; - } - sched_ctrl->harq_processes[harq_idx].is_waiting = 0; - } - } + 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 int8_t 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]; + const int feedback_slot = (slot - 1 + num_slots) % num_slots; + AssertFatal(harq->feedback_slot == feedback_slot, + "expected feedback slot %d, but found %d instead\n", + harq->feedback_slot, feedback_slot); + DevAssert(harq->is_waiting); + handle_dl_harq(mod_id, UE_id, pid, harq_value == 1 && harq_confidence == 0); } } } @@ -376,50 +374,21 @@ void handle_nr_uci_pucch_2_3_4(module_id_t mod_id, uci_234->ul_cqi, 30); - // TODO - int max_harq_rounds = 4; // TODO define macro + NR_ServingCellConfigCommon_t *scc = RC.nrmac[mod_id]->common_channels->ServingCellConfigCommon; + const int num_slots = nr_slots_per_frame[*scc->ssbSubcarrierSpacing]; if ((uci_234->pduBitmap >> 1) & 0x01) { - int harq_idx_s = 0; - int acknack; - // iterate over received harq bits for (int harq_bit = 0; harq_bit < uci_234->harq.harq_bit_len; harq_bit++) { - acknack = ((uci_234->harq.harq_payload[harq_bit>>3])>>harq_bit)&0x01; - for (int harq_idx = harq_idx_s; harq_idx < NR_MAX_NB_HARQ_PROCESSES-1; harq_idx++) { - // if the gNB received ack with a good confidence or if the max harq rounds was reached - if ((slot - 1) == sched_ctrl->harq_processes[harq_idx].feedback_slot) { - // TODO add some confidence level for when there is no CRC - sched_ctrl->harq_processes[harq_idx].feedback_slot = -1; - if ((uci_234->harq.harq_crc != 1) && acknack) { - // toggle NDI and reset round - sched_ctrl->harq_processes[harq_idx].ndi ^= 1; - sched_ctrl->harq_processes[harq_idx].round = 0; - } - else - sched_ctrl->harq_processes[harq_idx].round++; - sched_ctrl->harq_processes[harq_idx].is_waiting = 0; - harq_idx_s = harq_idx + 1; - // if the max harq rounds was reached - if (sched_ctrl->harq_processes[harq_idx].round == max_harq_rounds) { - sched_ctrl->harq_processes[harq_idx].ndi ^= 1; - sched_ctrl->harq_processes[harq_idx].round = 0; - UE_info->mac_stats[UE_id].dlsch_errors++; - } - break; - } - // if feedback slot processing is aborted - else if (sched_ctrl->harq_processes[harq_idx].feedback_slot != -1 - && (slot - 1) > sched_ctrl->harq_processes[harq_idx].feedback_slot - && sched_ctrl->harq_processes[harq_idx].is_waiting) { - sched_ctrl->harq_processes[harq_idx].feedback_slot = -1; - sched_ctrl->harq_processes[harq_idx].round++; - if (sched_ctrl->harq_processes[harq_idx].round == max_harq_rounds) { - sched_ctrl->harq_processes[harq_idx].ndi ^= 1; - sched_ctrl->harq_processes[harq_idx].round = 0; - } - sched_ctrl->harq_processes[harq_idx].is_waiting = 0; - } - } + const int acknack = ((uci_234->harq.harq_payload[harq_bit >> 3]) >> harq_bit) & 0x01; + const int8_t 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]; + const int feedback_slot = (slot - 1 + num_slots) % num_slots; + AssertFatal(harq->feedback_slot == feedback_slot, + "expected feedback slot %d, but found %d instead\n", + harq->feedback_slot, feedback_slot); + handle_dl_harq(mod_id, UE_id, pid, uci_234->harq.harq_crc != 1 && acknack); } } } diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index bdc01691d8f441b5000b8793d3e73f97b1180a98..000263a99314d3cfdcce14a4676159e4bbdc1c91 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -73,6 +73,7 @@ #define MAX_NUM_BWP 2 #define MAX_NUM_CORESET 2 #define MAX_NUM_CCE 90 +#define MAX_HARQ_ROUNDS 4 /*!\brief Maximum number of random access process */ #define NR_NB_RA_PROC_MAX 4 #define MAX_NUM_OF_SSB 64 @@ -336,7 +337,7 @@ typedef struct NR_sched_pusch { } NR_sched_pusch_t; typedef struct NR_UE_harq { - uint8_t is_waiting; + bool is_waiting; uint8_t ndi; uint8_t round; uint16_t feedback_slot; @@ -423,6 +424,8 @@ typedef struct { /// Retransmission-related information NR_UE_ret_info_t retInfo[NR_MAX_NB_HARQ_PROCESSES]; + /// DL HARQ PID to use for this UE, or -1 for "any new" + int8_t dl_harq_pid; uint16_t ta_frame; int16_t ta_update;