gNB_scheduler_ulsch.c 98.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
/*
 * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The OpenAirInterface Software Alliance licenses this file to You under
 * the OAI Public License, Version 1.1  (the "License"); you may not use this file
 * except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.openairinterface.org/?page_id=698
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *-------------------------------------------------------------------------------
 * For more information about the OpenAirInterface (OAI) Software Alliance:
 *      contact@openairinterface.org
 */

/*! \file gNB_scheduler_ulsch.c
 * \brief gNB procedures for the ULSCH transport channel
 * \author Navid Nikaein and Raymond Knopp, Guido Casati
 * \date 2019
 * \email: guido.casati@iis.fraunhofer.de
 * \version 1.0
 * @ingroup _mac
 */


#include "LAYER2/NR_MAC_gNB/mac_proto.h"
33
#include "executables/softmodem-common.h"
34
#include "common/utils/nr/nr_common.h"
35
#include "utils.h"
36
#include <openair2/UTIL/OPT/opt.h>
37
#include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h"
38
#include "LAYER2/nr_rlc/nr_rlc_oai_api.h"
39

40 41
//#define SRS_IND_DEBUG

mir's avatar
mir committed
42
int get_ul_tda(gNB_MAC_INST *nrmac, const NR_ServingCellConfigCommon_t *scc, int frame, int slot)
43 44 45
{
  /* we assume that this function is mutex-protected from outside */
  NR_SCHED_ENSURE_LOCKED(&nrmac->sched_lock);
46 47

  /* there is a mixed slot only when in TDD */
francescomani's avatar
francescomani committed
48
  const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL;
49
  AssertFatal(tdd || nrmac->common_channels->frame_type == FDD, "Dynamic TDD not handled yet\n");
50

51 52
  if (tdd && tdd->nrofUplinkSymbols > 1) { // if there is uplink symbols in mixed slot
    const int nr_slots_period = tdd->nrofDownlinkSlots + tdd->nrofUplinkSlots + 1;
53
    if ((slot % nr_slots_period) == tdd->nrofDownlinkSlots)
francescomani's avatar
francescomani committed
54 55 56 57 58 59 60
      return 2;
  }

  // Avoid slots with the SRS
  UE_iterator(nrmac->UE_info.list, UE) {
    NR_sched_srs_t sched_srs = UE->UE_sched_ctrl.sched_srs;
    if(sched_srs.srs_scheduled && sched_srs.frame == frame && sched_srs.slot == slot)
61
      return 1;
62
  }
francescomani's avatar
francescomani committed
63

64
  return 0; // if FDD or not mixed slot in TDD, for now use default TDA (TODO handle CSI-RS slots)
65 66
}

67 68
static int compute_ph_factor(int mu, int tbs_bits, int rb, int n_layers, int n_symbols, int n_dmrs, long *deltaMCS)
{
francescomani's avatar
francescomani committed
69 70
  // 38.213 7.1.1
  // if the PUSCH transmission is over more than one layer delta_tf = 0
francescomani's avatar
francescomani committed
71 72 73
  int delta_tf = 0;
  if(deltaMCS != NULL && n_layers == 1) {
    const int n_re = (NR_NB_SC_PER_RB * n_symbols - n_dmrs) * rb;
74 75
    const float BPRE = (float) tbs_bits/n_re;  //TODO change for PUSCH with CSI
    const float f = pow(2, BPRE * 1.25);
francescomani's avatar
francescomani committed
76 77 78 79 80
    const float beta = 1.0f; //TODO change for PUSCH with CSI
    delta_tf = (10 * log10((f - 1) * beta));
  }

  const int bw_factor = 10 * log10(rb << mu);
francescomani's avatar
francescomani committed
81

francescomani's avatar
francescomani committed
82
  return (delta_tf + bw_factor);
francescomani's avatar
francescomani committed
83 84
}

85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
//  For both UL-SCH except:
//   - UL-SCH: fixed-size MAC CE(known by LCID)
//   - UL-SCH: padding
//   - UL-SCH: MSG3 48-bits
//  |0|1|2|3|4|5|6|7|  bit-wise
//  |R|F|   LCID    |
//  |       L       |
//  |0|1|2|3|4|5|6|7|  bit-wise
//  |R|F|   LCID    |
//  |       L       |
//  |       L       |
//
//  For:
//   - UL-SCH: fixed-size MAC CE(known by LCID)
//   - UL-SCH: padding, for single/multiple 1-oct padding CE(s)
//   - UL-SCH: MSG3 48-bits
//  |0|1|2|3|4|5|6|7|  bit-wise
//  |R|R|   LCID    |
//
//  LCID: The Logical Channel ID field identifies the logical channel instance of the corresponding MAC SDU or the type of the corresponding MAC CE or padding as described in Tables 6.2.1-1 and 6.2.1-2 for the DL-SCH and UL-SCH respectively. There is one LCID field per MAC subheader. The LCID field size is 6 bits;
//  L: The Length field indicates the length of the corresponding MAC SDU or variable-sized MAC CE in bytes. There is one L field per MAC subheader except for subheaders corresponding to fixed-sized MAC CEs and padding. The size of the L field is indicated by the F field;
//  F: length of L is 0:8 or 1:16 bits wide
//  R: Reserved bit, set to zero.

109 110 111 112 113 114 115 116
static int nr_process_mac_pdu(instance_t module_idP,
                              NR_UE_info_t *UE,
                              uint8_t CC_id,
                              frame_t frameP,
                              sub_frame_t slot,
                              uint8_t *pduP,
                              int pdu_len,
                              const int8_t harq_pid)
117
{
cig's avatar
cig committed
118

119
  uint8_t done = 0;
120
  int sdus = 0;
121
  NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP;
122
  NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
cig's avatar
cig committed
123

francescomani's avatar
francescomani committed
124
  if (pduP[0] != UL_SCH_LCID_PADDING)
125
    trace_NRpdu(DIRECTION_UPLINK, pduP, pdu_len, WS_C_RNTI, UE->rnti, frameP, 0, 0, 0);
126

127 128 129 130
#ifdef ENABLE_MAC_PAYLOAD_DEBUG
  LOG_I(NR_MAC, "In %s: dumping MAC PDU in %d.%d:\n", __func__, frameP, slot);
  log_dump(NR_MAC, pduP, pdu_len, LOG_DUMP_CHAR, "\n");
#endif
131

132 133 134 135
  while (!done && pdu_len > 0){
    uint16_t mac_len=0;
    uint16_t mac_subheader_len=sizeof(NR_MAC_SUBHEADER_FIXED);
    uint8_t rx_lcid = ((NR_MAC_SUBHEADER_FIXED *)pduP)->LCID;
cig's avatar
cig committed
136

137
    LOG_D(NR_MAC, "In %s: received UL-SCH sub-PDU with LCID 0x%x in %d.%d (remaining PDU length %d)\n", __func__, rx_lcid, frameP, slot, pdu_len);
cig's avatar
cig committed
138

139 140
    unsigned char *ce_ptr;
    int n_Lcg = 0;
141

142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
    switch(rx_lcid){
      //  MAC CE
      /*#ifdef DEBUG_HEADER_PARSING
         LOG_D(NR_MAC, "[UE] LCID %d, PDU length %d\n", ((NR_MAC_SUBHEADER_FIXED *)pduP)->LCID, pdu_len);
      #endif*/
      case UL_SCH_LCID_RECOMMENDED_BITRATE_QUERY:
        // 38.321 Ch6.1.3.20
        mac_len = 2;
        break;
      case UL_SCH_LCID_CONFIGURED_GRANT_CONFIRMATION:
        // 38.321 Ch6.1.3.7
        break;
      case UL_SCH_LCID_S_BSR:
      case UL_SCH_LCID_S_TRUNCATED_BSR:
        //38.321 section 6.1.3.1
        //fixed length
        mac_len =1;
Melissa Elkadi's avatar
Melissa Elkadi committed
159 160 161 162 163
        if (pdu_len < sizeof(NR_BSR_SHORT)) {
              LOG_E(NR_MAC, "pdu_len %d is invalid (prior to cast of size %ld)\n",
                    pdu_len, sizeof(NR_BSR_SHORT));
              return 0;
        }
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
        /* Extract short BSR value */
        ce_ptr = &pduP[mac_subheader_len];
        NR_BSR_SHORT *bsr_s = (NR_BSR_SHORT *) ce_ptr;
        sched_ctrl->estimated_ul_buffer = 0;
        sched_ctrl->estimated_ul_buffer = NR_SHORT_BSR_TABLE[bsr_s->Buffer_size];
        LOG_D(NR_MAC,
              "SHORT BSR at %4d.%2d, LCG ID %d, BS Index %d, BS value < %d, est buf %d\n",
              frameP,
              slot,
              bsr_s->LcgID,
              bsr_s->Buffer_size,
              NR_SHORT_BSR_TABLE[bsr_s->Buffer_size],
              sched_ctrl->estimated_ul_buffer);
        break;
      case UL_SCH_LCID_L_BSR:
      case UL_SCH_LCID_L_TRUNCATED_BSR:
        //38.321 section 6.1.3.1
        //variable length
        /* Several checks have been added to this function to
           ensure that the casting of the pduP is possible. There seems
           to be a partial PDU at the end of this buffer, so here
           we gracefully ignore that by returning 0. See:
           https://gitlab.eurecom.fr/oai/openairinterface5g/-/issues/534 */
187 188
        if (!get_mac_len(pduP, pdu_len, &mac_len, &mac_subheader_len)) {
          LOG_E(NR_MAC, "pdu_len %d is invalid (shorter than MAC PDU header)\n", pdu_len);
189
          return 0;
190
        }
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
        /* Extract long BSR value */
        ce_ptr = &pduP[mac_subheader_len];
        NR_BSR_LONG *bsr_l = (NR_BSR_LONG *) ce_ptr;
        sched_ctrl->estimated_ul_buffer = 0;

        n_Lcg = bsr_l->LcgID7 + bsr_l->LcgID6 + bsr_l->LcgID5 + bsr_l->LcgID4 +
                bsr_l->LcgID3 + bsr_l->LcgID2 + bsr_l->LcgID1 + bsr_l->LcgID0;

        LOG_D(NR_MAC, "LONG BSR, LCG ID(7-0) %d/%d/%d/%d/%d/%d/%d/%d\n",
              bsr_l->LcgID7, bsr_l->LcgID6, bsr_l->LcgID5, bsr_l->LcgID4,
              bsr_l->LcgID3, bsr_l->LcgID2, bsr_l->LcgID1, bsr_l->LcgID0);

        for (int n = 0; n < n_Lcg; n++){
          LOG_D(NR_MAC, "LONG BSR, %d/%d (n/n_Lcg), BS Index %d, BS value < %d",
                n, n_Lcg, pduP[mac_subheader_len + 1 + n],
                NR_LONG_BSR_TABLE[pduP[mac_subheader_len + 1 + n]]);
          sched_ctrl->estimated_ul_buffer += NR_LONG_BSR_TABLE[pduP[mac_subheader_len + 1 + n]];
          LOG_D(NR_MAC,
                "LONG BSR at %4d.%2d, %d/%d (n/n_Lcg), BS Index %d, BS value < %d, total %d\n",
                frameP,
                slot,
                n,
                n_Lcg,
                pduP[mac_subheader_len + 1 + n],
                NR_LONG_BSR_TABLE[pduP[mac_subheader_len + 1 + n]],
                sched_ctrl->estimated_ul_buffer);
        }
ChiehChun's avatar
ChiehChun committed
218

219
        break;
220

221
      case UL_SCH_LCID_C_RNTI:
222

223 224 225
        for (int i = 0; i < NR_NB_RA_PROC_MAX; i++) {
          NR_RA_t *ra = &RC.nrmac[module_idP]->common_channels[CC_id].ra[i];
          if (ra->state >= WAIT_Msg3 && ra->rnti == UE->rnti) {
226 227 228 229 230 231 232
            // remove UE context just created after Msg.3 in some milliseconds
            // as the UE is one already known (not now, as the UE context is
            // still needed for the moment)
            nr_mac_trigger_release_timer(&UE->UE_sched_ctrl, UE->current_UL_BWP.scs);
            //mac_remove_nr_ue(RC.nrmac[module_idP], ra->rnti);
            // this UE is the one identified by the RNTI in pduP
            ra->rnti = ((pduP[1]&0xFF)<<8)|(pduP[2]&0xFF);
233
            ra->state = Msg3_dcch_dtch;
234
            break;
235
          }
236
        }
237

238 239 240 241 242
        //38.321 section 6.1.3.2
        //fixed length
        mac_len = 2;
        /* Extract CRNTI value */
        break;
243

244
      case UL_SCH_LCID_SINGLE_ENTRY_PHR:
245 246 247 248 249
        if (harq_pid < 0) {
          LOG_E(NR_MAC, "Invalid HARQ PID %d\n", harq_pid);
          done = 1;
          break;
        }
francescomani's avatar
francescomani committed
250
        NR_sched_pusch_t *sched_pusch = &sched_ctrl->ul_harq_processes[harq_pid].sched_pusch;;
251 252 253 254 255 256 257
        //38.321 section 6.1.3.8
        //fixed length
        mac_len = 2;
        /* Extract SINGLE ENTRY PHR elements for PHR calculation */
        ce_ptr = &pduP[mac_subheader_len];
        NR_SINGLE_ENTRY_PHR_MAC_CE *phr = (NR_SINGLE_ENTRY_PHR_MAC_CE *) ce_ptr;
        /* Save the phr info */
francescomani's avatar
francescomani committed
258
        int PH;
259 260
        const int PCMAX = phr->PCMAX;
        /* 38.133 Table10.1.17.1-1 */
francescomani's avatar
francescomani committed
261 262
        if (phr->PH < 55)
          PH = phr->PH - 32;
263
        else
francescomani's avatar
francescomani committed
264 265
          PH = phr->PH - 32 + (phr->PH - 54);
        // in sched_ctrl we set normalized PH wrt MCS and PRBs
266
        long *deltaMCS = ul_bwp->pusch_Config ? ul_bwp->pusch_Config->pusch_PowerControl->deltaMCS : NULL;
francescomani's avatar
francescomani committed
267
        sched_ctrl->ph = PH +
268
                         compute_ph_factor(ul_bwp->scs,
francescomani's avatar
francescomani committed
269 270 271 272 273 274
                                           sched_pusch->tb_size<<3,
                                           sched_pusch->rbSize,
                                           sched_pusch->nrOfLayers,
                                           sched_pusch->tda_info.nrOfSymbols, //n_symbols
                                           sched_pusch->dmrs_info.num_dmrs_symb*sched_pusch->dmrs_info.N_PRB_DMRS, //n_dmrs
                                           deltaMCS);
275 276
        /* 38.133 Table10.1.18.1-1 */
        sched_ctrl->pcmax = PCMAX - 29;
francescomani's avatar
francescomani committed
277
        LOG_D(NR_MAC, "SINGLE ENTRY PHR R1 %d PH %d (%d dB) R2 %d PCMAX %d (%d dBm)\n",
278 279
              phr->R1, PH, sched_ctrl->ph, phr->R2, PCMAX, sched_ctrl->pcmax);
        break;
280

281
      case UL_SCH_LCID_MULTI_ENTRY_PHR_1_OCT:
282 283
        LOG_E(NR_MAC, "Multi entry PHR not supported\n");
        done = 1;
284
        //38.321 section 6.1.3.9
285
        //  variable length
286 287 288 289
        if (!get_mac_len(pduP, pdu_len, &mac_len, &mac_subheader_len))
          return 0;
        /* Extract MULTI ENTRY PHR elements from single octet bitmap for PHR calculation */
        break;
290

291
      case UL_SCH_LCID_MULTI_ENTRY_PHR_4_OCT:
292 293
        LOG_E(NR_MAC, "Multi entry PHR not supported\n");
        done = 1;
294
        //38.321 section 6.1.3.9
295
        //  variable length
296 297 298 299
        if (!get_mac_len(pduP, pdu_len, &mac_len, &mac_subheader_len))
          return 0;
        /* Extract MULTI ENTRY PHR elements from four octets bitmap for PHR calculation */
        break;
300

301 302 303 304
      case UL_SCH_LCID_PADDING:
        done = 1;
        //  end of MAC PDU, can ignore the rest.
        break;
305

306 307
      case UL_SCH_LCID_SRB1:
      case UL_SCH_LCID_SRB2:
308 309
        if (!get_mac_len(pduP, pdu_len, &mac_len, &mac_subheader_len)) {
          LOG_E(NR_MAC, "pdu_len %d is invalid (shorter than MAC PDU header)\n", pdu_len);
310
          return 0;
311
        }
312

313 314 315 316 317 318 319 320 321 322
        rnti_t crnti = UE->rnti;
        NR_UE_info_t* UE_idx = UE;
        for (int i = 0; i < NR_NB_RA_PROC_MAX; i++) {
          NR_RA_t *ra = &RC.nrmac[module_idP]->common_channels[CC_id].ra[i];
          if (ra->state >= WAIT_Msg3 && ra->rnti == UE->rnti) {
            uint8_t *next_subpduP = pduP + mac_subheader_len + mac_len;
            if ((pduP[mac_subheader_len+mac_len] & 0x3F) == UL_SCH_LCID_C_RNTI) {
              crnti = ((next_subpduP[1]&0xFF)<<8)|(next_subpduP[2]&0xFF);
              LOG_W(NR_MAC, " UL_SCH_LCID_SRB for rnti %04x\n", crnti);
              UE_idx = find_nr_UE(&RC.nrmac[module_idP]->UE_info, crnti);
323
              break;
324 325
            }
          }
326
        }
327

328 329
        if (UE_idx->CellGroup) {
          LOG_D(NR_MAC, "Frame %d : ULSCH -> UL-DCCH %d (gNB %ld, %d bytes), rnti: 0x%04x \n", frameP, rx_lcid, module_idP, mac_len, crnti);
330
          UE->mac_stats.ul.total_sdu_bytes += mac_len;
331
          mac_rlc_data_ind(module_idP,
332
                           crnti,
333 334 335 336 337
                           module_idP,
                           frameP,
                           ENB_FLAG_YES,
                           MBMS_FLAG_NO,
                           rx_lcid,
338
                           (char *) (pduP + mac_subheader_len),
339
                           mac_len,
340 341
                           1,
                           NULL);
342 343
        } else {
          AssertFatal(1==0,"[UE %04x] Frame/Slot %d.%d : Received LCID %d which is not configured, dropping packet\n",UE->rnti,frameP,slot,rx_lcid);
cig's avatar
cig committed
344
        }
345
        UE->mac_stats.ul.lc_bytes[rx_lcid] += mac_len;
346
        break;
347

348 349 350 351
      case UL_SCH_LCID_CCCH:
      case UL_SCH_LCID_CCCH1:
        // fixed length
        mac_subheader_len = 1;
Laurent THOMAS's avatar
Laurent THOMAS committed
352

353 354 355
        if ( rx_lcid == UL_SCH_LCID_CCCH1 ) {
          // RRCResumeRequest1 message includes the full I-RNTI and has a size of 8 bytes
          mac_len = 8;
356

357
          // Check if it is a valid CCCH1 message, we get all 00's messages very often
Melissa Elkadi's avatar
Melissa Elkadi committed
358 359 360 361 362
          if (pdu_len < mac_subheader_len + mac_len) {
              LOG_E(NR_MAC, "pdu_len %d is invalid (prior to cast of size %d)\n",
                    pdu_len, mac_subheader_len + mac_len);
              return 0;
        }
363 364 365 366 367 368 369 370 371
          int i = 0;
          for(i=0; i<(mac_subheader_len+mac_len); i++) {
            if(pduP[i] != 0) {
              break;
            }
          }
          if (i == (mac_subheader_len+mac_len)) {
            LOG_D(NR_MAC, "%s() Invalid CCCH1 message!, pdu_len: %d\n", __func__, pdu_len);
            done = 1;
372
            break;
373
          }
374
        } else {
375 376
          // fixed length of 6 bytes
          mac_len = 6;
377 378
        }

379
        LOG_W(MAC, "[RAPROC] Received SDU for CCCH length %d for UE %04x\n", mac_len, UE->rnti);
380

381
        prepare_initial_ul_rrc_message(RC.nrmac[module_idP], UE);
382 383 384 385 386 387 388 389 390 391 392
        mac_rlc_data_ind(module_idP,
                         UE->rnti,
                         module_idP,
                         frameP,
                         ENB_FLAG_YES,
                         MBMS_FLAG_NO,
                         0,
                         (char *) (pduP + mac_subheader_len),
                         mac_len,
                         1,
                         NULL);
393
        break;
cig's avatar
cig committed
394

395 396
      case UL_SCH_LCID_DTCH ... (UL_SCH_LCID_DTCH + 28):
        //  check if LCID is valid at current time.
397 398
        if (!get_mac_len(pduP, pdu_len, &mac_len, &mac_subheader_len)) {
          LOG_E(NR_MAC, "pdu_len %d is invalid (shorter than MAC PDU header)\n", pdu_len);
Eurecom's avatar
Eurecom committed
399
          return 0;
400
        }
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423

        LOG_D(NR_MAC, "[UE %04x] %d.%d : ULSCH -> UL-%s %d (gNB %ld, %d bytes)\n",
              UE->rnti,
              frameP,
              slot,
              rx_lcid<4?"DCCH":"DTCH",
              rx_lcid,
              module_idP,
              mac_len);
        UE->mac_stats.ul.lc_bytes[rx_lcid] += mac_len;

        mac_rlc_data_ind(module_idP,
                         UE->rnti,
                         module_idP,
                         frameP,
                         ENB_FLAG_YES,
                         MBMS_FLAG_NO,
                         rx_lcid,
                         (char *)(pduP + mac_subheader_len),
                         mac_len,
                         1,
                         NULL);

424
        sdus += 1;
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461
        /* Updated estimated buffer when receiving data */
        if (sched_ctrl->estimated_ul_buffer >= mac_len)
          sched_ctrl->estimated_ul_buffer -= mac_len;
        else
          sched_ctrl->estimated_ul_buffer = 0;
        break;

      default:
        LOG_E(NR_MAC, "Received unknown MAC header (LCID = 0x%02x)\n", rx_lcid);
        return -1;
        break;
      }

#ifdef ENABLE_MAC_PAYLOAD_DEBUG
      if (rx_lcid < 45 || rx_lcid == 52 || rx_lcid == 63) {
        LOG_I(NR_MAC, "In %s: dumping UL MAC SDU sub-header with length %d (LCID = 0x%02x):\n", __func__, mac_subheader_len, rx_lcid);
        log_dump(NR_MAC, pduP, mac_subheader_len, LOG_DUMP_CHAR, "\n");
        LOG_I(NR_MAC, "In %s: dumping UL MAC SDU with length %d (LCID = 0x%02x):\n", __func__, mac_len, rx_lcid);
        log_dump(NR_MAC, pduP + mac_subheader_len, mac_len, LOG_DUMP_CHAR, "\n");
      } else {
        LOG_I(NR_MAC, "In %s: dumping UL MAC CE with length %d (LCID = 0x%02x):\n", __func__, mac_len, rx_lcid);
        log_dump(NR_MAC, pduP + mac_subheader_len + mac_len, mac_len, LOG_DUMP_CHAR, "\n");
      }
#endif

      pduP += ( mac_subheader_len + mac_len );
      pdu_len -= ( mac_subheader_len + mac_len );

      if (pdu_len < 0) {
        LOG_E(NR_MAC, "In %s: residual UL MAC PDU in %d.%d with length < 0!, pdu_len %d \n", __func__, frameP, slot, pdu_len);
        LOG_E(NR_MAC, "MAC PDU ");
        for (int i = 0; i < 20; i++) // Only printf 1st - 20nd bytes
          printf("%02x ", pduP[i]);
        printf("\n");
        return 0;
      }
  }
Robert Schmidt's avatar
Robert Schmidt committed
462 463 464

  UE->mac_stats.ul.num_mac_sdu += sdus;

Eurecom's avatar
Eurecom committed
465
  return 0;
466
}
467

