From abc65b1d868432ee1c9a7597b51f247c87836ba9 Mon Sep 17 00:00:00 2001
From: Robert Schmidt <robert.schmidt@eurecom.fr>
Date: Thu, 27 Feb 2020 16:47:11 +0100
Subject: [PATCH] Reimplement UL PP

---
 openair2/LAYER2/MAC/mac.h           |   8 +
 openair2/LAYER2/MAC/mac_proto.h     |   9 -
 openair2/LAYER2/MAC/pre_processor.c | 467 ++++++++++++++++++++--------
 3 files changed, 352 insertions(+), 132 deletions(-)

diff --git a/openair2/LAYER2/MAC/mac.h b/openair2/LAYER2/MAC/mac.h
index 16a1d8ec17..feba483147 100644
--- a/openair2/LAYER2/MAC/mac.h
+++ b/openair2/LAYER2/MAC/mac.h
@@ -1262,6 +1262,14 @@ typedef struct {
   uint8_t rballoc_sub[NFAPI_CC_MAX][N_RBG_MAX];
 } slice_info_t;
 
+/**
+ * describes contiguous RBs
+ */
+typedef struct {
+  int start;
+  int length;
+} contig_rbs_t;
+
 /*! \brief eNB common channels */
 typedef struct {
   int physCellId;
diff --git a/openair2/LAYER2/MAC/mac_proto.h b/openair2/LAYER2/MAC/mac_proto.h
index ed4c2be024..650d5999e1 100644
--- a/openair2/LAYER2/MAC/mac_proto.h
+++ b/openair2/LAYER2/MAC/mac_proto.h
@@ -674,15 +674,6 @@ void ulsch_scheduler_pre_processor(module_id_t module_idP,
                                    sub_frame_t subframeP,
                                    int sched_frameP,
                                    unsigned char sched_subframeP);
-void store_ulsch_buffer(module_id_t module_idP, int frameP,
-                        sub_frame_t subframeP);
-void assign_max_mcs_min_rb(module_id_t module_idP,
-                           int CC_id,
-                           int frameP,
-                           sub_frame_t subframeP,
-                           int available_rbs);
-void adjust_bsr_info(int buffer_occupancy, uint16_t TBS,
-                     UE_TEMPLATE *UE_template);
 
 int phy_stats_exist(module_id_t Mod_id, int rnti);
 
diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c
index 8563120856..613edf9127 100644
--- a/openair2/LAYER2/MAC/pre_processor.c
+++ b/openair2/LAYER2/MAC/pre_processor.c
@@ -380,111 +380,12 @@ dlsch_scheduler_pre_processor(module_id_t Mod_id,
     }
   }
   if (print)
-    LOG_I(MAC, "%4d.%d DL scheduler allocation list: %s\n", frameP, subframeP, t);
+    LOG_D(MAC, "%4d.%d DL scheduler allocation list: %s\n", frameP, subframeP, t);
 #endif
 }
 
 /// ULSCH PRE_PROCESSOR
 
