Implement DL HARQ using NR_list_t
This commit is contained in:
@@ -207,6 +207,20 @@ void nr_dlsim_preprocessor(module_id_t module_id,
|
||||
sched_ctrl->mcs = g_mcsIndex;
|
||||
sched_ctrl->time_domain_allocation = 2;
|
||||
sched_ctrl->mcsTableIdx = g_mcsTableIdx;
|
||||
/* the simulator assumes the HARQ PID is equal to the slot number */
|
||||
sched_ctrl->dl_harq_pid = slot;
|
||||
/* The scheduler uses lists to track whether a HARQ process is
|
||||
* free/busy/awaiting retransmission, and updates the HARQ process states.
|
||||
* However, in the simulation, we never get ack or nack for any HARQ process,
|
||||
* thus the list and HARQ states don't match what the scheduler expects.
|
||||
* Therefore, below lines just "repair" everything so that the scheduler
|
||||
* won't remark that there is no HARQ feedback */
|
||||
sched_ctrl->feedback_dl_harq.head = -1; // always overwrite feedback HARQ process
|
||||
if (sched_ctrl->harq_processes[slot].round == 0) // depending on round set in simulation ...
|
||||
add_front_nr_list(&sched_ctrl->available_dl_harq, slot); // ... make PID available
|
||||
else
|
||||
add_front_nr_list(&sched_ctrl->retrans_dl_harq, slot); // ... make PID retransmission
|
||||
sched_ctrl->harq_processes[slot].is_waiting = false;
|
||||
AssertFatal(sched_ctrl->rbStart >= 0, "invalid rbStart %d\n", sched_ctrl->rbStart);
|
||||
AssertFatal(sched_ctrl->rbSize > 0, "invalid rbSize %d\n", sched_ctrl->rbSize);
|
||||
AssertFatal(sched_ctrl->mcs >= 0, "invalid sched_ctrl->mcs %d\n", sched_ctrl->mcs);
|
||||
|
||||
@@ -418,14 +418,13 @@ 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;
|
||||
const uint16_t bwpSize = NRRIV2BW(sched_ctrl->active_bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
|
||||
int rbStart = NRRIV2PRBOFFSET(sched_ctrl->active_bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
|
||||
|
||||
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 */
|
||||
@@ -563,11 +562,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,
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -290,6 +290,31 @@ void nr_csi_meas_reporting(int Mod_idP,
|
||||
}
|
||||
}
|
||||
|
||||
static 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,
|
||||
@@ -309,50 +334,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -375,50 +373,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,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
|
||||
@@ -338,7 +339,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;
|
||||
@@ -425,6 +426,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;
|
||||
|
||||
Reference in New Issue
Block a user