468
static void abort_nr_ul_harq(NR_UE_info_t *UE, int8_t harq_pid)
469
{
Laurent THOMAS's avatar
Laurent THOMAS committed
470
  NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
471 472 473 474
  NR_UE_ul_harq_t *harq = &sched_ctrl->ul_harq_processes[harq_pid];

  harq->ndi ^= 1;
  harq->round = 0;
Laurent THOMAS's avatar
Laurent THOMAS committed
475
  UE->mac_stats.ul.errors++;
476 477 478 479 480 481 482 483 484
  add_tail_nr_list(&sched_ctrl->available_ul_harq, harq_pid);

  /* the transmission failed: the UE won't send the data we expected initially,
   * so retrieve to correctly schedule after next BSR */
  sched_ctrl->sched_ul_bytes -= harq->sched_pusch.tb_size;
  if (sched_ctrl->sched_ul_bytes < 0)
    sched_ctrl->sched_ul_bytes = 0;
}

485
static bool get_UE_waiting_CFRA_msg3(const gNB_MAC_INST *gNB_mac, const int CC_id, const frame_t frame, const sub_frame_t slot)
486 487 488 489 490 491 492 493 494 495 496 497
{
  bool UE_waiting_CFRA_msg3 = false;
  for (int i = 0; i < NR_NB_RA_PROC_MAX; i++) {
    const NR_RA_t *ra = &gNB_mac->common_channels[CC_id].ra[i];
    if (ra->cfra == true && ra->state == WAIT_Msg3 && frame == ra->Msg3_frame && slot == ra->Msg3_slot) {
      UE_waiting_CFRA_msg3 = true;
      break;
    }
  }
  return UE_waiting_CFRA_msg3;
}

498 499
void handle_nr_ul_harq(const int CC_idP,
                       module_id_t mod_id,
500 501 502 503
                       frame_t frame,
                       sub_frame_t slot,
                       const nfapi_nr_crc_t *crc_pdu)
{
504 505 506 507 508
  gNB_MAC_INST *nrmac = RC.nrmac[mod_id];
  NR_SCHED_LOCK(&nrmac->sched_lock);

  NR_UE_info_t *UE = find_nr_UE(&nrmac->UE_info, crc_pdu->rnti);
  bool UE_waiting_CFRA_msg3 = get_UE_waiting_CFRA_msg3(nrmac, CC_idP, frame, slot);
509 510

  if (!UE || UE_waiting_CFRA_msg3 == true) {
Laurent THOMAS's avatar
Laurent THOMAS committed
511
    LOG_W(NR_MAC, "handle harq for rnti %04x, in RA process\n", crc_pdu->rnti);
512
    for (int i = 0; i < NR_NB_RA_PROC_MAX; ++i) {
513 514 515
      NR_RA_t *ra = &nrmac->common_channels[CC_idP].ra[i];
      if (ra->state >= WAIT_Msg3 && ra->rnti == crc_pdu->rnti) {
        NR_SCHED_UNLOCK(&nrmac->sched_lock);
516
        return;
517
      }
518
    }
519
    NR_SCHED_UNLOCK(&nrmac->sched_lock);
520
    LOG_E(NR_MAC, "%s(): unknown RNTI 0x%04x in PUSCH\n", __func__, crc_pdu->rnti);
521 522
    return;
  }
Laurent THOMAS's avatar
Laurent THOMAS committed
523
  NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
524
  int8_t harq_pid = sched_ctrl->feedback_ul_harq.head;
525
  LOG_D(NR_MAC, "Comparing crc_pdu->harq_id vs feedback harq_pid = %d %d\n",crc_pdu->harq_id, harq_pid);
526
  while (crc_pdu->harq_id != harq_pid || harq_pid < 0) {
527
    LOG_W(NR_MAC,
528
          "Unexpected ULSCH HARQ PID %d (have %d) for RNTI 0x%04x (ignore this warning for RA)\n",
529 530
          crc_pdu->harq_id,
          harq_pid,
531
          crc_pdu->rnti);
532 533
    if (harq_pid < 0) {
      NR_SCHED_UNLOCK(&nrmac->sched_lock);
534
      return;
535
    }
536 537

    remove_front_nr_list(&sched_ctrl->feedback_ul_harq);
538
    sched_ctrl->ul_harq_processes[harq_pid].is_waiting = false;
Laurent THOMAS's avatar
Laurent THOMAS committed
539

540
    if(sched_ctrl->ul_harq_processes[harq_pid].round >= RC.nrmac[mod_id]->ul_bler.harq_round_max - 1) {
Laurent THOMAS's avatar
Laurent THOMAS committed
541
      abort_nr_ul_harq(UE, harq_pid);
542 543 544 545
    } else {
      sched_ctrl->ul_harq_processes[harq_pid].round++;
      add_tail_nr_list(&sched_ctrl->retrans_ul_harq, harq_pid);
    }
546
    harq_pid = sched_ctrl->feedback_ul_harq.head;
547 548 549 550 551 552 553 554 555
  }
  remove_front_nr_list(&sched_ctrl->feedback_ul_harq);
  NR_UE_ul_harq_t *harq = &sched_ctrl->ul_harq_processes[harq_pid];
  DevAssert(harq->is_waiting);
  harq->feedback_slot = -1;
  harq->is_waiting = false;
  if (!crc_pdu->tb_crc_status) {
    harq->ndi ^= 1;
    harq->round = 0;
556
    LOG_D(NR_MAC,
557 558 559 560
          "Ulharq id %d crc passed for RNTI %04x\n",
          harq_pid,
          crc_pdu->rnti);
    add_tail_nr_list(&sched_ctrl->available_ul_harq, harq_pid);
561
  } else if (harq->round >= RC.nrmac[mod_id]->ul_bler.harq_round_max  - 1) {
Laurent THOMAS's avatar
Laurent THOMAS committed
562
    abort_nr_ul_harq(UE, harq_pid);
563
    LOG_D(NR_MAC,
564 565 566 567 568
          "RNTI %04x: Ulharq id %d crc failed in all rounds\n",
          crc_pdu->rnti,
          harq_pid);
  } else {
    harq->round++;
569
    LOG_D(NR_MAC,
570 571 572 573 574
          "Ulharq id %d crc failed for RNTI %04x\n",
          harq_pid,
          crc_pdu->rnti);
    add_tail_nr_list(&sched_ctrl->retrans_ul_harq, harq_pid);
  }
575
  NR_SCHED_UNLOCK(&nrmac->sched_lock);
576
}
577