-void ulsch_scheduler_pre_processor(module_id_t module_idP,
-                                   int CC_id,
-                                   int frameP,
-                                   sub_frame_t subframeP,
-                                   int sched_frameP,
-                                   unsigned char sched_subframeP) {
-  uint16_t nb_allocated_rbs[MAX_MOBILES_PER_ENB];
-  uint16_t total_allocated_rbs = 0;
-  uint16_t average_rbs_per_user = 0;
-  int16_t total_remaining_rbs = 0;
-  uint16_t total_ue_count = 0;
-
-  UE_info_t *UE_info = &RC.mac[module_idP]->UE_info;
-  const int N_RB_UL = to_prb(RC.mac[module_idP]->common_channels[CC_id].ul_Bandwidth);
-  const COMMON_channels_t *cc = &RC.mac[module_idP]->common_channels[CC_id];
-  int available_rbs = 0;
-  int first_rb = -1;
-  for (int i = 0; i < N_RB_UL; ++i) {
-    if (cc->vrb_map_UL[i] == 0) {
-      available_rbs++;
-      if (first_rb < 0)
-        first_rb = i;
-    }
-  }
-
-  // maximize MCS and then allocate required RB according to the buffer
-  // occupancy with the limit of max available UL RB
-  LOG_D(MAC, "In ulsch_preprocessor: assign max mcs min rb\n");
-  assign_max_mcs_min_rb(module_idP, CC_id, frameP, subframeP, available_rbs);
-
-  for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) {
-    if (UE_info->UE_template[CC_id][UE_id].pre_allocated_nb_rb_ul > 0) {
-      total_ue_count++;
-    }
-  }
-
-  if (total_ue_count == 0)
-    average_rbs_per_user = 0;
-  else if (total_ue_count == 1)
-    average_rbs_per_user = available_rbs + 1;
-  else if (total_ue_count <= available_rbs)
-    average_rbs_per_user = (uint16_t) floor(available_rbs / total_ue_count);
-  else
-    average_rbs_per_user = 1;
-
-  if (total_ue_count > 0)
-    LOG_D(MAC, "[eNB %d] Frame %d subframe %d: total ue to be scheduled %d\n",
-          module_idP,
-          frameP,
-          subframeP,
-          total_ue_count);
-
-  for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) {
-    uint8_t harq_pid = subframe2harqpid(&RC.mac[module_idP]->common_channels[CC_id],
-                                        sched_frameP, sched_subframeP);
-
-    if (UE_info->UE_sched_ctrl[UE_id].round_UL[CC_id][harq_pid] > 0)
-      nb_allocated_rbs[UE_id] = UE_info->UE_template[CC_id][UE_id].nb_rb_ul[harq_pid];
-    else
-      nb_allocated_rbs[UE_id] = cmin(UE_info->UE_template[CC_id][UE_id].pre_allocated_nb_rb_ul, average_rbs_per_user);
-
-    total_allocated_rbs += nb_allocated_rbs[UE_id];
-    LOG_D(MAC, "In ulsch_preprocessor: assigning %d RBs for UE %d CCid %d, harq_pid %d\n",
-          nb_allocated_rbs[UE_id],
-          UE_id,
-          CC_id,
-          harq_pid);
-  }
-
-  for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) {
-    UE_TEMPLATE *UE_template = &UE_info->UE_template[CC_id][UE_id];
-    total_remaining_rbs = available_rbs - total_allocated_rbs;
-
-    /* TODO this has already been accounted for - do we need it again? */
-    //if (total_ue_count == 1)
-    //  total_remaining_rbs++;
-
-    while (UE_template->pre_allocated_nb_rb_ul > 0 &&
-           nb_allocated_rbs[UE_id] < UE_template->pre_allocated_nb_rb_ul &&
-           total_remaining_rbs > 0) {
-      nb_allocated_rbs[UE_id] = cmin(nb_allocated_rbs[UE_id] + 1, UE_template->pre_allocated_nb_rb_ul);
-      total_remaining_rbs--;
-      total_allocated_rbs++;
-    }
-
-    UE_template->pre_first_nb_rb_ul = first_rb;
-    UE_template->pre_allocated_nb_rb_ul = nb_allocated_rbs[UE_id];
-    first_rb += nb_allocated_rbs[UE_id];
-    LOG_D(MAC, "******************UL Scheduling Information for UE%d CC_id %d ************************\n",
-          UE_id,
-          CC_id);
-    LOG_D(MAC, "[eNB %d] total RB allocated for UE%d CC_id %d  = %d\n",
-          module_idP,
-          UE_id,
-          CC_id,
-          UE_template->pre_allocated_nb_rb_ul);
-  }
-}
-
 void calculate_max_mcs_min_rb(module_id_t mod_id,
                               int CC_id,
                               int bytes,
@@ -530,29 +431,106 @@ void calculate_max_mcs_min_rb(module_id_t mod_id,
   }
 }
 