578 579 580
/*
* When data are received on PHY and transmitted to MAC
*/
581 582 583 584 585 586 587 588 589 590 591
static void _nr_rx_sdu(const module_id_t gnb_mod_idP,
                       const int CC_idP,
                       const frame_t frameP,
                       const sub_frame_t slotP,
                       const rnti_t rntiP,
                       uint8_t *sduP,
                       const uint16_t sdu_lenP,
                       const uint16_t timing_advance,
                       const uint8_t ul_cqi,
                       const uint16_t rssi)
{
Robert Schmidt's avatar
Robert Schmidt committed
592 593 594
  gNB_MAC_INST *gNB_mac = RC.nrmac[gnb_mod_idP];

  const int current_rnti = rntiP;
Laurent THOMAS's avatar
Laurent THOMAS committed
595
  LOG_D(NR_MAC, "rx_sdu for rnti %04x\n", current_rnti);
Robert Schmidt's avatar
Robert Schmidt committed
596
  const int target_snrx10 = gNB_mac->pusch_target_snrx10;
597
  const int pusch_failure_thres = gNB_mac->pusch_failure_thres;
598 599 600 601 602 603

  NR_UE_info_t *UE = find_nr_UE(&gNB_mac->UE_info, current_rnti);
  bool UE_waiting_CFRA_msg3 = get_UE_waiting_CFRA_msg3(gNB_mac, CC_idP, frameP, slotP);

  if (UE && UE_waiting_CFRA_msg3 == false) {

Laurent THOMAS's avatar
Laurent THOMAS committed
604
    NR_UE_sched_ctrl_t *UE_scheduling_control = &UE->UE_sched_ctrl;
Robert Schmidt's avatar
Robert Schmidt committed
605 606 607 608 609 610
    const int8_t harq_pid = UE_scheduling_control->feedback_ul_harq.head;

    if (sduP)
      T(T_GNB_MAC_UL_PDU_WITH_DATA, T_INT(gnb_mod_idP), T_INT(CC_idP),
        T_INT(rntiP), T_INT(frameP), T_INT(slotP), T_INT(harq_pid),
        T_BUFFER(sduP, sdu_lenP));
611

Laurent THOMAS's avatar
Laurent THOMAS committed
612 613
    UE->mac_stats.ul.total_bytes += sdu_lenP;
    LOG_D(NR_MAC, "[gNB %d][PUSCH %d] CC_id %d %d.%d Received ULSCH sdu from PHY (rnti %04x) ul_cqi %d TA %d sduP %p, rssi %d\n",
614 615 616 617
          gnb_mod_idP,
          harq_pid,
          CC_idP,
          frameP,
618
          slotP,
619
          current_rnti,
620
          ul_cqi,
621
          timing_advance,
622 623
          sduP,
          rssi);
624

625
    // if not missed detection (10dB threshold for now)
626
    if (rssi>0) {
627
      UE_scheduling_control->tpc0 = nr_get_tpc(target_snrx10,ul_cqi,30);
628 629
      if (timing_advance != 0xffff)
        UE_scheduling_control->ta_update = timing_advance;
630 631
      UE_scheduling_control->raw_rssi = rssi;
      UE_scheduling_control->pusch_snrx10 = ul_cqi * 5 - 640;
Laurent THOMAS's avatar
Laurent THOMAS committed
632 633

      LOG_D(NR_MAC, "[UE %04x] PUSCH TPC %d and TA %d\n",UE->rnti,UE_scheduling_control->tpc0,UE_scheduling_control->ta_update);
634 635
    }
    else{
Laurent THOMAS's avatar
Laurent THOMAS committed
636
      LOG_D(NR_MAC,"[UE %04x] Detected DTX : increasing UE TX power\n",UE->rnti);
637
      UE_scheduling_control->tpc0 = 1;
638 639
    }

640
#if defined(ENABLE_MAC_PAYLOAD_DEBUG)
Laurent's avatar
Laurent committed
641

642
    LOG_I(NR_MAC, "Printing received UL MAC payload at gNB side: %d \n");
643
    for (int i = 0; i < sdu_lenP ; i++) {
francescomani's avatar
francescomani committed
644 645 646
      //harq_process_ul_ue->a[i] = (unsigned char) rand();
      //printf("a[%d]=0x%02x\n",i,harq_process_ul_ue->a[i]);
      printf("%02x ",(unsigned char)sduP[i]);
647 648
    }
    printf("\n");
Laurent's avatar
Laurent committed
649

650 651 652
#endif

    if (sduP != NULL){
rmagueta's avatar
rmagueta committed
653
      LOG_D(NR_MAC, "Received PDU at MAC gNB \n");
654

Laurent THOMAS's avatar
Laurent THOMAS committed
655
      UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt = 0;
656 657
      const uint32_t tb_size = UE_scheduling_control->ul_harq_processes[harq_pid].sched_pusch.tb_size;
      UE_scheduling_control->sched_ul_bytes -= tb_size;
658 659 660
      if (UE_scheduling_control->sched_ul_bytes < 0)
        UE_scheduling_control->sched_ul_bytes = 0;

francescomani's avatar
francescomani committed
661
      nr_process_mac_pdu(gnb_mod_idP, UE, CC_idP, frameP, slotP, sduP, sdu_lenP, harq_pid);
662 663
    }
    else {
664 665 666
      NR_UE_ul_harq_t *cur_harq = &UE_scheduling_control->ul_harq_processes[harq_pid];
      /* reduce sched_ul_bytes when cur_harq->round == 3 */
      if (cur_harq->round == 3){
667 668
        const uint32_t tb_size = UE_scheduling_control->ul_harq_processes[harq_pid].sched_pusch.tb_size;
        UE_scheduling_control->sched_ul_bytes -= tb_size;
669 670 671
        if (UE_scheduling_control->sched_ul_bytes < 0)
          UE_scheduling_control->sched_ul_bytes = 0;
      }
672
      if (ul_cqi <= 128) {
Laurent THOMAS's avatar
Laurent THOMAS committed
673 674
        UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt++;
        UE->mac_stats.ulsch_DTX++;
675
      }
Laurent THOMAS's avatar
Laurent THOMAS committed
676 677 678 679

      if (!get_softmodem_params()->phy_test && UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt >= pusch_failure_thres) {
         LOG_W(NR_MAC,"Detected UL Failure on PUSCH after %d PUSCH DTX, stopping scheduling\n",
               UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt);
680
         nr_mac_trigger_ul_failure(&UE->UE_sched_ctrl, UE->current_UL_BWP.scs);
681
      }
682
    }
683 684 685 686 687 688 689 690 691 692 693 694 695
  } else if(sduP) {

    bool no_sig = true;
    for (int k = 0; k < sdu_lenP; k++) {
      if(sduP[k]!=0) {
        no_sig = false;
        break;
      }
    }

    if(no_sig) {
      LOG_W(NR_MAC, "No signal\n");
    }
696

Robert Schmidt's avatar
Robert Schmidt committed
697 698 699
    T(T_GNB_MAC_UL_PDU_WITH_DATA, T_INT(gnb_mod_idP), T_INT(CC_idP),
      T_INT(rntiP), T_INT(frameP), T_INT(slotP), T_INT(-1) /* harq_pid */,
      T_BUFFER(sduP, sdu_lenP));
Laurent THOMAS's avatar
Laurent THOMAS committed
700
    
701 702 703 704 705 706 707
    /* we don't know this UE (yet). Check whether there is a ongoing RA (Msg 3)
     * and check the corresponding UE's RNTI match, in which case we activate
     * it. */
    for (int i = 0; i < NR_NB_RA_PROC_MAX; ++i) {
      NR_RA_t *ra = &gNB_mac->common_channels[CC_idP].ra[i];
      if (ra->state != WAIT_Msg3)
        continue;
Laurent THOMAS's avatar
Laurent THOMAS committed
708
      
709
      if(no_sig) {
710
        LOG_D(NR_MAC, "Random Access %i failed at state %i (no signal)\n", i, ra->state);
711
        nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra);
712 713 714 715
      } else {

        // random access pusch with TC-RNTI
        if (ra->rnti != current_rnti) {
716
          LOG_D(NR_MAC,
rmagueta's avatar
rmagueta committed
717
                "expected TC_RNTI %04x to match current RNTI %04x\n",
718 719
                ra->rnti,
                current_rnti);
rmagueta's avatar
rmagueta committed
720 721

          if( (frameP==ra->Msg3_frame) && (slotP==ra->Msg3_slot) ) {
722
            LOG_D(NR_MAC, "Random Access %i failed at state %i (TC_RNTI %04x RNTI %04x)\n", i, ra->state,ra->rnti,current_rnti);
rmagueta's avatar
rmagueta committed
723 724 725
            nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra);
          }

726 727
          continue;
        }
rmagueta's avatar
rmagueta committed
728

729 730 731 732
        NR_UE_info_t *UE_msg3_stage = UE ? UE : add_new_nr_ue(gNB_mac, ra->rnti, ra->CellGroup);
        if (!UE_msg3_stage) {
          LOG_W(NR_MAC, "Random Access %i discarded at state %i (TC_RNTI %04x RNTI %04x): max number of users achieved!\n", i, ra->state, ra->rnti, current_rnti);

733 734 735 736
          nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra);
          return;
        }

737
        UE_msg3_stage->UE_beam_index = ra->beam_id;
rmagueta's avatar
rmagueta committed
738 739

        // re-initialize ta update variables after RA procedure completion
740
        UE_msg3_stage->UE_sched_ctrl.ta_frame = frameP;
rmagueta's avatar
rmagueta committed
741

rmagueta's avatar
rmagueta committed
742
        LOG_D(NR_MAC,
743
              "reset RA state information for RA-RNTI 0x%04x/index %d\n",
744
              ra->rnti,
745
              i);
746

747
        LOG_I(NR_MAC,
748
              "[gNB %d][RAPROC] PUSCH with TC_RNTI 0x%04x received correctly, "
Laurent THOMAS's avatar
Laurent THOMAS committed
749
              "adding UE MAC Context RNTI 0x%04x\n",
750 751 752
              gnb_mod_idP,
              current_rnti,
              ra->rnti);
753

754
        NR_UE_sched_ctrl_t *UE_scheduling_control = &UE_msg3_stage->UE_sched_ctrl;
755

756
        UE_scheduling_control->tpc0 = nr_get_tpc(target_snrx10, ul_cqi, 30);
francescomani's avatar
francescomani committed
757 758 759 760
        if (timing_advance != 0xffff)
          UE_scheduling_control->ta_update = timing_advance;
        UE_scheduling_control->raw_rssi = rssi;
        UE_scheduling_control->pusch_snrx10 = ul_cqi * 5 - 640;
761 762
        LOG_D(NR_MAC, "[UE %04x] PUSCH TPC %d and TA %d\n", UE_msg3_stage->rnti, UE_scheduling_control->tpc0, UE_scheduling_control->ta_update);
        if (ra->cfra) {
Laurent THOMAS's avatar
Laurent THOMAS committed
763
          LOG_A(NR_MAC, "(rnti 0x%04x) CFRA procedure succeeded!\n", ra->rnti);
764
          nr_mac_reset_ul_failure(UE_scheduling_control);
765 766 767
          reset_dl_harq_list(UE_scheduling_control);
          reset_ul_harq_list(UE_scheduling_control);
          UE_msg3_stage->ra_timer = 0;
768
          nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra);
769
          process_CellGroup(ra->CellGroup, UE_msg3_stage);
770

771
        } else {
772

773
          LOG_A(NR_MAC,"[RAPROC] RA-Msg3 received (sdu_lenP %d)\n",sdu_lenP);
rmagueta's avatar
rmagueta committed
774
          LOG_D(NR_MAC,"[RAPROC] Received Msg3:\n");
775
          for (int k = 0; k < sdu_lenP; k++) {
rmagueta's avatar
rmagueta committed
776
            LOG_D(NR_MAC,"(%i): 0x%x\n",k,sduP[k]);
777
          }
778

779 780 781 782
          // UE Contention Resolution Identity
          // Store the first 48 bits belonging to the uplink CCCH SDU within Msg3 to fill in Msg4
          // First byte corresponds to R/LCID MAC sub-header
          memcpy(ra->cont_res_id, &sduP[1], sizeof(uint8_t) * 6);
francescomani's avatar
francescomani committed
783 784
          // harq_pid set a non valid value because it is not used in this call
          // the function is only called to decode the contention resolution sub-header
785
          if (nr_process_mac_pdu(gnb_mod_idP, UE_msg3_stage, CC_idP, frameP, slotP, sduP, sdu_lenP, -1) == 0) {
786
            
787
            if (ra->state == Msg3_dcch_dtch) {
788
              // Check if the UE identified by C-RNTI still exists at the gNB
789
              NR_UE_info_t * UE_C = find_nr_UE(&gNB_mac->UE_info, ra->rnti);
Laurent THOMAS's avatar
Laurent THOMAS committed
790
              if (!UE_C) {
791 792
                // The UE identified by C-RNTI no longer exists at the gNB
                // Let's abort the current RA, so the UE will trigger a new RA later but using RRCSetupRequest instead. A better solution may be implemented
Laurent THOMAS's avatar
Laurent THOMAS committed
793
                mac_remove_nr_ue(gNB_mac, ra->rnti);
794
                nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra);
795
                LOG_W(NR_MAC, "No UE found with C-RNTI %04x, ignoring Msg.3 to have UE come back with new RA attempt\n", ra->rnti);
796 797
                return;
              } else {
rmagueta's avatar
rmagueta committed
798 799 800
                // Reset Msg4_ACKed to not schedule ULSCH and DLSCH before RRC Reconfiguration
                UE_C->Msg4_ACKed = false;

801
                // The UE identified by C-RNTI still exists at the gNB
802
                nr_mac_reset_ul_failure(&UE_C->UE_sched_ctrl);
803 804 805 806

                // Reset HARQ processes
                reset_dl_harq_list(&UE_C->UE_sched_ctrl);
                reset_ul_harq_list(&UE_C->UE_sched_ctrl);
807 808 809 810

                // Trigger RRC Reconfiguration
                LOG_I(NR_MAC, "Received UL_SCH_LCID_C_RNTI with C-RNTI 0x%04x, triggering RRC Reconfiguration\n", UE_C->rnti);
                nr_mac_trigger_reconfiguration(RC.nrmac[gnb_mod_idP], UE_C);
811
              }
812 813 814 815 816
            }
            else {
              LOG_I(NR_MAC, "Activating scheduling RA-Msg4 for TC_RNTI 0x%04x (state %d)\n",
                    ra->rnti, ra->state);
              ra->state = Msg4;
817
            }
Eurecom's avatar
Eurecom committed
818 819
          }
          else {
820
            nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra);
Eurecom's avatar
Eurecom committed
821
          }
822
        }
823
        return;
824
      }
825 826 827 828 829 830
    }
  } else {
    for (int i = 0; i < NR_NB_RA_PROC_MAX; ++i) {
      NR_RA_t *ra = &gNB_mac->common_channels[CC_idP].ra[i];
      if (ra->state != WAIT_Msg3)
        continue;
831

832 833 834
      if( (frameP!=ra->Msg3_frame) || (slotP!=ra->Msg3_slot))
        continue;

835 836
      // for CFRA (NSA) do not schedule retransmission of msg3
      if (ra->cfra) {
837
        LOG_D(NR_MAC, "Random Access %i failed at state %i (NSA msg3 reception failed)\n", i, ra->state);
838 839 840 841
        nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra);
        return;
      }

842 843
      if (ra->msg3_round >= gNB_mac->ul_bler.harq_round_max - 1) {
        LOG_W(NR_MAC, "Random Access %i failed at state %i (Reached msg3 max harq rounds)\n", i, ra->state);
844 845 846 847
        nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra);
        return;
      }

848
      LOG_D(NR_MAC, "Random Access %i Msg3 CRC did not pass)\n", i);
Laurent THOMAS's avatar
Laurent THOMAS committed
849

850
      ra->msg3_round++;
851
      ra->state = Msg3_retransmission;
852
    }
853
  }
854 855
}

856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872
void nr_rx_sdu(const module_id_t gnb_mod_idP,
               const int CC_idP,
               const frame_t frameP,
               const sub_frame_t slotP,
               const rnti_t rntiP,
               uint8_t *sduP,
               const uint16_t sdu_lenP,
               const uint16_t timing_advance,
               const uint8_t ul_cqi,
               const uint16_t rssi)
{
  gNB_MAC_INST *gNB_mac = RC.nrmac[gnb_mod_idP];
  NR_SCHED_LOCK(&gNB_mac->sched_lock);
  _nr_rx_sdu(gnb_mod_idP, CC_idP, frameP, slotP, rntiP, sduP, sdu_lenP, timing_advance, ul_cqi, rssi);
  NR_SCHED_UNLOCK(&gNB_mac->sched_lock);
}

873 874
static uint32_t calc_power_complex(const int16_t *x, const int16_t *y, const uint32_t size)
{
875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895
  // Real part value
  int64_t sum_x = 0;
  int64_t sum_x2 = 0;
  for(int k = 0; k<size; k++) {
    sum_x = sum_x + x[k];
    sum_x2 = sum_x2 + x[k]*x[k];
  }
  uint32_t power_re = sum_x2/size - (sum_x/size)*(sum_x/size);

  // Imaginary part power
  int64_t sum_y = 0;
  int64_t sum_y2 = 0;
  for(int k = 0; k<size; k++) {
    sum_y = sum_y + y[k];
    sum_y2 = sum_y2 + y[k]*y[k];
  }
  uint32_t power_im = sum_y2/size - (sum_y/size)*(sum_y/size);

  return power_re+power_im;
}

896 897
static c16_t nr_h_times_w(c16_t h, char w)
{
898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925
  c16_t output;
    switch (w) {
      case '0': // 0
        output.r = 0;
        output.i = 0;
        break;
      case '1': // 1
        output.r = h.r;
        output.i = h.i;
        break;
      case 'n': // -1
        output.r = -h.r;
        output.i = -h.i;
        break;
      case 'j': // j
        output.r = -h.i;
        output.i = h.r;
        break;
      case 'o': // -j
        output.r = h.i;
        output.i = -h.r;
        break;
      default:
        AssertFatal(1==0,"Invalid precoder value %c\n", w);
    }
  return output;
}

926 927 928 929 930
static uint8_t get_max_tpmi(const NR_PUSCH_Config_t *pusch_Config,
                            const uint16_t num_ue_srs_ports,
                            const uint8_t *nrOfLayers,
                            int *additional_max_tpmi)
{
931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088
  uint8_t max_tpmi = 0;

  if ((pusch_Config && pusch_Config->txConfig != NULL && *pusch_Config->txConfig == NR_PUSCH_Config__txConfig_nonCodebook) ||
      num_ue_srs_ports == 1) {
    return max_tpmi;
  }

  long max_rank = *pusch_Config->maxRank;
  long *ul_FullPowerTransmission = pusch_Config->ext1 ? pusch_Config->ext1->ul_FullPowerTransmission_r16 : NULL;
  long *codebookSubset = pusch_Config->codebookSubset;

  if (num_ue_srs_ports == 2) {

    if (max_rank == 1) {
      if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) {
        max_tpmi = 2;
      } else {
        if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
          max_tpmi = 1;
        } else {
          max_tpmi = 5;
        }
      }
    } else {
      if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) {
        max_tpmi = *nrOfLayers == 1 ? 2 : 0;
      } else {
        if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
          max_tpmi = *nrOfLayers == 1 ? 1 : 0;
        } else {
          max_tpmi = *nrOfLayers == 1 ? 5 : 2;
        }
      }
    }

  } else if (num_ue_srs_ports == 4) {

    if (max_rank == 1) {
      if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) {
        if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
          max_tpmi = 3;
          *additional_max_tpmi = 13;
        } else {
          max_tpmi = 15;
        }
      } else {
        if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
          max_tpmi = 3;
        } else if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent) {
          max_tpmi = 11;
        } else {
          max_tpmi = 27;
        }
      }
    } else {
      if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) {
        if (max_rank == 2) {
          if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
            max_tpmi = *nrOfLayers == 1 ? 3 : 6;
            if (*nrOfLayers == 1) {
              *additional_max_tpmi = 13;
            }
          } else {
            max_tpmi = *nrOfLayers == 1 ? 15 : 13;
          }
        } else {
          if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
            switch (*nrOfLayers) {
              case 1:
                max_tpmi = 3;
                *additional_max_tpmi = 13;
                break;
              case 2:
                max_tpmi = 6;
                break;
              case 3:
                max_tpmi = 1;
                break;
              case 4:
                max_tpmi = 0;
                break;
              default:
                LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers);
            }
          } else {
            switch (*nrOfLayers) {
              case 1:
                max_tpmi = 15;
                break;
              case 2:
                max_tpmi = 13;
                break;
              case 3:
              case 4:
                max_tpmi = 2;
                break;
              default:
                LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers);
            }
          }
        }
      } else {
        if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) {
          switch (*nrOfLayers) {
            case 1:
              max_tpmi = 3;
              break;
            case 2:
              max_tpmi = 5;
              break;
            case 3:
            case 4:
              max_tpmi = 0;
              break;
            default:
              LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers);
          }
        } else if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent) {
          switch (*nrOfLayers) {
            case 1:
              max_tpmi = 11;
              break;
            case 2:
              max_tpmi = 13;
              break;
            case 3:
            case 4:
              max_tpmi = 2;
              break;
            default:
              LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers);
          }
        } else {
          switch (*nrOfLayers) {
            case 1:
              max_tpmi = 28;
              break;
            case 2:
              max_tpmi = 22;
              break;
            case 3:
              max_tpmi = 7;
              break;
            case 4:
              max_tpmi = 5;
              break;
            default:
              LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers);
          }
        }
      }
    }

  }

  return max_tpmi;
}

1089 1090 1091 1092 1093 1094 1095
static void get_precoder_matrix_coef(char *w,
                                     const uint8_t ul_ri,
                                     const uint16_t num_ue_srs_ports,
                                     const long transform_precoding,
                                     const uint8_t tpmi,
                                     const uint8_t uI,
                                     int layer_idx)
1096
{
1097 1098
  if (ul_ri == 0) {
    if (num_ue_srs_ports == 2) {
1099
      *w = table_38211_6_3_1_5_1[tpmi][uI][layer_idx];
1100
    } else {
1101
      if (transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled) {
1102
        *w = table_38211_6_3_1_5_2[tpmi][uI][layer_idx];
1103
      } else {
1104
        *w = table_38211_6_3_1_5_3[tpmi][uI][layer_idx];
1105 1106
      }
    }
1107 1108 1109 1110 1111 1112
  } else if (ul_ri == 1) {
    if (num_ue_srs_ports == 2) {
      *w = table_38211_6_3_1_5_4[tpmi][uI][layer_idx];
    } else {
      *w = table_38211_6_3_1_5_5[tpmi][uI][layer_idx];
    }
1113
  } else {
1114
    AssertFatal(1 == 0, "Function get_precoder_matrix_coef() does not support %i layers yet!\n", ul_ri + 1);
1115
  }
1116 1117
}

1118 1119 1120 1121 1122 1123 1124 1125 1126 1127
static int nr_srs_tpmi_estimation(const NR_PUSCH_Config_t *pusch_Config,
                                  const long transform_precoding,
                                  const uint8_t *channel_matrix,
                                  const uint8_t normalized_iq_representation,
                                  const uint16_t num_gnb_antenna_elements,
                                  const uint16_t num_ue_srs_ports,
                                  const uint16_t prg_size,
                                  const uint16_t num_prgs,
                                  const uint8_t ul_ri)
{
1128 1129 1130 1131
  if (ul_ri > 1) {
    LOG_D(NR_MAC, "TPMI computation for ul_ri %i is not implemented yet!\n", ul_ri);
    return 0;
  }
1132 1133

  uint8_t tpmi_sel = 0;
1134 1135 1136 1137
  const uint8_t nrOfLayers = ul_ri + 1;
  int16_t precoded_channel_matrix_re[num_prgs * num_gnb_antenna_elements];
  int16_t precoded_channel_matrix_im[num_prgs * num_gnb_antenna_elements];
  c16_t *channel_matrix16 = (c16_t *)channel_matrix;
1138 1139 1140 1141
  uint32_t max_precoded_signal_power = 0;
  int additional_max_tpmi = -1;
  char w;

1142
  uint8_t max_tpmi = get_max_tpmi(pusch_Config, num_ue_srs_ports, &nrOfLayers, &additional_max_tpmi);
1143 1144 1145 1146 1147 1148 1149 1150
  uint8_t end_tpmi_loop = additional_max_tpmi > max_tpmi ? additional_max_tpmi : max_tpmi;

  //                      channel_matrix                          x   precoder_matrix
  // [ (gI=0,uI=0) (gI=0,uI=1) ... (gI=0,uI=num_ue_srs_ports-1) ] x   [uI=0]
  // [ (gI=1,uI=0) (gI=1,uI=1) ... (gI=1,uI=num_ue_srs_ports-1) ]     [uI=1]
  // [ (gI=2,uI=0) (gI=2,uI=1) ... (gI=2,uI=num_ue_srs_ports-1) ]     [uI=2]
  //                           ...                                     ...

1151
  for (uint8_t tpmi = 0; tpmi <= end_tpmi_loop && end_tpmi_loop > 0; tpmi++) {
1152 1153 1154 1155
    if (tpmi > max_tpmi) {
      tpmi = end_tpmi_loop;
    }

1156 1157 1158
    for (int pI = 0; pI < num_prgs; pI++) {
      for (int gI = 0; gI < num_gnb_antenna_elements; gI++) {
        uint16_t index_gI_pI = gI * num_prgs + pI;
1159 1160 1161
        precoded_channel_matrix_re[index_gI_pI] = 0;
        precoded_channel_matrix_im[index_gI_pI] = 0;

1162 1163 1164 1165 1166
        for (int uI = 0; uI < num_ue_srs_ports; uI++) {
          for (int layer_idx = 0; layer_idx < nrOfLayers; layer_idx++) {
            uint16_t index = uI * num_gnb_antenna_elements * num_prgs + index_gI_pI;
            get_precoder_matrix_coef(&w, ul_ri, num_ue_srs_ports, transform_precoding, tpmi, uI, layer_idx);
            c16_t h_times_w = nr_h_times_w(channel_matrix16[index], w);
1167

1168 1169
            precoded_channel_matrix_re[index_gI_pI] += h_times_w.r;
            precoded_channel_matrix_im[index_gI_pI] += h_times_w.i;
1170 1171

#ifdef SRS_IND_DEBUG
1172 1173
            LOG_I(NR_MAC, "(pI %i, gI %i,  uI %i, layer_idx %i) w = %c, channel_matrix --> real %i, imag %i\n",
                  pI, gI, uI, layer_idx, w, channel_matrix16[index].r, channel_matrix16[index].i);
1174
#endif
1175
          }
1176 1177 1178
        }

#ifdef SRS_IND_DEBUG
1179 1180
        LOG_I(NR_MAC, "(pI %i, gI %i) precoded_channel_coef --> real %i, imag %i\n",
              pI, gI, precoded_channel_matrix_re[index_gI_pI], precoded_channel_matrix_im[index_gI_pI]);
1181 1182 1183 1184 1185 1186
#endif
      }
    }

    uint32_t precoded_signal_power = calc_power_complex(precoded_channel_matrix_re,
                                                        precoded_channel_matrix_im,
1187
                                                        num_prgs * num_gnb_antenna_elements);
1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201

#ifdef SRS_IND_DEBUG
    LOG_I(NR_MAC, "(tpmi %i) precoded_signal_power = %i\n", tpmi, precoded_signal_power);
#endif

    if (precoded_signal_power > max_precoded_signal_power) {
      max_precoded_signal_power = precoded_signal_power;
      tpmi_sel = tpmi;
    }
  }

  return tpmi_sel;
}

1202 1203 1204
void handle_nr_srs_measurements(const module_id_t module_id,
                                const frame_t frame,
                                const sub_frame_t slot,
1205
                                nfapi_nr_srs_indication_pdu_t *srs_ind)
luis_pereira87's avatar
luis_pereira87 committed
1206
{
1207 1208
  gNB_MAC_INST *nrmac = RC.nrmac[module_id];
  NR_SCHED_LOCK(&nrmac->sched_lock);
1209
  LOG_D(NR_MAC, "(%d.%d) Received SRS indication for UE %04x\n", frame, slot, srs_ind->rnti);
1210 1211 1212 1213

#ifdef SRS_IND_DEBUG
  LOG_I(NR_MAC, "frame = %i\n", frame);
  LOG_I(NR_MAC, "slot = %i\n", slot);
1214 1215 1216 1217 1218 1219 1220
  LOG_I(NR_MAC, "srs_ind->rnti = %04x\n", srs_ind->rnti);
  LOG_I(NR_MAC, "srs_ind->timing_advance_offset = %i\n", srs_ind->timing_advance_offset);
  LOG_I(NR_MAC, "srs_ind->timing_advance_offset_nsec = %i\n", srs_ind->timing_advance_offset_nsec);
  LOG_I(NR_MAC, "srs_ind->srs_usage = %i\n", srs_ind->srs_usage);
  LOG_I(NR_MAC, "srs_ind->report_type = %i\n", srs_ind->report_type);
#endif

1221
  NR_UE_info_t *UE = find_nr_UE(&RC.nrmac[module_id]->UE_info, srs_ind->rnti);
Roberto Louro Magueta's avatar
Roberto Louro Magueta committed
1222
  if (!UE) {
1223
    LOG_W(NR_MAC, "Could not find UE for RNTI %04x\n", srs_ind->rnti);
1224
    NR_SCHED_UNLOCK(&nrmac->sched_lock);
luis_pereira87's avatar
luis_pereira87 committed
1225 1226 1227
    return;
  }

1228 1229
  if (srs_ind->timing_advance_offset == 0xFFFF) {
    LOG_W(NR_MAC, "Invalid timing advance offset for RNTI %04x\n", srs_ind->rnti);
1230
    NR_SCHED_UNLOCK(&nrmac->sched_lock);
1231 1232 1233
    return;
  }

1234 1235
  gNB_MAC_INST *nr_mac = RC.nrmac[module_id];
  NR_mac_stats_t *stats = &UE->mac_stats;
1236
  nfapi_srs_report_tlv_t *report_tlv = &srs_ind->report_tlv;
1237

1238 1239
  switch (srs_ind->srs_usage) {
    case NR_SRS_ResourceSet__usage_beamManagement: {
1240
      nfapi_nr_srs_beamforming_report_t nr_srs_bf_report;
1241 1242
      unpack_nr_srs_beamforming_report(report_tlv->value,
                                       report_tlv->length,
1243
                                       &nr_srs_bf_report,
1244 1245
                                       sizeof(nfapi_nr_srs_beamforming_report_t));

1246
      if (nr_srs_bf_report.wide_band_snr == 0xFF) {
1247
        LOG_W(NR_MAC, "Invalid wide_band_snr for RNTI %04x\n", srs_ind->rnti);
1248
        NR_SCHED_UNLOCK(&nrmac->sched_lock);
1249 1250 1251
        return;
      }

1252
      int wide_band_snr_dB = (nr_srs_bf_report.wide_band_snr >> 1) - 64;
1253

1254
#ifdef SRS_IND_DEBUG
1255 1256 1257 1258 1259 1260
      LOG_I(NR_MAC, "nr_srs_bf_report.prg_size = %i\n", nr_srs_bf_report.prg_size);
      LOG_I(NR_MAC, "nr_srs_bf_report.num_symbols = %i\n", nr_srs_bf_report.num_symbols);
      LOG_I(NR_MAC, "nr_srs_bf_report.wide_band_snr = %i (%i dB)\n", nr_srs_bf_report.wide_band_snr, wide_band_snr_dB);
      LOG_I(NR_MAC, "nr_srs_bf_report.num_reported_symbols = %i\n", nr_srs_bf_report.num_reported_symbols);
      LOG_I(NR_MAC, "nr_srs_bf_report.prgs[0].num_prgs = %i\n", nr_srs_bf_report.prgs[0].num_prgs);
      for (int prg_idx = 0; prg_idx < nr_srs_bf_report.prgs[0].num_prgs; prg_idx++) {
1261
        LOG_I(NR_MAC,
1262
              "nr_srs_bf_report.prgs[0].prg_list[%3i].rb_snr = %i (%i dB)\n",
1263
              prg_idx,
1264 1265
              nr_srs_bf_report.prgs[0].prg_list[prg_idx].rb_snr,
              (nr_srs_bf_report.prgs[0].prg_list[prg_idx].rb_snr >> 1) - 64);
1266 1267 1268
      }
#endif

1269
      sprintf(stats->srs_stats, "UL-SNR %i dB", wide_band_snr_dB);
1270

1271
      const int ul_prbblack_SNR_threshold = nr_mac->ul_prbblack_SNR_threshold;
1272
      uint16_t *ulprbbl = nr_mac->ulprbbl;
1273

1274
      uint16_t num_rbs = nr_srs_bf_report.prg_size * nr_srs_bf_report.prgs.num_prgs;
1275
      memset(ulprbbl, 0, num_rbs * sizeof(uint16_t));
1276
      for (int rb = 0; rb < num_rbs; rb++) {
1277
        int snr = (nr_srs_bf_report.prgs.prg_list[rb / nr_srs_bf_report.prg_size].rb_snr >> 1) - 64;
1278
        if (snr < wide_band_snr_dB - ul_prbblack_SNR_threshold) {
1279 1280 1281 1282
          ulprbbl[rb] = 0x3FFF; // all symbols taken
        }
        LOG_D(NR_MAC, "ulprbbl[%3i] = 0x%x\n", rb, ulprbbl[rb]);
      }
1283

1284
      break;
1285
    }
1286 1287

    case NR_SRS_ResourceSet__usage_codebook: {
1288
      nfapi_nr_srs_normalized_channel_iq_matrix_t nr_srs_channel_iq_matrix;
1289 1290
      unpack_nr_srs_normalized_channel_iq_matrix(report_tlv->value,
                                                 report_tlv->length,
1291
                                                 &nr_srs_channel_iq_matrix,
1292 1293 1294
                                                 sizeof(nfapi_nr_srs_normalized_channel_iq_matrix_t));

#ifdef SRS_IND_DEBUG
1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305
      LOG_I(NR_MAC, "nr_srs_channel_iq_matrix.normalized_iq_representation = %i\n", nr_srs_channel_iq_matrix.normalized_iq_representation);
      LOG_I(NR_MAC, "nr_srs_channel_iq_matrix.num_gnb_antenna_elements = %i\n", nr_srs_channel_iq_matrix.num_gnb_antenna_elements);
      LOG_I(NR_MAC, "nr_srs_channel_iq_matrix.num_ue_srs_ports = %i\n", nr_srs_channel_iq_matrix.num_ue_srs_ports);
      LOG_I(NR_MAC, "nr_srs_channel_iq_matrix.prg_size = %i\n", nr_srs_channel_iq_matrix.prg_size);
      LOG_I(NR_MAC, "nr_srs_channel_iq_matrix.num_prgs = %i\n", nr_srs_channel_iq_matrix.num_prgs);
      c16_t *channel_matrix16 = (c16_t *)nr_srs_channel_iq_matrix.channel_matrix;
      c8_t *channel_matrix8 = (c8_t *)nr_srs_channel_iq_matrix.channel_matrix;
      for (int uI = 0; uI < nr_srs_channel_iq_matrix.num_ue_srs_ports; uI++) {
        for (int gI = 0; gI < nr_srs_channel_iq_matrix.num_gnb_antenna_elements; gI++) {
          for (int pI = 0; pI < nr_srs_channel_iq_matrix.num_prgs; pI++) {
            uint16_t index = uI * nr_srs_channel_iq_matrix.num_gnb_antenna_elements * nr_srs_channel_iq_matrix.num_prgs + gI * nr_srs_channel_iq_matrix.num_prgs + pI;
1306 1307 1308 1309 1310
            LOG_I(NR_MAC,
                  "(uI %i, gI %i, pI %i) channel_matrix --> real %i, imag %i\n",
                  uI,
                  gI,
                  pI,
1311 1312
                  nr_srs_channel_iq_matrix.normalized_iq_representation == 0 ? channel_matrix8[index].r : channel_matrix16[index].r,
                  nr_srs_channel_iq_matrix.normalized_iq_representation == 0 ? channel_matrix8[index].i : channel_matrix16[index].i);
1313 1314 1315 1316 1317
          }
        }
      }
#endif

1318
      NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
1319
      NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP;
1320
      sched_ctrl->srs_feedback.sri = NR_SRS_SRI_0;
1321

1322
      start_meas(&nr_mac->nr_srs_ri_computation_timer);
1323
      nr_srs_ri_computation(&nr_srs_channel_iq_matrix, current_BWP, &sched_ctrl->srs_feedback.ul_ri);
1324
      stop_meas(&nr_mac->nr_srs_ri_computation_timer);
1325

1326
      start_meas(&nr_mac->nr_srs_tpmi_computation_timer);
1327 1328
      sched_ctrl->srs_feedback.tpmi = nr_srs_tpmi_estimation(current_BWP->pusch_Config,
                                                             current_BWP->transform_precoding,
1329 1330 1331 1332 1333 1334
                                                             nr_srs_channel_iq_matrix.channel_matrix,
                                                             nr_srs_channel_iq_matrix.normalized_iq_representation,
                                                             nr_srs_channel_iq_matrix.num_gnb_antenna_elements,
                                                             nr_srs_channel_iq_matrix.num_ue_srs_ports,
                                                             nr_srs_channel_iq_matrix.prg_size,
                                                             nr_srs_channel_iq_matrix.num_prgs,
1335
                                                             sched_ctrl->srs_feedback.ul_ri);
1336
      stop_meas(&nr_mac->nr_srs_tpmi_computation_timer);
1337

1338
      sprintf(stats->srs_stats, "UL-RI %d, TPMI %d", sched_ctrl->srs_feedback.ul_ri + 1, sched_ctrl->srs_feedback.tpmi);
1339

1340 1341 1342 1343 1344 1345 1346 1347 1348
      break;
    }

    case NR_SRS_ResourceSet__usage_nonCodebook:
    case NR_SRS_ResourceSet__usage_antennaSwitching:
      LOG_W(NR_MAC, "MAC procedures for this SRS usage are not implemented yet!\n");
      break;

    default:
1349
      AssertFatal(1 == 0, "Invalid SRS usage\n");
1350
  }
1351
  NR_SCHED_UNLOCK(&nrmac->sched_lock);
1352 1353
}