-void
-assign_max_mcs_min_rb(module_id_t module_idP,
-                      int CC_id,
-                      int frameP,
-                      sub_frame_t subframeP,
-                      int available_rbs) {
-  const int Ncp = RC.mac[module_idP]->common_channels[CC_id].Ncp;
-  UE_info_t *UE_info = &RC.mac[module_idP]->UE_info;
+int pp_find_rb_table_index(int approximate) {
+  int lo = 2;
+  if (approximate <= rb_table[lo])
+    return lo;
+  int hi = sizeof(rb_table) - 1;
+  if (approximate >= rb_table[hi])
+    return hi;
+  int p = (hi + lo) / 2;
+  for (; lo + 1 != hi; p = (hi + lo) / 2) {
+    if (approximate <= rb_table[p])
+      hi = p;
+    else
+      lo = p;
+  }
+  return p + 1;
+}
 
-  for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) {
+int g_start_ue_ul = -1;
+int round_robin_ul(module_id_t Mod_id,
+                   int CC_id,
+                   int frame,
+                   int subframe,
+                   int sched_frame,
+                   int sched_subframe,
+                   UE_list_t *UE_list,
+                   int max_num_ue,
+                   int num_contig_rb,
+                   contig_rbs_t *rbs) {
+  AssertFatal(num_contig_rb <= 2, "cannot handle more than two contiguous RB regions\n");
+  UE_info_t *UE_info = &RC.mac[Mod_id]->UE_info;
+  const int max_rb = num_contig_rb > 1 ? MAX(rbs[0].length, rbs[1].length) : rbs[0].length;
+
+  /* for every UE: check whether we have to handle a retransmission (and
+   * allocate, if so). If not, compute how much RBs this UE would need */
+  int rb_idx_required[MAX_MOBILES_PER_ENB];
+  memset(rb_idx_required, 0, sizeof(rb_idx_required));
+  int num_ue_req = 0;
+  for (int UE_id = UE_list->head; UE_id >= 0; UE_id = UE_list->next[UE_id]) {
     UE_TEMPLATE *UE_template = &UE_info->UE_template[CC_id][UE_id];
+    uint8_t harq_pid = subframe2harqpid(&RC.mac[Mod_id]->common_channels[CC_id],
+                                        sched_frame, sched_subframe);
+    if (UE_info->UE_sched_ctrl[UE_id].round_UL[CC_id][harq_pid] > 0) {
+      /* this UE has a retransmission, allocate it right away */
+      const int nb_rb = UE_template->nb_rb_ul[harq_pid];
+      if (nb_rb == 0) {
+        LOG_E(MAC,
+              "%4d.%d UE %d retransmission of 0 RBs in round %d, ignoring\n",
+              sched_frame, sched_subframe, UE_id,
+              UE_info->UE_sched_ctrl[UE_id].round_UL[CC_id][harq_pid]);
+        continue;
+      }
+      if (rbs[0].length >= nb_rb) { // fits in first contiguous region
+        UE_template->pre_first_nb_rb_ul = rbs[0].start;
+        rbs[0].length -= nb_rb;
+        rbs[0].start += nb_rb;
+      } else if (num_contig_rb == 2 && rbs[1].length >= nb_rb) { // in second
+        UE_template->pre_first_nb_rb_ul = rbs[1].start;
+        rbs[1].length -= nb_rb;
+        rbs[1].start += nb_rb;
+      } else if (num_contig_rb == 2
+          && rbs[1].start + rbs[1].length - rbs[0].start >= nb_rb) { // overlapping the middle
+        UE_template->pre_first_nb_rb_ul = rbs[0].start;
+        rbs[0].length = 0;
+        int ol = nb_rb - (rbs[1].start - rbs[0].start); // how much overlap in second region
+        if (ol > 0) {
+          rbs[1].length -= ol;
+          rbs[1].start += ol;
+        }
+      } else {
+        LOG_W(MAC,
+              "cannot allocate UL retransmission for UE %d (nb_rb %d)\n",
+              UE_id,
+              nb_rb);
+        continue;
+      }
+      LOG_D(MAC, "%4d.%d UE %d retx %d RBs at start %d\n",
+            sched_frame,
+            sched_subframe,
+            UE_id,
+            UE_template->pre_allocated_nb_rb_ul,
+            UE_template->pre_first_nb_rb_ul);
+      UE_template->pre_allocated_nb_rb_ul = nb_rb;
+      max_num_ue--;
+      if (max_num_ue == 0) /* in this case, cannot allocate any other UE anymore */
+        return rbs[0].length + (num_contig_rb > 1 ? rbs[1].length : 0);
+      continue;
+    }
 
     const int B = cmax(UE_template->estimated_ul_buffer - UE_template->scheduled_ul_bytes, 0);
-
-    const int UE_to_be_scheduled = UE_is_to_be_scheduled(module_idP, CC_id, UE_id);
+    const int UE_to_be_scheduled = UE_is_to_be_scheduled(Mod_id, CC_id, UE_id);
     if (B == 0 && !UE_to_be_scheduled)
       continue;
 
+    num_ue_req++;
+
     /* if UE has pending scheduling request then pre-allocate 3 RBs */
     if (B == 0 && UE_to_be_scheduled) {
       UE_template->pre_assigned_mcs_ul = 10; /* use QPSK mcs only */
-      UE_template->pre_allocated_rb_table_index_ul = 2;
-      UE_template->pre_allocated_nb_rb_ul = 3;
+      rb_idx_required[UE_id] = 2;
+      //UE_template->pre_allocated_nb_rb_ul = 3;
       continue;
     }
 
@@ -560,28 +538,271 @@ assign_max_mcs_min_rb(module_id_t module_idP,
     int rb_table_index;
     int tx_power;
     calculate_max_mcs_min_rb(
-        module_idP,
+        Mod_id,
         CC_id,
         B,
         UE_template->phr_info,
         UE_info->UE_sched_ctrl[UE_id].phr_received == 1 ? 20 : 10,
         &mcs,
-        available_rbs,
+        max_rb,
         &rb_table_index,
         &tx_power);
 
     UE_template->pre_assigned_mcs_ul = mcs;
-    UE_template->pre_allocated_rb_table_index_ul = rb_table_index;
-    UE_template->pre_allocated_nb_rb_ul = rb_table[rb_table_index];
-    LOG_D(MAC, "[eNB %d] frame %d subframe %d: for UE %d CC %d: pre-assigned mcs %d, pre-allocated rb_table[%d]=%d RBs (phr %d, tx power %d)\n",
-          module_idP,
+    rb_idx_required[UE_id] = rb_table_index;
+    //UE_template->pre_allocated_nb_rb_ul = rb_table[rb_table_index];
+    /* only print log when PHR changed */
+    static int phr = 0;
+    if (phr != UE_template->phr_info) {
+      phr = UE_template->phr_info;
+      LOG_D(MAC, "%d.%d UE %d CC %d: pre mcs %d, pre rb_table[%d]=%d RBs (phr %d, tx power %d, bytes %d)\n",
+            frame,
+            subframe,
+            UE_id,
+            CC_id,
+            UE_template->pre_assigned_mcs_ul,
+            UE_template->pre_allocated_rb_table_index_ul,
+            UE_template->pre_allocated_nb_rb_ul,
+            UE_template->phr_info,
+            tx_power,
+            B);
+    }
+  }
+
+  if (num_ue_req == 0)
+    return rbs[0].length + (num_contig_rb > 1 ? rbs[1].length : 0);
+
+  // calculate how many users should be in both regions, and to maximize usage,
+  // go from the larger to the smaller one which at least will handle a single
+  // full load case better.
+  const int n = min(num_ue_req, max_num_ue);
+  int nr[2] = {n, 0};
+  int step = 1; // the order if we have two regions
+  int start = 0;
+  int end = 1;
+  if (num_contig_rb > 1) {
+    // proportionally divide between both regions
+    int la = rbs[0].length > 0 ? rbs[0].length : 1;
+    int lb = rbs[1].length > 0 ? rbs[1].length : 1;
+    nr[1] = min(max(n/(la/lb + 1), 1), n - 1);
+    nr[0] = n - nr[1];
+    step = la > lb ? 1 : -1; // 1: from 0 to 1, -1: from 1 to 0
+    start = la > lb ? 0 : 1;
+    end = la > lb ? 2 : -1;
+  }
+
+  if (g_start_ue_ul == -1)
+    g_start_ue_ul = UE_list->head;
+  int sUE_id = g_start_ue_ul;
+  int rb_idx_given[MAX_MOBILES_PER_ENB];
+  memset(rb_idx_given, 0, sizeof(rb_idx_given));
+
+  for (int r = start; r != end; r += step) {
+    // don't allocate if we have too little RBs
+    if (rbs[r].length < 3)
+      continue;
+    if (nr[r] <= 0)
+      continue;
+
+    UE_list_t UE_sched;
+    // average RB index: just below the index that fits all UEs
+    int start_idx = pp_find_rb_table_index(rbs[r].length / nr[r]) - 1;
+    int num_ue_sched = 0;
+    int rb_required_add = 0;
+    int *cur_UE = &UE_sched.head;
+    while (num_ue_sched < nr[r]) {
+      while (rb_idx_required[sUE_id] == 0)
+        sUE_id = next_ue_list_looped(UE_list, sUE_id);
+      /* TODO: check that CCE allocated is feasible. If it is not, reduce
+       * nr[r] by one as this would been one opportunity */
+      *cur_UE = sUE_id;
+      cur_UE = &UE_sched.next[sUE_id];
+      rb_idx_given[sUE_id] = min(start_idx, rb_idx_required[sUE_id]);
+      rb_required_add += rb_table[rb_idx_required[sUE_id]] - rb_table[rb_idx_given[sUE_id]];
+      rbs[r].length -= rb_table[rb_idx_given[sUE_id]];
+      num_ue_sched++;
+      sUE_id = next_ue_list_looped(UE_list, sUE_id);
+    }
+    *cur_UE = -1;
+
+    /* give remaining RBs in RR fashion. Since we don't know in advance the
+     * amount of RBs we can give (the "step size" in rb_table is non-linear), go
+     * through all UEs and try to give a bit more. Continue until no UE can be
+     * given a higher index because the remaining RBs do not suffice to increase */
+    int UE_id = UE_sched.head;
+    int rb_required_add_old;
+    do {
+      rb_required_add_old = rb_required_add;
+      for (int UE_id = UE_sched.head; UE_id >= 0; UE_id = UE_sched.next[UE_id]) {
+        if (rb_idx_given[UE_id] >= rb_idx_required[UE_id])
+          continue; // this UE does not need more
+        const int new_idx = rb_idx_given[UE_id] + 1;
+        const int rb_inc = rb_table[new_idx] - rb_table[rb_idx_given[UE_id]];
+        if (rbs[r].length < rb_inc)
+          continue;
+        rb_idx_given[UE_id] = new_idx;
+        rbs[r].length -= rb_inc;
+        rb_required_add -= rb_inc;
+      }
+    } while (rb_required_add != rb_required_add_old);
+
+    for (UE_id = UE_sched.head; UE_id >= 0; UE_id = UE_sched.next[UE_id]) {
+      UE_TEMPLATE *UE_template = &UE_info->UE_template[CC_id][UE_id];
+
+      /* MCS has been allocated previously */
+      UE_template->pre_first_nb_rb_ul = rbs[r].start;
+      UE_template->pre_allocated_rb_table_index_ul = rb_idx_given[UE_id];
+      UE_template->pre_allocated_nb_rb_ul = rb_table[rb_idx_given[UE_id]];
+      rbs[r].start += rb_table[rb_idx_given[UE_id]];
+      LOG_D(MAC, "%4d.%d UE %d allocated %d RBs start %d new start %d\n",
+            sched_frame,
+            sched_subframe,
+            UE_id,
+            UE_template->pre_allocated_nb_rb_ul,
+            UE_template->pre_first_nb_rb_ul,
+            rbs[r].start);
+    }
+  }
+
+  /* if not all UEs could be allocated in this round */
+  if (num_ue_req > max_num_ue) {
+    /* go to the first one we missed */
+    for (int i = 0; i < max_num_ue; ++i)
+      g_start_ue_ul = next_ue_list_looped(UE_list, g_start_ue_ul);
+  } else {
+    /* else, just start with the next UE next time */
+    g_start_ue_ul = next_ue_list_looped(UE_list, g_start_ue_ul);
+  }
+
+  return rbs[0].length + (num_contig_rb > 1 ? rbs[1].length : 0);
+}
+
+void ulsch_scheduler_pre_processor(module_id_t Mod_id,
+                                   int CC_id,
+                                   int frameP,
+                                   sub_frame_t subframeP,
+                                   int sched_frameP,
+                                   unsigned char sched_subframeP) {
+  UE_info_t *UE_info = &RC.mac[Mod_id]->UE_info;
+  const int N_RB_UL = to_prb(RC.mac[Mod_id]->common_channels[CC_id].ul_Bandwidth);
+  COMMON_channels_t *cc = &RC.mac[Mod_id]->common_channels[CC_id];
+
+  UE_list_t UE_to_sched;
+  UE_to_sched.head = -1;
+  for (int i = 0; i < MAX_MOBILES_PER_ENB; ++i)
+    UE_to_sched.next[i] = -1;
+
+  int last_UE_id = -1;
+  for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) {
+    UE_TEMPLATE *UE_template = &UE_info->UE_template[CC_id][UE_id];
+    UE_sched_ctrl_t *ue_sched_ctrl = &UE_info->UE_sched_ctrl[UE_id];
+
+    /* initialize per-UE scheduling information */
+    UE_template->pre_assigned_mcs_ul = 0;
+    UE_template->pre_allocated_nb_rb_ul = 0;
+    UE_template->pre_allocated_rb_table_index_ul = -1;
+    UE_template->pre_first_nb_rb_ul = 0;
+
+    const rnti_t rnti = UE_RNTI(Mod_id, UE_id);
+    if (rnti == NOT_A_RNTI) {
+      LOG_E(MAC, "UE %d has RNTI NOT_A_RNTI!\n", UE_id);
+      continue;
+    }
+    if (ue_sched_ctrl->cdrx_configured && !ue_sched_ctrl->in_active_time)
+      continue;
+    if (UE_info->UE_template[CC_id][UE_id].rach_resource_type > 0)
+      continue;
+
+    /* define UEs to schedule */
+    if (UE_to_sched.head < 0)
+      UE_to_sched.head = UE_id;
+    else
+      UE_to_sched.next[last_UE_id] = UE_id;
+    UE_to_sched.next[UE_id] = -1;
+    last_UE_id = UE_id;
+  }
+
+  if (UE_to_sched.head < 0)
+    return;
+
+  int last_rb_blocked = 1;
+  int n_contig = 0;
+  contig_rbs_t rbs[2]; // up to two contig RBs for PRACH in between
+  for (int i = 0; i < N_RB_UL; ++i) {
+    if (cc->vrb_map_UL[i] == 0 && last_rb_blocked == 1) {
+      last_rb_blocked = 0;
+      n_contig++;
+      AssertFatal(n_contig <= 2, "cannot handle more than two contiguous RB regions\n");
+      rbs[n_contig - 1].start = i;
+    }
+    if (cc->vrb_map_UL[i] == 1 && last_rb_blocked == 0) {
+      last_rb_blocked = 1;
+      rbs[n_contig - 1].length = i - rbs[n_contig - 1].start;
+    }
+  }
+
+  round_robin_ul(Mod_id,
+                 CC_id,
+                 frameP,
+                 subframeP,
+                 sched_frameP,
+                 sched_subframeP,
+                 &UE_to_sched,
+                 3, // max_num_ue
+                 n_contig,
+                 rbs);
+
+  // the following block is meant for validation of the pre-processor to check
+  // whether all UE allocations are non-overlapping and is not necessary for
+  // scheduling functionality
+#ifdef DEBUG_eNB_SCHEDULER
+  char t[101] = "__________________________________________________"
+                "__________________________________________________";
+  t[N_RB_UL] = 0;
+  for (int j = 0; j < N_RB_UL; j++)
+    if (cc->vrb_map_UL[j] != 0)
+      t[j] = 'x';
+  int print = 0;
+  for (int UE_id = UE_info->list.head; UE_id >= 0; UE_id = UE_info->list.next[UE_id]) {
+    UE_TEMPLATE *UE_template = &UE_info->UE_template[CC_id][UE_id];
+    if (UE_template->pre_allocated_nb_rb_ul == 0)
+      continue;
+
+    print = 1;
+    uint8_t harq_pid = subframe2harqpid(&RC.mac[Mod_id]->common_channels[CC_id],
+                                        sched_frameP, sched_subframeP);
+    LOG_D(MAC, "%4d.%d UE%d %d RBs (index %d) at start %d, pre MCS %d %s\n",
           frameP,
           subframeP,
           UE_id,
-          CC_id,
-          UE_template->pre_assigned_mcs_ul,
-          UE_template->pre_allocated_rb_table_index_ul,
           UE_template->pre_allocated_nb_rb_ul,
-          UE_template->phr_info, tx_power);
+          UE_template->pre_allocated_rb_table_index_ul,
+          UE_template->pre_first_nb_rb_ul,
+          UE_template->pre_assigned_mcs_ul,
+          UE_info->UE_sched_ctrl[UE_id].round_UL[CC_id][harq_pid] > 0 ? "(retx)" : "");
+
+    for (int i = 0; i < UE_template->pre_allocated_nb_rb_ul; ++i) {
+      /* only check if this is not a retransmission */
+      if (UE_info->UE_sched_ctrl[UE_id].round_UL[CC_id][harq_pid] == 0
+          && cc->vrb_map_UL[UE_template->pre_first_nb_rb_ul + i] == 1) {
+
+        LOG_I(MAC, "%4d.%d UL scheduler allocation list: %s\n", frameP, subframeP, t);
+        LOG_E(MAC,
+              "%4d.%d: UE %d allocated at locked RB %d (is: allocated start "
+              "%d/length %d)\n",
+              frameP, subframeP, UE_id, UE_template->pre_first_nb_rb_ul + i,
+              UE_template->pre_first_nb_rb_ul,
+              UE_template->pre_allocated_nb_rb_ul);
+      }
+      cc->vrb_map_UL[UE_template->pre_first_nb_rb_ul + i] = 1;
+      t[UE_template->pre_first_nb_rb_ul + i] = UE_id + '0';
+    }
   }
+  if (print)
+    LOG_D(MAC,
+          "%4d.%d UL scheduler allocation list: %s\n",
+          sched_frameP,
+          sched_subframeP,
+          t);
+#endif
 }
-- 
2.26.2