1354
long get_K2(NR_PUSCH_TimeDomainResourceAllocationList_t *tdaList,
1355 1356 1357
            int time_domain_assignment,
            int mu) {

1358
  /* we assume that this function is mutex-protected from outside */
1359
  NR_PUSCH_TimeDomainResourceAllocation_t *tda = tdaList->list.array[time_domain_assignment];
1360

1361 1362
  if (tda->k2)
    return *tda->k2;
1363 1364 1365 1366 1367 1368 1369 1370
  else if (mu < 2)
    return 1;
  else if (mu == 2)
    return 2;
  else
    return 3;
}

1371
static bool nr_UE_is_to_be_scheduled(const NR_ServingCellConfigCommon_t *scc, int CC_id,  NR_UE_info_t* UE, frame_t frame, sub_frame_t slot, uint32_t ulsch_max_frame_inactivity)
1372
{
1373
  const int n = nr_slots_per_frame[*scc->ssbSubcarrierSpacing];
1374 1375
  const int now = frame * n + slot;

Laurent THOMAS's avatar
Laurent THOMAS committed
1376 1377
  const NR_UE_sched_ctrl_t *sched_ctrl =&UE->UE_sched_ctrl;

1378 1379 1380
  const NR_TDD_UL_DL_Pattern_t *tdd =
      scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL;
  int num_slots_per_period;
Laurent THOMAS's avatar
Laurent THOMAS committed
1381
  int last_ul_slot;
1382
  if (tdd) { // Force the default transmission in a full slot as early as possible in the UL portion of TDD period (last_ul_slot)
1383 1384
    num_slots_per_period =  n / get_nb_periods_per_frame(tdd->dl_UL_TransmissionPeriodicity);
    last_ul_slot = 1 + tdd->nrofDownlinkSlots;
1385
  } else {
1386
    num_slots_per_period = n;
1387
    last_ul_slot = sched_ctrl->last_ul_slot;
1388
  }
1389

Laurent THOMAS's avatar
Laurent THOMAS committed
1390
  const int last_ul_sched = sched_ctrl->last_ul_frame * n + last_ul_slot;
1391 1392 1393 1394 1395 1396
  const int diff = (now - last_ul_sched + 1024 * n) % (1024 * n);
  /* UE is to be scheduled if
   * (1) we think the UE has more bytes awaiting than what we scheduled
   * (2) there is a scheduling request
   * (3) or we did not schedule it in more than 10 frames */
  const bool has_data = sched_ctrl->estimated_ul_buffer > sched_ctrl->sched_ul_bytes;
Laurent THOMAS's avatar
Laurent THOMAS committed
1397
  const bool high_inactivity = diff >= (ulsch_max_frame_inactivity > 0 ? ulsch_max_frame_inactivity * n : num_slots_per_period);
1398
  LOG_D(NR_MAC,
1399 1400 1401 1402 1403 1404 1405 1406 1407
        "%4d.%2d UL inactivity %d slots has_data %d SR %d\n",
        frame,
        slot,
        diff,
        has_data,
        sched_ctrl->SR);
  return has_data || sched_ctrl->SR || high_inactivity;
}

1408
static void update_ul_ue_R_Qm(int mcs, int mcs_table, const NR_PUSCH_Config_t *pusch_Config, uint16_t *R, uint8_t *Qm)
1409
{
1410 1411
  *R = nr_get_code_rate_ul(mcs, mcs_table);
  *Qm = nr_get_Qm_ul(mcs, mcs_table);
1412

1413
  if (pusch_Config && pusch_Config->tp_pi2BPSK && ((mcs_table == 3 && mcs < 2) || (mcs_table == 4 && mcs < 6))) {
1414 1415 1416 1417 1418
    *R >>= 1;
    *Qm <<= 1;
  }
}

1419 1420 1421 1422 1423 1424 1425 1426
static void nr_ue_max_mcs_min_rb(int mu,
                                 int ph_limit,
                                 NR_sched_pusch_t *sched_pusch,
                                 NR_UE_UL_BWP_t *ul_bwp,
                                 uint16_t minRb,
                                 uint32_t tbs,
                                 uint16_t *Rb,
                                 uint8_t *mcs)
1427
{
francescomani's avatar
francescomani committed
1428
  AssertFatal(*Rb >= minRb, "illegal Rb %d < minRb %d\n", *Rb, minRb);
1429 1430
  AssertFatal(*mcs >= 0 && *mcs <= 28, "illegal MCS %d\n", *mcs);

1431
  int tbs_bits = tbs << 3;
1432 1433
  uint16_t R;
  uint8_t Qm;
1434
  update_ul_ue_R_Qm(*mcs, ul_bwp->mcs_table, ul_bwp->pusch_Config, &R, &Qm);
1435

1436
  long *deltaMCS = ul_bwp->pusch_Config ? ul_bwp->pusch_Config->pusch_PowerControl->deltaMCS : NULL;
francescomani's avatar
francescomani committed
1437 1438 1439 1440 1441 1442 1443
  int tx_power = compute_ph_factor(mu,
                                   tbs_bits,
                                   *Rb,
                                   sched_pusch->nrOfLayers,
                                   sched_pusch->tda_info.nrOfSymbols,
                                   sched_pusch->dmrs_info.N_PRB_DMRS*sched_pusch->dmrs_info.num_dmrs_symb,
                                   deltaMCS);
francescomani's avatar
francescomani committed
1444

1445
  while (ph_limit < tx_power && *Rb > minRb) {
francescomani's avatar
francescomani committed
1446
    (*Rb)--;
1447 1448 1449 1450 1451 1452
    tbs_bits = nr_compute_tbs(Qm, R, *Rb,
                              sched_pusch->tda_info.nrOfSymbols,
                              sched_pusch->dmrs_info.N_PRB_DMRS * sched_pusch->dmrs_info.num_dmrs_symb,
                              0, // nb_rb_oh
                              0,
                              sched_pusch->nrOfLayers);
francescomani's avatar
francescomani committed
1453 1454 1455 1456 1457 1458 1459
    tx_power = compute_ph_factor(mu,
                                 tbs_bits,
                                 *Rb,
                                 sched_pusch->nrOfLayers,
                                 sched_pusch->tda_info.nrOfSymbols,
                                 sched_pusch->dmrs_info.N_PRB_DMRS*sched_pusch->dmrs_info.num_dmrs_symb,
                                 deltaMCS);
1460 1461
  }

1462
  while (ph_limit < tx_power && *mcs > 0) {
1463
    (*mcs)--;
1464
    update_ul_ue_R_Qm(*mcs, ul_bwp->mcs_table, ul_bwp->pusch_Config, &R, &Qm);
1465 1466 1467 1468 1469 1470
    tbs_bits = nr_compute_tbs(Qm, R, *Rb,
                              sched_pusch->tda_info.nrOfSymbols,
                              sched_pusch->dmrs_info.N_PRB_DMRS * sched_pusch->dmrs_info.num_dmrs_symb,
                              0, // nb_rb_oh
                              0,
                              sched_pusch->nrOfLayers);
francescomani's avatar
francescomani committed
1471 1472 1473 1474 1475 1476 1477
    tx_power = compute_ph_factor(mu,
                                 tbs_bits,
                                 *Rb,
                                 sched_pusch->nrOfLayers,
                                 sched_pusch->tda_info.nrOfSymbols,
                                 sched_pusch->dmrs_info.N_PRB_DMRS*sched_pusch->dmrs_info.num_dmrs_symb,
                                 deltaMCS);
1478 1479
  }

francescomani's avatar
francescomani committed
1480 1481 1482
  if (ph_limit < tx_power)
    LOG_W(NR_MAC, "Normalized power %d based on current resources (RBs %d, MCS %d) exceed reported PHR %d (normalized value)\n",
          tx_power, *Rb, *mcs, ph_limit);
1483 1484
}

Laurent THOMAS's avatar
Laurent THOMAS committed
1485 1486 1487 1488 1489 1490 1491 1492 1493
static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac,
				       frame_t frame,
				       sub_frame_t slot,
				       uint16_t *rballoc_mask,
				       int *n_rb_sched,
				       NR_UE_info_t* UE,
				       int harq_pid,
				       const NR_ServingCellConfigCommon_t *scc,
				       const int tda)
1494 1495
{
  const int CC_id = 0;
Laurent THOMAS's avatar
Laurent THOMAS committed
1496
  NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
1497
  NR_sched_pusch_t *retInfo = &sched_ctrl->ul_harq_processes[harq_pid].sched_pusch;
1498
  NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP;
1499

1500
  int rbStart = 0; // wrt BWP start
1501
  const uint16_t bwpSize = ul_bwp->BWPSize;
1502
  const uint8_t nrOfLayers = retInfo->nrOfLayers;
1503
  LOG_D(NR_MAC,"retInfo->time_domain_allocation = %d, tda = %d\n", retInfo->time_domain_allocation, tda);
francescomani's avatar
francescomani committed
1504
  LOG_D(NR_MAC,"tbs %d\n",retInfo->tb_size);
1505
  NR_tda_info_t tda_info = get_ul_tda_info(ul_bwp, sched_ctrl->coreset->controlResourceSetId, sched_ctrl->search_space->searchSpaceType->present, NR_RNTI_C, tda);
1506 1507
  bool reuse_old_tda = (retInfo->tda_info.startSymbolIndex == tda_info.startSymbolIndex) && (retInfo->tda_info.nrOfSymbols <= tda_info.nrOfSymbols);
  if (reuse_old_tda && nrOfLayers == retInfo->nrOfLayers) {
1508
    /* Check the resource is enough for retransmission */
francescomani's avatar
francescomani committed
1509
    const uint16_t slbitmap = SL_to_bitmap(retInfo->tda_info.startSymbolIndex, retInfo->tda_info.nrOfSymbols);
1510
    while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap)
1511 1512
      rbStart++;
    if (rbStart + retInfo->rbSize > bwpSize) {
1513
      LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not allocate UL retransmission: no resources (rbStart %d, retInfo->rbSize %d, bwpSize %d) \n",
1514 1515 1516 1517 1518 1519
            UE->rnti,
            frame,
            slot,
            rbStart,
            retInfo->rbSize,
            bwpSize);
1520 1521
      return false;
    }
1522
    LOG_D(NR_MAC, "%s(): retransmission keeping TDA %d and TBS %d\n", __func__, tda, retInfo->tb_size);
1523
  } else {
francescomani's avatar
francescomani committed
1524
    NR_pusch_dmrs_t dmrs_info = get_ul_dmrs_params(scc,
1525
                                                   ul_bwp,
francescomani's avatar
francescomani committed
1526 1527
                                                   &tda_info,
                                                   nrOfLayers);
1528 1529
    /* the retransmission will use a different time domain allocation, check
     * that we have enough resources */
francescomani's avatar
francescomani committed
1530
    const uint16_t slbitmap = SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols);
1531
    while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap)
1532 1533
      rbStart++;
    int rbSize = 0;
1534
    while (rbStart + rbSize < bwpSize && (rballoc_mask[rbStart + rbSize] & slbitmap) == slbitmap)
1535 1536 1537 1538 1539
      rbSize++;
    uint32_t new_tbs;
    uint16_t new_rbSize;
    bool success = nr_find_nb_rb(retInfo->Qm,
                                 retInfo->R,
1540
                                 UE->current_UL_BWP.transform_precoding,
1541
                                 nrOfLayers,
francescomani's avatar
francescomani committed
1542 1543
                                 tda_info.nrOfSymbols,
                                 dmrs_info.N_PRB_DMRS * dmrs_info.num_dmrs_symb,
1544
                                 retInfo->tb_size,
1545
                                 1, /* minimum of 1RB: need to find exact TBS, don't preclude any number */
1546 1547 1548 1549
                                 rbSize,
                                 &new_tbs,
                                 &new_rbSize);
    if (!success || new_tbs != retInfo->tb_size) {
1550 1551 1552 1553 1554 1555
      LOG_D(NR_MAC, "[UE %04x][%4d.%2d] allocation of UL retransmission failed: new TBsize %d of new TDA does not match old TBS %d \n",
            UE->rnti,
            frame,
            slot,
            new_tbs,
            retInfo->tb_size);
1556 1557
      return false; /* the maximum TBsize we might have is smaller than what we need */
    }
1558
    LOG_D(NR_MAC, "%s(): retransmission with TDA %d->%d and TBS %d -> %d\n", __func__, retInfo->time_domain_allocation, tda, retInfo->tb_size, new_tbs);
1559 1560 1561 1562 1563
    /* we can allocate it. Overwrite the time_domain_allocation, the number
     * of RBs, and the new TB size. The rest is done below */
    retInfo->tb_size = new_tbs;
    retInfo->rbSize = new_rbSize;
    retInfo->time_domain_allocation = tda;
francescomani's avatar
francescomani committed
1564 1565
    retInfo->dmrs_info = dmrs_info;
    retInfo->tda_info = tda_info;
1566 1567
  }

1568
  /* Find a free CCE */
1569 1570 1571 1572 1573 1574 1575
  int CCEIndex = get_cce_index(nrmac,
                               CC_id, slot, UE->rnti,
                               &sched_ctrl->aggregation_level,
                               sched_ctrl->search_space,
                               sched_ctrl->coreset,
                               &sched_ctrl->sched_pdcch,
                               false);
1576
  if (CCEIndex<0) {
1577 1578 1579 1580
    LOG_D(NR_MAC, "[UE %04x][%4d.%2d] no free CCE for retransmission UL DCI UE\n",
          UE->rnti,
          frame,
          slot);
1581 1582 1583
    return false;
  }

1584
  sched_ctrl->cce_index = CCEIndex;
Laurent THOMAS's avatar
Laurent THOMAS committed
1585
  fill_pdcch_vrb_map(nrmac,
1586
                     CC_id,
1587
                     &sched_ctrl->sched_pdcch,
1588 1589 1590
                     CCEIndex,
                     sched_ctrl->aggregation_level);

1591 1592 1593 1594 1595 1596 1597 1598 1599
  /* frame/slot in sched_pusch has been set previously. In the following, we
   * overwrite the information in the retransmission information before storing
   * as the new scheduling instruction */
  retInfo->frame = sched_ctrl->sched_pusch.frame;
  retInfo->slot = sched_ctrl->sched_pusch.slot;
  /* Get previous PSUCH field info */
  sched_ctrl->sched_pusch = *retInfo;
  NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch;

1600
  LOG_D(NR_MAC,
Laurent THOMAS's avatar
Laurent THOMAS committed
1601
        "%4d.%2d Allocate UL retransmission RNTI %04x sched %4d.%2d (%d RBs)\n",
1602 1603
        frame,
        slot,
Laurent THOMAS's avatar
Laurent THOMAS committed
1604
        UE->rnti,
1605 1606 1607 1608 1609 1610 1611 1612 1613 1614
        sched_pusch->frame,
        sched_pusch->slot,
        sched_pusch->rbSize);

  sched_pusch->rbStart = rbStart;
  /* no need to recompute the TBS, it will be the same */

  /* Mark the corresponding RBs as used */
  n_rb_sched -= sched_pusch->rbSize;
  for (int rb = 0; rb < sched_ctrl->sched_pusch.rbSize; rb++)
francescomani's avatar
francescomani committed
1615
    rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] ^= SL_to_bitmap(sched_pusch->tda_info.startSymbolIndex, sched_pusch->tda_info.nrOfSymbols);
1616 1617 1618
  return true;
}

Laurent THOMAS's avatar
Laurent THOMAS committed
1619
uint32_t ul_pf_tbs[3][29]; // pre-computed, approximate TBS values for PF coefficient
Laurent THOMAS's avatar
Laurent THOMAS committed
1620 1621 1622 1623 1624 1625 1626 1627 1628
typedef struct UEsched_s {
  float coef;
  NR_UE_info_t * UE;
} UEsched_t;

static int comparator(const void *p, const void *q) {
  return ((UEsched_t*)p)->coef < ((UEsched_t*)q)->coef;
}

1629 1630 1631 1632 1633 1634 1635
static void pf_ul(module_id_t module_id,
                  frame_t frame,
                  sub_frame_t slot,
                  NR_UE_info_t *UE_list[],
                  int max_num_ue,
                  int n_rb_sched,
                  uint16_t *rballoc_mask)
1636
{
ChiehChun's avatar
ChiehChun committed
1637 1638

  const int CC_id = 0;
1639 1640
  gNB_MAC_INST *nrmac = RC.nrmac[module_id];
  NR_ServingCellConfigCommon_t *scc = nrmac->common_channels[CC_id].ServingCellConfigCommon;
Laurent THOMAS's avatar
Laurent THOMAS committed
1641 1642
  
  const int min_rb = 5;
1643
  // UEs that could be scheduled
Laurent THOMAS's avatar
Laurent THOMAS committed
1644
  UEsched_t UE_sched[MAX_MOBILES_PER_GNB] = {0};
1645
  int remainUEs = max_num_ue;
Laurent THOMAS's avatar
Laurent THOMAS committed
1646
  int curUE=0;
ChiehChun's avatar
ChiehChun committed
1647 1648

  /* Loop UE_list to calculate throughput and coeff */
Laurent THOMAS's avatar
Laurent THOMAS committed
1649
  UE_iterator(UE_list, UE) {
1650

1651
    NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
1652
    if (UE->Msg4_ACKed != true || sched_ctrl->ul_failure)
Laurent THOMAS's avatar
Laurent THOMAS committed
1653
      continue;
1654

Laurent THOMAS's avatar
Laurent THOMAS committed
1655
    LOG_D(NR_MAC,"pf_ul: preparing UL scheduling for UE %04x\n",UE->rnti);
francescomani's avatar
francescomani committed
1656
    NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP;
1657

1658
    int rbStart = 0; // wrt BWP start
Eurecom's avatar
Eurecom committed
1659

francescomani's avatar
francescomani committed
1660
    const uint16_t bwpSize = current_BWP->BWPSize;
1661
    NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch;
Laurent THOMAS's avatar
Laurent THOMAS committed
1662
    const NR_mac_dir_stats_t *stats = &UE->mac_stats.ul;
ChiehChun's avatar
ChiehChun committed
1663 1664

    /* Calculate throughput */
1665
    const float a = 0.01f;
Robert Schmidt's avatar
Robert Schmidt committed
1666
    const uint32_t b = stats->current_bytes;
Laurent THOMAS's avatar
Laurent THOMAS committed
1667
    UE->ul_thr_ue = (1 - a) * UE->ul_thr_ue + a * b;
ChiehChun's avatar
ChiehChun committed
1668

1669 1670 1671
    if(remainUEs == 0)
      continue;

1672
    /* Check if retransmission is necessary */
1673
    sched_pusch->ul_harq_pid = sched_ctrl->retrans_ul_harq.head;
Laurent THOMAS's avatar
Laurent THOMAS committed
1674
    LOG_D(NR_MAC,"pf_ul: UE %04x harq_pid %d\n",UE->rnti,sched_pusch->ul_harq_pid);
1675 1676
    if (sched_pusch->ul_harq_pid >= 0) {
      /* Allocate retransmission*/
francescomani's avatar
francescomani committed
1677
      const int tda = get_ul_tda(nrmac, scc, sched_pusch->frame, sched_pusch->slot);
1678
      bool r = allocate_ul_retransmission(nrmac, frame, slot, rballoc_mask, &n_rb_sched, UE, sched_pusch->ul_harq_pid, scc, tda);
1679
      if (!r) {
1680 1681 1682 1683
        LOG_D(NR_MAC, "[UE %04x][%4d.%2d] UL retransmission could not be allocated\n",
              UE->rnti,
              frame,
              slot);
1684 1685
        continue;
      }
Laurent THOMAS's avatar
Laurent THOMAS committed
1686
      else LOG_D(NR_MAC,"%4d.%2d UL Retransmission UE RNTI %04x to be allocated, max_num_ue %d\n",frame,slot,UE->rnti,max_num_ue);
1687

1688
      /* reduce max_num_ue once we are sure UE can be allocated, i.e., has CCE */
Laurent THOMAS's avatar
Laurent THOMAS committed
1689 1690 1691
      remainUEs--;
      continue;
    } 
1692 1693 1694 1695 1696

    /* skip this UE if there are no free HARQ processes. This can happen e.g.
     * if the UE disconnected in L2sim, in which case the gNB is not notified
     * (this can be considered a design flaw) */
    if (sched_ctrl->available_ul_harq.head < 0) {
1697 1698 1699 1700
      LOG_D(NR_MAC, "[UE %04x][%4d.%2d] has no free UL HARQ process, skipping\n",
            UE->rnti,
            frame,
            slot);
1701 1702 1703
      continue;
    }

1704 1705
    const int B = max(0, sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes);
    /* preprocessor computed sched_frame/sched_slot */
Laurent THOMAS's avatar
Laurent THOMAS committed
1706
    const bool do_sched = nr_UE_is_to_be_scheduled(scc, 0, UE, sched_pusch->frame, sched_pusch->slot, nrmac->ulsch_max_frame_inactivity);
1707

Laurent THOMAS's avatar
Laurent THOMAS committed
1708
    LOG_D(NR_MAC,"pf_ul: do_sched UE %04x => %s\n",UE->rnti,do_sched ? "yes" : "no");
1709
    if ((B == 0 && !do_sched) || (sched_ctrl->rrc_processing_timer > 0)) {
Robert Schmidt's avatar
Robert Schmidt committed
1710
      continue;
1711
    }
Robert Schmidt's avatar
Robert Schmidt committed
1712

Robert Schmidt's avatar
Robert Schmidt committed
1713
    const NR_bler_options_t *bo = &nrmac->ul_bler;
1714 1715
    const int max_mcs_table = (current_BWP->mcs_table == 0 || current_BWP->mcs_table == 2) ? 28 : 27;
    const int max_mcs = min(bo->max_mcs, max_mcs_table); /* no per-user maximum MCS yet */
1716 1717 1718
    if (bo->harq_round_max == 1)
      sched_pusch->mcs = max_mcs;
    else
1719
      sched_pusch->mcs = get_mcs_from_bler(bo, stats, &sched_ctrl->ul_bler_stats, max_mcs, frame);
Robert Schmidt's avatar
Robert Schmidt committed
1720

1721 1722 1723
    /* Schedule UE on SR or UL inactivity and no data (otherwise, will be scheduled
     * based on data to transmit) */
    if (B == 0 && do_sched) {
1724
      /* if no data, pre-allocate 5RB */
1725
      /* Find a free CCE */
1726 1727 1728 1729 1730 1731 1732
      int CCEIndex = get_cce_index(nrmac,
                                   CC_id, slot, UE->rnti,
                                   &sched_ctrl->aggregation_level,
                                   sched_ctrl->search_space,
                                   sched_ctrl->coreset,
                                   &sched_ctrl->sched_pdcch,
                                   false);
1733
      if (CCEIndex<0) {
1734 1735 1736 1737
        LOG_D(NR_MAC, "[UE %04x][%4d.%2d] no free CCE for UL DCI (BSR 0)\n",
              UE->rnti,
              frame,
              slot);
1738 1739
        continue;
      }
1740

1741
      sched_pusch->nrOfLayers = sched_ctrl->srs_feedback.ul_ri + 1;
francescomani's avatar
francescomani committed
1742
      sched_pusch->time_domain_allocation = get_ul_tda(nrmac, scc, sched_pusch->frame, sched_pusch->slot);
1743
      sched_pusch->tda_info = get_ul_tda_info(current_BWP, sched_ctrl->coreset->controlResourceSetId, sched_ctrl->search_space->searchSpaceType->present, NR_RNTI_C, sched_pusch->time_domain_allocation);
francescomani's avatar
francescomani committed
1744 1745 1746 1747
      sched_pusch->dmrs_info = get_ul_dmrs_params(scc,
                                                  current_BWP,
                                                  &sched_pusch->tda_info,
                                                  sched_pusch->nrOfLayers);
1748

1749
      LOG_D(NR_MAC,"Looking for min_rb %d RBs, starting at %d num_dmrs_cdm_grps_no_data %d\n",
francescomani's avatar
francescomani committed
1750 1751
            min_rb, rbStart, sched_pusch->dmrs_info.num_dmrs_cdm_grps_no_data);
      const uint16_t slbitmap = SL_to_bitmap(sched_pusch->tda_info.startSymbolIndex, sched_pusch->tda_info.nrOfSymbols);
1752
      while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap)
1753 1754
        rbStart++;
      if (rbStart + min_rb >= bwpSize) {
1755
        LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not allocate continuous UL data: no resources (rbStart %d, min_rb %d, bwpSize %d)\n",
1756 1757 1758 1759 1760 1761
              UE->rnti,
              frame,
              slot,
              rbStart,
              min_rb,
              bwpSize);
1762
        continue;
1763 1764
      }

francescomani's avatar
francescomani committed
1765
      sched_ctrl->cce_index = CCEIndex;
1766
      fill_pdcch_vrb_map(nrmac,
francescomani's avatar
francescomani committed
1767 1768 1769 1770 1771
                         CC_id,
                         &sched_ctrl->sched_pdcch,
                         CCEIndex,
                         sched_ctrl->aggregation_level);

1772
      NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch;
Robert Schmidt's avatar
Robert Schmidt committed
1773
      sched_pusch->mcs = min(nrmac->min_grant_mcs, sched_pusch->mcs);
1774
      update_ul_ue_R_Qm(sched_pusch->mcs, current_BWP->mcs_table, current_BWP->pusch_Config, &sched_pusch->R, &sched_pusch->Qm);
1775 1776 1777 1778 1779
      sched_pusch->rbStart = rbStart;
      sched_pusch->rbSize = min_rb;
      sched_pusch->tb_size = nr_compute_tbs(sched_pusch->Qm,
                                            sched_pusch->R,
                                            sched_pusch->rbSize,
francescomani's avatar
francescomani committed
1780 1781
                                            sched_pusch->tda_info.nrOfSymbols,
                                            sched_pusch->dmrs_info.N_PRB_DMRS * sched_pusch->dmrs_info.num_dmrs_symb,
1782 1783
                                            0, // nb_rb_oh
                                            0,
1784
                                            sched_pusch->nrOfLayers) >> 3;
1785 1786 1787 1788

      /* Mark the corresponding RBs as used */
      n_rb_sched -= sched_pusch->rbSize;
      for (int rb = 0; rb < sched_ctrl->sched_pusch.rbSize; rb++)
1789
        rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] ^= slbitmap;
1790

1791
      remainUEs--;
1792
      continue;
1793
    }
1794 1795

    /* Create UE_sched for UEs eligibale for new data transmission*/
Robert Schmidt's avatar
Robert Schmidt committed
1796
    /* Calculate coefficient*/
francescomani's avatar
francescomani committed
1797
    const uint32_t tbs = ul_pf_tbs[current_BWP->mcs_table][sched_pusch->mcs];
Laurent THOMAS's avatar
Laurent THOMAS committed
1798
    float coeff_ue = (float) tbs / UE->ul_thr_ue;
1799 1800 1801 1802 1803 1804 1805 1806
    LOG_D(NR_MAC, "[UE %04x][%4d.%2d] b %d, ul_thr_ue %f, tbs %d, coeff_ue %f\n",
          UE->rnti,
          frame,
          slot,
          b,
          UE->ul_thr_ue,
          tbs,
          coeff_ue);
Laurent THOMAS's avatar
Laurent THOMAS committed
1807 1808 1809
    UE_sched[curUE].coef=coeff_ue;
    UE_sched[curUE].UE=UE;
    curUE++;
1810 1811
  }

Guido's avatar
Guido committed
1812
  qsort(UE_sched, sizeofArray(UE_sched), sizeof(UEsched_t), comparator);
Laurent THOMAS's avatar
Laurent THOMAS committed
1813
  UEsched_t *iterator=UE_sched;
1814

Robert Schmidt's avatar
Robert Schmidt committed
1815
  /* Loop UE_sched to find max coeff and allocate transmission */
1816
  while (remainUEs> 0 && n_rb_sched >= min_rb && iterator->UE != NULL) {
Robert Schmidt's avatar
Robert Schmidt committed
1817

Laurent THOMAS's avatar
Laurent THOMAS committed
1818
    NR_UE_sched_ctrl_t *sched_ctrl = &iterator->UE->UE_sched_ctrl;
1819 1820 1821 1822 1823 1824 1825
    int CCEIndex = get_cce_index(nrmac,
                                 CC_id, slot, iterator->UE->rnti,
                                 &sched_ctrl->aggregation_level,
                                 sched_ctrl->search_space,
                                 sched_ctrl->coreset,
                                 &sched_ctrl->sched_pdcch,
                                 false);
1826 1827

    if (CCEIndex<0) {
1828 1829 1830 1831
      LOG_D(NR_MAC, "[UE %04x][%4d.%2d] no free CCE for UL DCI\n",
            iterator->UE->rnti,
            frame,
            slot);
Laurent THOMAS's avatar
Laurent THOMAS committed
1832
      iterator++;
1833 1834
      continue;
    }
Laurent THOMAS's avatar
Laurent THOMAS committed
1835
    else LOG_D(NR_MAC, "%4d.%2d free CCE for UL DCI UE %04x\n",frame,slot, iterator->UE->rnti);
Robert Schmidt's avatar
Robert Schmidt committed
1836

francescomani's avatar
francescomani committed
1837
    NR_UE_UL_BWP_t *current_BWP = &iterator->UE->current_UL_BWP;
1838

Robert Schmidt's avatar
Robert Schmidt committed
1839
    NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch;
francescomani's avatar
francescomani committed
1840

1841
    sched_pusch->nrOfLayers = sched_ctrl->srs_feedback.ul_ri + 1;
francescomani's avatar
francescomani committed
1842
    sched_pusch->time_domain_allocation = get_ul_tda(nrmac, scc, sched_pusch->frame, sched_pusch->slot);
1843
    sched_pusch->tda_info = get_ul_tda_info(current_BWP, sched_ctrl->coreset->controlResourceSetId, sched_ctrl->search_space->searchSpaceType->present, NR_RNTI_C, sched_pusch->time_domain_allocation);
francescomani's avatar
francescomani committed
1844 1845 1846 1847
    sched_pusch->dmrs_info = get_ul_dmrs_params(scc,
                                                current_BWP,
                                                &sched_pusch->tda_info,
                                                sched_pusch->nrOfLayers);
1848

francescomani's avatar
francescomani committed
1849
    int rbStart = 0;
francescomani's avatar
francescomani committed
1850
    const uint16_t slbitmap = SL_to_bitmap(sched_pusch->tda_info.startSymbolIndex, sched_pusch->tda_info.nrOfSymbols);
1851
    const uint16_t bwpSize = current_BWP->BWPSize;
1852
    while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap)
1853 1854 1855
      rbStart++;
    sched_pusch->rbStart = rbStart;
    uint16_t max_rbSize = 1;
1856
    while (rbStart + max_rbSize < bwpSize && (rballoc_mask[rbStart + max_rbSize] & slbitmap) == slbitmap)
1857 1858
      max_rbSize++;

1859
    if (rbStart + min_rb >= bwpSize || max_rbSize < min_rb) {
1860 1861 1862 1863 1864 1865 1866
      LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not allocate UL data: no resources (rbStart %d, min_rb %d, bwpSize %d)\n",
            iterator->UE->rnti,
            frame,
            slot,
            rbStart,
            min_rb,
            bwpSize);
1867
      iterator++;
1868
      continue;
1869 1870
    } else
      LOG_D(NR_MAC, "allocating UL data for RNTI %04x (rbStart %d, min_rb %d, max_rbSize %d, bwpSize %d)\n", iterator->UE->rnti, rbStart, min_rb, max_rbSize, bwpSize);
1871

1872
    /* Calculate the current scheduling bytes */
ChiehChun's avatar
ChiehChun committed
1873
    const int B = cmax(sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes, 0);
francescomani's avatar
francescomani committed
1874
    /* adjust rbSize and MCS according to PHR and BPRE */
francescomani's avatar
francescomani committed
1875 1876
    if(sched_ctrl->pcmax!=0 ||
       sched_ctrl->ph!=0) // verify if the PHR related parameter have been initialized
1877
      nr_ue_max_mcs_min_rb(current_BWP->scs, sched_ctrl->ph, sched_pusch, current_BWP, min_rb, B, &max_rbSize, &sched_pusch->mcs);
1878 1879 1880

    if (sched_pusch->mcs < sched_ctrl->ul_bler_stats.mcs)
      sched_ctrl->ul_bler_stats.mcs = sched_pusch->mcs; /* force estimated MCS down */
1881

1882
    update_ul_ue_R_Qm(sched_pusch->mcs, current_BWP->mcs_table, current_BWP->pusch_Config, &sched_pusch->R, &sched_pusch->Qm);
1883 1884 1885 1886
    uint16_t rbSize = 0;
    uint32_t TBS = 0;
    nr_find_nb_rb(sched_pusch->Qm,
                  sched_pusch->R,
1887
                  current_BWP->transform_precoding,
1888
                  sched_pusch->nrOfLayers,
francescomani's avatar
francescomani committed
1889 1890
                  sched_pusch->tda_info.nrOfSymbols,
                  sched_pusch->dmrs_info.N_PRB_DMRS * sched_pusch->dmrs_info.num_dmrs_symb,
1891
                  B,
1892
                  min_rb,
1893 1894 1895
                  max_rbSize,
                  &TBS,
                  &rbSize);
francescomani's avatar
francescomani committed
1896

1897 1898
    sched_pusch->rbSize = rbSize;
    sched_pusch->tb_size = TBS;
1899
    LOG_D(NR_MAC,"rbSize %d (max_rbSize %d), TBS %d, est buf %d, sched_ul %d, B %d, CCE %d, num_dmrs_symb %d, N_PRB_DMRS %d\n",
francescomani's avatar
francescomani committed
1900 1901
          rbSize, max_rbSize,sched_pusch->tb_size, sched_ctrl->estimated_ul_buffer, sched_ctrl->sched_ul_bytes, B,
          sched_ctrl->cce_index,sched_pusch->dmrs_info.num_dmrs_symb,sched_pusch->dmrs_info.N_PRB_DMRS);
ChiehChun's avatar
ChiehChun committed
1902 1903

    /* Mark the corresponding RBs as used */
1904 1905

    sched_ctrl->cce_index = CCEIndex;
1906
    fill_pdcch_vrb_map(nrmac,
1907
                       CC_id,
1908
                       &sched_ctrl->sched_pdcch,
1909 1910 1911
                       CCEIndex,
                       sched_ctrl->aggregation_level);

1912
    n_rb_sched -= sched_pusch->rbSize;
ChiehChun's avatar
ChiehChun committed
1913
    for (int rb = 0; rb < sched_ctrl->sched_pusch.rbSize; rb++)
1914
      rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] ^= slbitmap;
1915

Laurent THOMAS's avatar
Laurent THOMAS committed
1916 1917 1918
    /* reduce max_num_ue once we are sure UE can be allocated, i.e., has CCE */
    remainUEs--;
    iterator++;
1919 1920 1921
  }
}

1922
static bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t slot)
1923
{
1924 1925 1926
  gNB_MAC_INST *nr_mac = RC.nrmac[module_id];
  NR_COMMON_channels_t *cc = nr_mac->common_channels;
  NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
1927 1928
  const NR_SIB1_t *sib1 = nr_mac->common_channels[0].sib1 ? nr_mac->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL;
  NR_ServingCellConfigCommonSIB_t *scc_sib1 = sib1 ? sib1->servingCellConfigCommon : NULL;
1929 1930 1931

  AssertFatal(scc!=NULL || scc_sib1!=NULL,"We need one serving cell config common\n");

1932
  // no UEs
Laurent THOMAS's avatar
Laurent THOMAS committed
1933
  if (nr_mac->UE_info.list[0] == NULL)
1934
    return false;
1935 1936 1937

  const int CC_id = 0;

1938 1939 1940 1941
  /* Get the K2 for first UE to compute offset. The other UEs are guaranteed to
   * have the same K2 (we don't support multiple/different K2s via different
   * TDAs yet). If the TDA is negative, it means that there is no UL slot to
   * schedule now (slot + k2 is not UL slot) */
Laurent THOMAS's avatar
Laurent THOMAS committed
1942
  NR_UE_sched_ctrl_t *sched_ctrl = &nr_mac->UE_info.list[0]->UE_sched_ctrl;
francescomani's avatar
francescomani committed
1943 1944
  NR_UE_UL_BWP_t *current_BWP = &nr_mac->UE_info.list[0]->current_UL_BWP;
  int mu = current_BWP->scs;
francescomani's avatar
francescomani committed
1945
  const int temp_tda = get_ul_tda(nr_mac, scc, frame, slot);
1946 1947
  NR_PUSCH_TimeDomainResourceAllocationList_t *tdaList = get_ul_tdalist(current_BWP, sched_ctrl->coreset->controlResourceSetId, sched_ctrl->search_space->searchSpaceType->present, NR_RNTI_C);
  int K2 = get_K2(tdaList, temp_tda, mu);
luis_pereira87's avatar
luis_pereira87 committed
1948
  const int sched_frame = (frame + (slot + K2 >= nr_slots_per_frame[mu])) & 1023;
ChiehChun's avatar
ChiehChun committed
1949
  const int sched_slot = (slot + K2) % nr_slots_per_frame[mu];
francescomani's avatar
francescomani committed
1950
  const int tda = get_ul_tda(nr_mac, scc, sched_frame, sched_slot);
francescomani's avatar
francescomani committed
1951 1952
  if (tda < 0)
    return false;
1953
  DevAssert(K2 == get_K2(tdaList, tda, mu));
1954

1955
  if (!is_xlsch_in_slot(nr_mac->ulsch_slot_bitmap[sched_slot / 64], sched_slot))
1956
    return false;
1957

1958 1959
  sched_ctrl->sched_pusch.slot = sched_slot;
  sched_ctrl->sched_pusch.frame = sched_frame;
Laurent THOMAS's avatar
Laurent THOMAS committed
1960 1961
  UE_iterator(nr_mac->UE_info.list, UE2) {
    NR_UE_sched_ctrl_t *sched_ctrl = &UE2->UE_sched_ctrl;
1962
    AssertFatal(K2 == get_K2(tdaList, tda, mu),
Laurent THOMAS's avatar
Laurent THOMAS committed
1963
                "Different K2, %d(UE%d) != %ld(UE%04x)\n",
1964
		K2, 0, get_K2(tdaList, tda, mu), UE2->rnti);
ChiehChun's avatar
ChiehChun committed
1965 1966
    sched_ctrl->sched_pusch.slot = sched_slot;
    sched_ctrl->sched_pusch.frame = sched_frame;
1967
  }
Robert Schmidt's avatar
Robert Schmidt committed
1968

1969 1970 1971
  /* Change vrb_map_UL to rballoc_mask: check which symbols per RB (in
   * vrb_map_UL) overlap with the "default" tda and exclude those RBs.
   * Calculate largest contiguous RBs */
1972 1973
  const int index = ul_buffer_index(sched_frame, sched_slot, mu, nr_mac->vrb_map_UL_size);
  uint16_t *vrb_map_UL = &nr_mac->common_channels[CC_id].vrb_map_UL[index * MAX_BWP_SIZE];
1974

francescomani's avatar
francescomani committed
1975 1976
  const uint16_t bwpSize = current_BWP->BWPSize;
  const uint16_t bwpStart = current_BWP->BWPStart;
1977

1978
  const int startSymbolAndLength = tdaList->list.array[tda]->startSymbolAndLength;
1979 1980
  int startSymbolIndex, nrOfSymbols;
  SLIV2SL(startSymbolAndLength, &startSymbolIndex, &nrOfSymbols);
1981
  const uint16_t symb = SL_to_bitmap(startSymbolIndex, nrOfSymbols);
1982

1983
  int st = 0, e = 0, len = 0;
1984

1985
  for (int i = 0; i < bwpSize; i++) {
1986
    while ((vrb_map_UL[bwpStart + i] & symb) != 0 && i < bwpSize)
1987 1988
      i++;
    st = i;
1989
    while ((vrb_map_UL[bwpStart + i] & symb) == 0 && i < bwpSize)
1990 1991 1992 1993 1994
      i++;
    if (i - st > len) {
      len = i - st;
      e = i - 1;
    }
1995
  }
1996 1997
  st = e - len + 1;

Raymond Knopp's avatar
Raymond Knopp committed
1998
  LOG_D(NR_MAC,"UL %d.%d : start_prb %d, end PRB %d\n",frame,slot,st,e);
1999
  
2000
  uint16_t rballoc_mask[bwpSize];
2001 2002 2003

  /* Calculate mask: if any RB in vrb_map_UL is blocked (1), the current RB will be 0 */
  for (int i = 0; i < bwpSize; i++)
2004
    rballoc_mask[i] = (i >= st && i <= e)*SL_to_bitmap(startSymbolIndex, nrOfSymbols);
2005

2006 2007 2008 2009
  int bw = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth;
  int average_agg_level = 4; // TODO find a better estimation
  int max_sched_ues = bw / (average_agg_level * NR_NB_REG_PER_CCE);

ChiehChun's avatar
ChiehChun committed
2010 2011 2012 2013
  /* proportional fair scheduling algorithm */
  pf_ul(module_id,
        frame,
        slot,
Laurent THOMAS's avatar
Laurent THOMAS committed
2014
        nr_mac->UE_info.list,
2015
        max_sched_ues,
2016
        len,
2017
        rballoc_mask);
2018
  return true;
2019 2020
}

2021
nr_pp_impl_ul nr_init_fr1_ulsch_preprocessor(int CC_id)
2022
{
2023
  /* during initialization: no mutex needed */
2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035
  /* in the PF algorithm, we have to use the TBsize to compute the coefficient.
   * This would include the number of DMRS symbols, which in turn depends on
   * the time domain allocation. In case we are in a mixed slot, we do not want
   * to recalculate all these values, and therefore we provide a look-up table
   * which should approximately(!) give us the TBsize. In particular, the
   * number of symbols, the number of DMRS symbols, and the exact Qm and R, are
   * not correct*/
  for (int mcsTableIdx = 0; mcsTableIdx < 3; ++mcsTableIdx) {
    for (int mcs = 0; mcs < 29; ++mcs) {
      if (mcs > 27 && mcsTableIdx == 1)
        continue;
      const uint8_t Qm = nr_get_Qm_dl(mcs, mcsTableIdx);
2036
      const uint16_t R = nr_get_code_rate_ul(mcs, mcsTableIdx);
2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051
      /* note: we do not update R/Qm based on low MCS or pi2BPSK */
      ul_pf_tbs[mcsTableIdx][mcs] = nr_compute_tbs(Qm,
                                                   R,
                                                   1, /* rbSize */
                                                   10, /* hypothetical number of slots */
                                                   0, /* N_PRB_DMRS * N_DMRS_SLOT */
                                                   0 /* N_PRB_oh, 0 for initialBWP */,
                                                   0 /* tb_scaling */,
                                                   1 /* nrOfLayers */)
                                    >> 3;
    }
  }
  return nr_fr1_ulsch_preprocessor;
}

2052
void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot, nfapi_nr_ul_dci_request_t *ul_dci_req)
2053 2054
{
  gNB_MAC_INST *nr_mac = RC.nrmac[module_id];
2055 2056 2057
  /* already mutex protected: held in gNB_dlsch_ulsch_scheduler() */
  NR_SCHED_ENSURE_LOCKED(&nr_mac->sched_lock);

2058 2059
  /* Uplink data ONLY can be scheduled when the current slot is downlink slot,
   * because we have to schedule the DCI0 first before schedule uplink data */
2060
  if (!is_xlsch_in_slot(nr_mac->dlsch_slot_bitmap[slot / 64], slot)) {
2061
    LOG_D(NR_MAC, "Current slot %d is NOT DL slot, cannot schedule DCI0 for UL data\n", slot);
2062 2063
    return;
  }
2064
  bool do_sched = nr_mac->pre_processor_ul(module_id, frame, slot);
2065 2066
  if (!do_sched)
    return;
2067

2068 2069 2070 2071 2072
  ul_dci_req->SFN = frame;
  ul_dci_req->Slot = slot;
  /* a PDCCH PDU groups DCIs per BWP and CORESET. Save a pointer to each
   * allocated PDCCH so we can easily allocate UE's DCIs independent of any
   * CORESET order */
2073 2074
  nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_coreset[MAX_NUM_CORESET] = {0};

2075

2076 2077 2078
  NR_ServingCellConfigCommon_t *scc = nr_mac->common_channels[0].ServingCellConfigCommon;
  NR_UEs_t *UE_info = &nr_mac->UE_info;
  const NR_SIB1_t *sib1 = nr_mac->common_channels[0].sib1 ? nr_mac->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL;
Laurent THOMAS's avatar
Laurent THOMAS committed
2079 2080
  UE_iterator( UE_info->list, UE) {
    NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
2081 2082
    if (sched_ctrl->ul_failure && !get_softmodem_params()->phy_test)
      continue;
2083

Laurent THOMAS's avatar
Laurent THOMAS committed
2084
    NR_CellGroupConfig_t *cg = UE->CellGroup;
2085
    NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP;
2086

Laurent THOMAS's avatar
Laurent THOMAS committed
2087
    UE->mac_stats.ul.current_bytes = 0;
Robert Schmidt's avatar
Robert Schmidt committed
2088
    UE->mac_stats.ul.current_rbs = 0;
2089

2090 2091
    /* dynamic PUSCH values (RB alloc, MCS, hence R, Qm, TBS) that change in
     * every TTI are pre-populated by the preprocessor and used below */
Robert Schmidt's avatar
Robert Schmidt committed
2092
    NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch;
Laurent THOMAS's avatar
Laurent THOMAS committed
2093
    LOG_D(NR_MAC,"UE %04x : sched_pusch->rbSize %d\n",UE->rnti,sched_pusch->rbSize);
Robert Schmidt's avatar
Robert Schmidt committed
2094
    if (sched_pusch->rbSize <= 0)
2095 2096
      continue;

Laurent THOMAS's avatar
Laurent THOMAS committed
2097
    uint16_t rnti = UE->rnti;
Robert Schmidt's avatar
Robert Schmidt committed
2098
    sched_ctrl->SR = false;
2099

2100 2101 2102 2103 2104
    int8_t harq_id = sched_pusch->ul_harq_pid;
    if (harq_id < 0) {
      /* PP has not selected a specific HARQ Process, get a new one */
      harq_id = sched_ctrl->available_ul_harq.head;
      AssertFatal(harq_id >= 0,
Laurent THOMAS's avatar
Laurent THOMAS committed
2105 2106
                  "no free HARQ process available for UE %04x\n",
                  UE->rnti);
2107
      remove_front_nr_list(&sched_ctrl->available_ul_harq);
2108
      sched_pusch->ul_harq_pid = harq_id;
2109 2110 2111 2112 2113 2114 2115 2116 2117
    } 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->ul_harq_processes[harq_id].round == 0)
        remove_nr_list(&sched_ctrl->available_ul_harq, harq_id);
      else
        remove_nr_list(&sched_ctrl->retrans_ul_harq, harq_id);
    }
Robert Schmidt's avatar
Robert Schmidt committed
2118
    NR_UE_ul_harq_t *cur_harq = &sched_ctrl->ul_harq_processes[harq_id];
2119 2120 2121 2122
    DevAssert(!cur_harq->is_waiting);
    add_tail_nr_list(&sched_ctrl->feedback_ul_harq, harq_id);
    cur_harq->feedback_slot = sched_pusch->slot;
    cur_harq->is_waiting = true;
Robert Schmidt's avatar
Robert Schmidt committed
2123

Robert Schmidt's avatar
Robert Schmidt committed
2124 2125
    int rnti_types[2] = { NR_RNTI_C, 0 };

2126
    /* Statistics */
2127
    AssertFatal(cur_harq->round < nr_mac->ul_bler.harq_round_max, "Indexing ulsch_rounds[%d] is out of bounds\n", cur_harq->round);
Laurent THOMAS's avatar
Laurent THOMAS committed
2128
    UE->mac_stats.ul.rounds[cur_harq->round]++;
2129
    if (cur_harq->round == 0) {
Laurent THOMAS's avatar
Laurent THOMAS committed
2130
      UE->mac_stats.ulsch_total_bytes_scheduled += sched_pusch->tb_size;
2131 2132 2133
      /* Save information on MCS, TBS etc for the current initial transmission
       * so we have access to it when retransmitting */
      cur_harq->sched_pusch = *sched_pusch;
2134
      /* save which time allocation and nrOfLayers have been used, to be used on
2135
       * retransmissions */
francescomani's avatar
francescomani committed
2136
      cur_harq->sched_pusch.time_domain_allocation = sched_pusch->time_domain_allocation;
2137
      cur_harq->sched_pusch.nrOfLayers = sched_pusch->nrOfLayers;
2138
      sched_ctrl->sched_ul_bytes += sched_pusch->tb_size;
Robert Schmidt's avatar
Robert Schmidt committed
2139 2140
      UE->mac_stats.ul.total_rbs += sched_pusch->rbSize;

2141
    } else {
2142
      LOG_D(NR_MAC,
2143
            "%d.%2d UL retransmission RNTI %04x sched %d.%2d HARQ PID %d round %d NDI %d\n",
2144 2145 2146 2147 2148
            frame,
            slot,
            rnti,
            sched_pusch->frame,
            sched_pusch->slot,
2149 2150 2151
            harq_id,
            cur_harq->round,
            cur_harq->ndi);
Robert Schmidt's avatar
Robert Schmidt committed
2152
      UE->mac_stats.ul.total_rbs_retx += sched_pusch->rbSize;
2153
    }
Laurent THOMAS's avatar
Laurent THOMAS committed
2154
    UE->mac_stats.ul.current_bytes = sched_pusch->tb_size;
Robert Schmidt's avatar
Robert Schmidt committed
2155
    UE->mac_stats.ul.current_rbs = sched_pusch->rbSize;
2156 2157
    sched_ctrl->last_ul_frame = sched_pusch->frame;
    sched_ctrl->last_ul_slot = sched_pusch->slot;
2158

rmagueta's avatar
rmagueta committed
2159
    LOG_D(NR_MAC,
2160
          "ULSCH/PUSCH: %4d.%2d RNTI %04x UL sched %4d.%2d DCI L %d start %2d RBS %3d startSymbol %2d nb_symbol %2d dmrs_pos %x MCS Table %2d MCS %2d nrOfLayers %2d num_dmrs_cdm_grps_no_data %2d TBS %4d HARQ PID %2d round %d RV %d NDI %d est %6d sched %6d est BSR %6d TPC %d\n",
2161 2162 2163 2164 2165
          frame,
          slot,
          rnti,
          sched_pusch->frame,
          sched_pusch->slot,
Eurecom's avatar
Eurecom committed
2166
          sched_ctrl->aggregation_level,
2167 2168
          sched_pusch->rbStart,
          sched_pusch->rbSize,
francescomani's avatar
francescomani committed
2169 2170 2171
          sched_pusch->tda_info.startSymbolIndex,
          sched_pusch->tda_info.nrOfSymbols,
          sched_pusch->dmrs_info.ul_dmrs_symb_pos,
2172
          current_BWP->mcs_table,
2173
          sched_pusch->mcs,
francescomani's avatar
francescomani committed
2174 2175
          sched_pusch->nrOfLayers,
          sched_pusch->dmrs_info.num_dmrs_cdm_grps_no_data,
2176 2177 2178
          sched_pusch->tb_size,
          harq_id,
          cur_harq->round,
2179
          nr_rv_round_map[cur_harq->round%4],
2180 2181 2182
          cur_harq->ndi,
          sched_ctrl->estimated_ul_buffer,
          sched_ctrl->sched_ul_bytes,
2183 2184
          sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes,
          sched_ctrl->tpc0);
2185

2186
    /* PUSCH in a later slot, but corresponding DCI now! */
2187 2188
    const int index = ul_buffer_index(sched_pusch->frame, sched_pusch->slot, current_BWP->scs, nr_mac->UL_tti_req_ahead_size);
    nfapi_nr_ul_tti_request_t *future_ul_tti_req = &nr_mac->UL_tti_req_ahead[0][index];
2189 2190 2191 2192 2193 2194 2195 2196
    if (future_ul_tti_req->SFN != sched_pusch->frame || future_ul_tti_req->Slot != sched_pusch->slot)
      LOG_W(MAC,
            "%d.%d future UL_tti_req's frame.slot %d.%d does not match PUSCH %d.%d\n",
            frame, slot,
            future_ul_tti_req->SFN,
            future_ul_tti_req->Slot,
            sched_pusch->frame,
            sched_pusch->slot);
2197 2198 2199
    AssertFatal(future_ul_tti_req->n_pdus <
                sizeof(future_ul_tti_req->pdus_list) / sizeof(future_ul_tti_req->pdus_list[0]),
                "Invalid future_ul_tti_req->n_pdus %d\n", future_ul_tti_req->n_pdus);
2200

2201 2202 2203 2204 2205 2206
    future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE;
    future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pusch_pdu_t);
    nfapi_nr_pusch_pdu_t *pusch_pdu = &future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pusch_pdu;
    memset(pusch_pdu, 0, sizeof(nfapi_nr_pusch_pdu_t));
    future_ul_tti_req->n_pdus += 1;

2207
    LOG_D(NR_MAC, "%4d.%2d Scheduling UE specific PUSCH for sched %d.%d, ul_tti_req %d.%d\n", frame, slot,
2208
    sched_pusch->frame,sched_pusch->slot,future_ul_tti_req->SFN,future_ul_tti_req->Slot);
2209 2210 2211 2212 2213

    pusch_pdu->pdu_bit_map = PUSCH_PDU_BITMAP_PUSCH_DATA;
    pusch_pdu->rnti = rnti;
    pusch_pdu->handle = 0; //not yet used

2214
    /* FAPI: BWP */
2215

2216 2217 2218
    pusch_pdu->bwp_size  = current_BWP->BWPSize;
    pusch_pdu->bwp_start = current_BWP->BWPStart;
    pusch_pdu->subcarrier_spacing = current_BWP->scs;
2219 2220
    pusch_pdu->cyclic_prefix = 0;

2221
    /* FAPI: PUSCH information always included */
2222 2223 2224
    pusch_pdu->target_code_rate = sched_pusch->R;
    pusch_pdu->qam_mod_order = sched_pusch->Qm;
    pusch_pdu->mcs_index = sched_pusch->mcs;
2225
    pusch_pdu->mcs_table = current_BWP->mcs_table;
2226
    pusch_pdu->transform_precoding = current_BWP->transform_precoding;
2227 2228
    if (current_BWP->pusch_Config && current_BWP->pusch_Config->dataScramblingIdentityPUSCH)
      pusch_pdu->data_scrambling_id = *current_BWP->pusch_Config->dataScramblingIdentityPUSCH;
2229 2230
    else
      pusch_pdu->data_scrambling_id = *scc->physCellId;
francescomani's avatar
francescomani committed
2231 2232
    pusch_pdu->nrOfLayers = sched_pusch->nrOfLayers;
    pusch_pdu->num_dmrs_cdm_grps_no_data = sched_pusch->dmrs_info.num_dmrs_cdm_grps_no_data;
2233

2234
    /* FAPI: DMRS */
francescomani's avatar
francescomani committed
2235 2236
    pusch_pdu->ul_dmrs_symb_pos = sched_pusch->dmrs_info.ul_dmrs_symb_pos;
    pusch_pdu->dmrs_config_type = sched_pusch->dmrs_info.dmrs_config_type;
2237
    const NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig = get_DMRS_UplinkConfig(current_BWP->pusch_Config, &sched_pusch->tda_info);
2238
    if (pusch_pdu->transform_precoding) { // transform precoding disabled
2239
      long *scramblingid=NULL;
francescomani's avatar
francescomani committed
2240 2241 2242 2243
      if (NR_DMRS_UplinkConfig && pusch_pdu->scid == 0)
        scramblingid = NR_DMRS_UplinkConfig->transformPrecodingDisabled->scramblingID0;
      else if (NR_DMRS_UplinkConfig)
        scramblingid = NR_DMRS_UplinkConfig->transformPrecodingDisabled->scramblingID1;
2244 2245 2246 2247 2248 2249 2250
      if (scramblingid == NULL)
        pusch_pdu->ul_dmrs_scrambling_id = *scc->physCellId;
      else
        pusch_pdu->ul_dmrs_scrambling_id = *scramblingid;
    }
    else {
      pusch_pdu->ul_dmrs_scrambling_id = *scc->physCellId;
2251 2252 2253
      if (NR_DMRS_UplinkConfig &&
          NR_DMRS_UplinkConfig->transformPrecodingEnabled &&
          NR_DMRS_UplinkConfig->transformPrecodingEnabled->nPUSCH_Identity != NULL)
francescomani's avatar
francescomani committed
2254 2255
        pusch_pdu->pusch_identity = *NR_DMRS_UplinkConfig->transformPrecodingEnabled->nPUSCH_Identity;
      else if (NR_DMRS_UplinkConfig)
2256 2257
        pusch_pdu->pusch_identity = *scc->physCellId;
    }
2258
    pusch_pdu->scid = 0;      // DMRS sequence initialization [TS38.211, sec 6.4.1.1.1]
francescomani's avatar
francescomani committed
2259
    pusch_pdu->dmrs_ports = ((1<<sched_pusch->nrOfLayers) - 1);
2260

2261 2262 2263 2264 2265
    /* FAPI: Pusch Allocation in frequency domain */
    pusch_pdu->resource_alloc = 1; //type 1
    pusch_pdu->rb_start = sched_pusch->rbStart;
    pusch_pdu->rb_size = sched_pusch->rbSize;
    pusch_pdu->vrb_to_prb_mapping = 0;
2266
    if (current_BWP->pusch_Config==NULL || current_BWP->pusch_Config->frequencyHopping==NULL)
2267 2268 2269 2270 2271
      pusch_pdu->frequency_hopping = 0;
    else
      pusch_pdu->frequency_hopping = 1;

    /* FAPI: Resource Allocation in time domain */
francescomani's avatar
francescomani committed
2272 2273
    pusch_pdu->start_symbol_index = sched_pusch->tda_info.startSymbolIndex;
    pusch_pdu->nr_of_symbols = sched_pusch->tda_info.nrOfSymbols;
2274 2275

    /* PUSCH PDU */
2276
    AssertFatal(cur_harq->round < nr_mac->ul_bler.harq_round_max, "Indexing nr_rv_round_map[%d] is out of bounds\n", cur_harq->round%4);
2277
    pusch_pdu->pusch_data.rv_index = nr_rv_round_map[cur_harq->round%4];
2278
    pusch_pdu->pusch_data.harq_process_id = harq_id;
2279
    pusch_pdu->pusch_data.new_data_indicator = (cur_harq->round == 0) ? 1 : 0;  // not NDI but indicator for new transmission
2280
    pusch_pdu->pusch_data.tb_size = sched_pusch->tb_size;
2281 2282
    pusch_pdu->pusch_data.num_cb = 0; //CBG not supported

2283
    pusch_pdu->maintenance_parms_v3.ldpcBaseGraph = get_BG(sched_pusch->tb_size<<3,sched_pusch->R);
2284 2285 2286 2287 2288 2289 2290
    if(current_BWP->pusch_servingcellconfig &&
       current_BWP->pusch_servingcellconfig->rateMatching) {
      // TBS_LBRM according to section 5.4.2.1 of 38.212
      long *maxMIMO_Layers = current_BWP->pusch_servingcellconfig->ext1->maxMIMO_Layers;
      if (!maxMIMO_Layers)
        maxMIMO_Layers = current_BWP->pusch_Config->maxRank;
      AssertFatal (maxMIMO_Layers != NULL,"Option with max MIMO layers not configured is not supported\n");
2291
      const int scc_bwpsize = current_BWP->initial_BWPSize;
francescomani's avatar
francescomani committed
2292
      int bw_tbslbrm = get_ulbw_tbslbrm(scc_bwpsize, cg);
2293 2294 2295 2296 2297 2298
      pusch_pdu->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(current_BWP->mcs_table,
                                                                           bw_tbslbrm,
                                                                           *maxMIMO_Layers);
    }
    else
     pusch_pdu->maintenance_parms_v3.tbSizeLbrmBytes = 0;
2299

2300
    LOG_D(NR_MAC,"PUSCH PDU : data_scrambling_identity %x, dmrs_scrambling_id %x\n",pusch_pdu->data_scrambling_id,pusch_pdu->ul_dmrs_scrambling_id);
2301 2302 2303 2304 2305 2306 2307 2308
    /* TRANSFORM PRECODING --------------------------------------------------------*/

    if (pusch_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled){

      // U as specified in section 6.4.1.1.1.2 in 38.211, if sequence hopping and group hopping are disabled
      pusch_pdu->dfts_ofdm.low_papr_group_number = pusch_pdu->pusch_identity % 30;

      // V as specified in section 6.4.1.1.1.2 in 38.211 V = 0 if sequence hopping and group hopping are disabled
2309 2310 2311 2312
      if ((!NR_DMRS_UplinkConfig ||
          !NR_DMRS_UplinkConfig->transformPrecodingEnabled ||
          (!NR_DMRS_UplinkConfig->transformPrecodingEnabled->sequenceGroupHopping && !NR_DMRS_UplinkConfig->transformPrecodingEnabled->sequenceHopping)) &&
          !scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->groupHoppingEnabledTransformPrecoding)
2313 2314
        pusch_pdu->dfts_ofdm.low_papr_sequence_number = 0;
      else
2315
        AssertFatal(1==0,"Hopping mode is not supported in transform precoding\n");
2316

2317
      LOG_D(NR_MAC,"TRANSFORM PRECODING IS ENABLED. CDM groups: %d, U: %d MCS table: %d\n", pusch_pdu->num_dmrs_cdm_grps_no_data, pusch_pdu->dfts_ofdm.low_papr_group_number, current_BWP->mcs_table);
2318 2319 2320 2321
    }

    /*-----------------------------------------------------------------------------*/

2322
    /* PUSCH PTRS */
francescomani's avatar
francescomani committed
2323
    if (NR_DMRS_UplinkConfig && NR_DMRS_UplinkConfig->phaseTrackingRS != NULL) {
2324
      bool valid_ptrs_setup = false;
2325
      pusch_pdu->pusch_ptrs.ptrs_ports_list   = (nfapi_nr_ptrs_ports_t *) malloc(2*sizeof(nfapi_nr_ptrs_ports_t));
francescomani's avatar
francescomani committed
2326
      valid_ptrs_setup = set_ul_ptrs_values(NR_DMRS_UplinkConfig->phaseTrackingRS->choice.setup,
2327 2328 2329 2330 2331 2332 2333
                                            pusch_pdu->rb_size, pusch_pdu->mcs_index, pusch_pdu->mcs_table,
                                            &pusch_pdu->pusch_ptrs.ptrs_freq_density,&pusch_pdu->pusch_ptrs.ptrs_time_density,
                                            &pusch_pdu->pusch_ptrs.ptrs_ports_list->ptrs_re_offset,&pusch_pdu->pusch_ptrs.num_ptrs_ports,
                                            &pusch_pdu->pusch_ptrs.ul_ptrs_power, pusch_pdu->nr_of_symbols);
      if (valid_ptrs_setup==true) {
        pusch_pdu->pdu_bit_map |= PUSCH_PDU_BITMAP_PUSCH_PTRS; // enable PUSCH PTRS
      }
2334 2335 2336 2337
    }
    else{
      pusch_pdu->pdu_bit_map &= ~PUSCH_PDU_BITMAP_PUSCH_PTRS; // disable PUSCH PTRS
    }
2338

2339 2340
    /* look up the PDCCH PDU for this BWP and CORESET. If it does not exist,
     * create it */
2341 2342
    NR_SearchSpace_t *ss = sched_ctrl->search_space;
    NR_ControlResourceSet_t *coreset = sched_ctrl->coreset;
2343
    const int coresetid = coreset->controlResourceSetId;
2344
    nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu = pdcch_pdu_coreset[coresetid];
2345 2346 2347 2348 2349 2350 2351
    if (!pdcch_pdu) {
      nfapi_nr_ul_dci_request_pdus_t *ul_dci_request_pdu = &ul_dci_req->ul_dci_pdu_list[ul_dci_req->numPdus];
      memset(ul_dci_request_pdu, 0, sizeof(nfapi_nr_ul_dci_request_pdus_t));
      ul_dci_request_pdu->PDUType = NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE;
      ul_dci_request_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu));
      pdcch_pdu = &ul_dci_request_pdu->pdcch_pdu.pdcch_pdu_rel15;
      ul_dci_req->numPdus += 1;
2352
      nr_configure_pdcch(pdcch_pdu, coreset, false, &sched_ctrl->sched_pdcch);
2353
      pdcch_pdu_coreset[coresetid] = pdcch_pdu;
2354
    }
2355

Laurent THOMAS's avatar
Laurent THOMAS committed
2356
    LOG_D(NR_MAC,"Configuring ULDCI/PDCCH in %d.%d at CCE %d, rnti %04x\n", frame,slot,sched_ctrl->cce_index,rnti);
2357

2358 2359 2360 2361
    /* Fill PDCCH DL DCI PDU */
    nfapi_nr_dl_dci_pdu_t *dci_pdu = &pdcch_pdu->dci_pdu[pdcch_pdu->numDlDci];
    pdcch_pdu->numDlDci++;
    dci_pdu->RNTI = rnti;
2362 2363 2364
    if (coreset->pdcch_DMRS_ScramblingID &&
        ss->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_ue_Specific) {
      dci_pdu->ScramblingId = *coreset->pdcch_DMRS_ScramblingID;
2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376
      dci_pdu->ScramblingRNTI = rnti;
    } else {
      dci_pdu->ScramblingId = *scc->physCellId;
      dci_pdu->ScramblingRNTI = 0;
    }
    dci_pdu->AggregationLevel = sched_ctrl->aggregation_level;
    dci_pdu->CceIndex = sched_ctrl->cce_index;
    dci_pdu->beta_PDCCH_1_0 = 0;
    dci_pdu->powerControlOffsetSS = 1;

    dci_pdu_rel15_t uldci_payload;
    memset(&uldci_payload, 0, sizeof(uldci_payload));
2377

2378
    config_uldci(sib1,
2379
                 scc,
2380
                 pusch_pdu,
2381
                 &uldci_payload,
2382
                 &sched_ctrl->srs_feedback,
francescomani's avatar
francescomani committed
2383
                 sched_pusch->time_domain_allocation,
Laurent THOMAS's avatar
Laurent THOMAS committed
2384
                 UE->UE_sched_ctrl.tpc0,
2385
                 cur_harq->ndi,
2386
                 current_BWP);
2387

2388
    fill_dci_pdu_rel15(scc,
2389
                       cg,
2390
                       &UE->current_DL_BWP,
2391
                       current_BWP,
2392 2393
                       dci_pdu,
                       &uldci_payload,
2394
                       current_BWP->dci_format,
2395
                       rnti_types[0],
2396
                       current_BWP->bwp_id,
2397
                       ss,
2398
                       coreset,
2399
                       nr_mac->cset0_bwp_size);
2400

Robert Schmidt's avatar
Robert Schmidt committed
2401
    memset(sched_pusch, 0, sizeof(*sched_pusch));
2402
  }
2403
}