gNB_scheduler_ulsch.c 93.6 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 37
#include <openair2/UTIL/OPT/opt.h>

38
#include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h"
39

40 41
//#define SRS_IND_DEBUG

francescomani's avatar
francescomani committed
42
const int get_ul_tda(const gNB_MAC_INST *nrmac, const NR_ServingCellConfigCommon_t *scc, int slot) {
43 44

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

48 49
  if (tdd && tdd->nrofUplinkSymbols > 1) { // if there is uplink symbols in mixed slot
    const int nr_slots_period = tdd->nrofDownlinkSlots + tdd->nrofUplinkSlots + 1;
francescomani's avatar
francescomani committed
50
    if ((slot%nr_slots_period) == tdd->nrofDownlinkSlots)
51
      return 1;
52
  }
53
  return 0; // if FDD or not mixed slot in TDD, for now use default TDA (TODO handle CSI-RS slots)
54 55
}

francescomani's avatar
francescomani committed
56 57 58 59 60 61 62
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
63 64 65

  // 38.213 7.1.1
  // if the PUSCH transmission is over more than one layer delta_tf = 0
francescomani's avatar
francescomani committed
66 67 68
  int delta_tf = 0;
  if(deltaMCS != NULL && n_layers == 1) {
    const int n_re = (NR_NB_SC_PER_RB * n_symbols - n_dmrs) * rb;
69 70
    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
71 72 73 74 75
    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
76

francescomani's avatar
francescomani committed
77
  return (delta_tf + bw_factor);
francescomani's avatar
francescomani committed
78 79
}

80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
//  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.

104 105 106 107 108 109
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,
francescomani's avatar
francescomani committed
110 111
                       int pdu_len,
                       const int8_t harq_pid)
112
{
cig's avatar
cig committed
113

114
  uint8_t done = 0;
115
  int sdus = 0;
116
  NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP;
117
  NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
cig's avatar
cig committed
118

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

122 123 124 125
#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
126

127 128 129 130
  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
131

132
    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
133

134 135
    unsigned char *ce_ptr;
    int n_Lcg = 0;
136

137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
    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
154 155 156 157 158
        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;
        }
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
        /* 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 */
182 183
        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);
184
          return 0;
185
        }
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
        /* 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
213

214
        break;
215

216
      case UL_SCH_LCID_C_RNTI:
217

218 219 220 221 222 223 224
        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) {
            ra->crnti = ((pduP[1]&0xFF)<<8)|(pduP[2]&0xFF);
            ra->msg3_dcch_dtch = true;
            LOG_I(NR_MAC, "Received UL_SCH_LCID_C_RNTI with C-RNTI 0x%04x\n", ra->crnti);
            break;
225
          }
226
        }
227

228 229 230 231 232
        //38.321 section 6.1.3.2
        //fixed length
        mac_len = 2;
        /* Extract CRNTI value */
        break;
233

234
      case UL_SCH_LCID_SINGLE_ENTRY_PHR:
235 236 237 238 239
        if (harq_pid < 0) {
          LOG_E(NR_MAC, "Invalid HARQ PID %d\n", harq_pid);
          done = 1;
          break;
        }
francescomani's avatar
francescomani committed
240
        NR_sched_pusch_t *sched_pusch = &sched_ctrl->ul_harq_processes[harq_pid].sched_pusch;;
241 242 243 244 245 246 247
        //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
248
        int PH;
249 250
        const int PCMAX = phr->PCMAX;
        /* 38.133 Table10.1.17.1-1 */
francescomani's avatar
francescomani committed
251 252
        if (phr->PH < 55)
          PH = phr->PH - 32;
253
        else
francescomani's avatar
francescomani committed
254 255
          PH = phr->PH - 32 + (phr->PH - 54);
        // in sched_ctrl we set normalized PH wrt MCS and PRBs
256
        long *deltaMCS = ul_bwp->pusch_Config ? ul_bwp->pusch_Config->pusch_PowerControl->deltaMCS : NULL;
francescomani's avatar
francescomani committed
257
        sched_ctrl->ph = PH +
francescomani's avatar
francescomani committed
258 259 260 261 262 263 264
                         compute_ph_factor(sched_pusch->mu,
                                           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);
265 266
        /* 38.133 Table10.1.18.1-1 */
        sched_ctrl->pcmax = PCMAX - 29;
francescomani's avatar
francescomani committed
267
        LOG_D(NR_MAC, "SINGLE ENTRY PHR R1 %d PH %d (%d dB) R2 %d PCMAX %d (%d dBm)\n",
268 269
              phr->R1, PH, sched_ctrl->ph, phr->R2, PCMAX, sched_ctrl->pcmax);
        break;
270

271
      case UL_SCH_LCID_MULTI_ENTRY_PHR_1_OCT:
272 273
        LOG_E(NR_MAC, "Multi entry PHR not supported\n");
        done = 1;
274
        //38.321 section 6.1.3.9
275
        //  variable length
276 277 278 279
        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;
280

281
      case UL_SCH_LCID_MULTI_ENTRY_PHR_4_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 four octets bitmap for PHR calculation */
        break;
290

291 292 293 294
      case UL_SCH_LCID_PADDING:
        done = 1;
        //  end of MAC PDU, can ignore the rest.
        break;
295

296 297
      case UL_SCH_LCID_SRB1:
      case UL_SCH_LCID_SRB2:
298 299
        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);
300
          return 0;
301
        }
302

303 304 305 306 307 308 309 310 311 312
        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);
313
              break;
314 315
            }
          }
316
        }
317

318 319
        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);
320
          mac_rlc_data_ind(module_idP,
321
                           crnti,
322 323 324 325 326
                           module_idP,
                           frameP,
                           ENB_FLAG_YES,
                           MBMS_FLAG_NO,
                           rx_lcid,
327
                           (char *) (pduP + mac_subheader_len),
328
                           mac_len,
329 330
                           1,
                           NULL);
331 332
        } 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
333
        }
334
        break;
335

336 337 338 339
      case UL_SCH_LCID_CCCH:
      case UL_SCH_LCID_CCCH1:
        // fixed length
        mac_subheader_len = 1;
Laurent THOMAS's avatar
Laurent THOMAS committed
340

341 342 343
        if ( rx_lcid == UL_SCH_LCID_CCCH1 ) {
          // RRCResumeRequest1 message includes the full I-RNTI and has a size of 8 bytes
          mac_len = 8;
344

345
          // Check if it is a valid CCCH1 message, we get all 00's messages very often
Melissa Elkadi's avatar
Melissa Elkadi committed
346 347 348 349 350
          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;
        }
351 352 353 354 355 356 357 358 359
          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;
360
            break;
361
          }
362
        } else {
363 364
          // fixed length of 6 bytes
          mac_len = 6;
365 366
        }

367 368 369 370 371 372
        send_initial_ul_rrc_message(module_idP,
                                    CC_id,
                                    UE,
                                    CCCH,
                                    pduP + mac_subheader_len,
                                    mac_len);
373
        break;
cig's avatar
cig committed
374

375 376
      case UL_SCH_LCID_DTCH ... (UL_SCH_LCID_DTCH + 28):
        //  check if LCID is valid at current time.
377 378
        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
379
          return 0;
380
        }
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403

        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);

404
        sdus += 1;
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
        /* 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
442 443 444

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

Eurecom's avatar
Eurecom committed
445
  return 0;
446
}
447

448
void abort_nr_ul_harq(NR_UE_info_t *UE, int8_t harq_pid)
449
{
Laurent THOMAS's avatar
Laurent THOMAS committed
450
  NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
451 452 453 454
  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
455
  UE->mac_stats.ul.errors++;
456 457 458 459 460 461 462 463 464
  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;
}

465 466
void handle_nr_ul_harq(const int CC_idP,
                       module_id_t mod_id,
467 468 469 470
                       frame_t frame,
                       sub_frame_t slot,
                       const nfapi_nr_crc_t *crc_pdu)
{
Laurent THOMAS's avatar
Laurent THOMAS committed
471 472 473
  NR_UE_info_t* UE = find_nr_UE(&RC.nrmac[mod_id]->UE_info, crc_pdu->rnti);
  if (!UE) {
    LOG_W(NR_MAC, "handle harq for rnti %04x, in RA process\n", crc_pdu->rnti);
474
    for (int i = 0; i < NR_NB_RA_PROC_MAX; ++i) {
Laurent THOMAS's avatar
Laurent THOMAS committed
475
      NR_RA_t *ra = &RC.nrmac[mod_id]->common_channels[CC_idP].ra[i];
476 477 478 479
      if (ra->state >= WAIT_Msg3 &&
          ra->rnti == crc_pdu->rnti)
        return;
    }
480
    LOG_E(NR_MAC, "%s(): unknown RNTI 0x%04x in PUSCH\n", __func__, crc_pdu->rnti);
481 482
    return;
  }
Laurent THOMAS's avatar
Laurent THOMAS committed
483
  NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
484
  int8_t harq_pid = sched_ctrl->feedback_ul_harq.head;
485
  LOG_D(NR_MAC, "Comparing crc_pdu->harq_id vs feedback harq_pid = %d %d\n",crc_pdu->harq_id, harq_pid);
486
  while (crc_pdu->harq_id != harq_pid || harq_pid < 0) {
487
    LOG_W(NR_MAC,
488
          "Unexpected ULSCH HARQ PID %d (have %d) for RNTI 0x%04x (ignore this warning for RA)\n",
489 490
          crc_pdu->harq_id,
          harq_pid,
491
          crc_pdu->rnti);
492 493 494 495
    if (harq_pid < 0)
      return;

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

498
    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
499
      abort_nr_ul_harq(UE, harq_pid);
500 501 502 503
    } else {
      sched_ctrl->ul_harq_processes[harq_pid].round++;
      add_tail_nr_list(&sched_ctrl->retrans_ul_harq, harq_pid);
    }
504
    harq_pid = sched_ctrl->feedback_ul_harq.head;
505 506 507 508 509 510 511 512 513
  }
  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;
514
    LOG_D(NR_MAC,
515 516 517 518
          "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);
519
  } else if (harq->round >= RC.nrmac[mod_id]->ul_bler.harq_round_max  - 1) {
Laurent THOMAS's avatar
Laurent THOMAS committed
520
    abort_nr_ul_harq(UE, harq_pid);
521
    LOG_D(NR_MAC,
522 523 524 525 526
          "RNTI %04x: Ulharq id %d crc failed in all rounds\n",
          crc_pdu->rnti,
          harq_pid);
  } else {
    harq->round++;
527
    LOG_D(NR_MAC,
528 529 530 531 532
          "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);
  }
533
}
534

535 536 537
/*
* When data are received on PHY and transmitted to MAC
*/
538 539 540
void nr_rx_sdu(const module_id_t gnb_mod_idP,
               const int CC_idP,
               const frame_t frameP,
541
               const sub_frame_t slotP,
542 543 544 545
               const rnti_t rntiP,
               uint8_t *sduP,
               const uint16_t sdu_lenP,
               const uint16_t timing_advance,
546 547
               const uint8_t ul_cqi,
               const uint16_t rssi){
548

Robert Schmidt's avatar
Robert Schmidt committed
549 550 551
  gNB_MAC_INST *gNB_mac = RC.nrmac[gnb_mod_idP];

  const int current_rnti = rntiP;
Laurent THOMAS's avatar
Laurent THOMAS committed
552
  LOG_D(NR_MAC, "rx_sdu for rnti %04x\n", current_rnti);
Robert Schmidt's avatar
Robert Schmidt committed
553
  const int target_snrx10 = gNB_mac->pusch_target_snrx10;
554
  const int pusch_failure_thres = gNB_mac->pusch_failure_thres;
Laurent THOMAS's avatar
Laurent THOMAS committed
555 556 557 558
  
  NR_UE_info_t* UE = find_nr_UE(&gNB_mac->UE_info, current_rnti);
  if (UE) {
    NR_UE_sched_ctrl_t *UE_scheduling_control = &UE->UE_sched_ctrl;
Robert Schmidt's avatar
Robert Schmidt committed
559 560 561 562 563 564
    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));
565

Laurent THOMAS's avatar
Laurent THOMAS committed
566 567
    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",
568 569 570 571
          gnb_mod_idP,
          harq_pid,
          CC_idP,
          frameP,
572
          slotP,
573
          current_rnti,
574
          ul_cqi,
575
          timing_advance,
576 577
          sduP,
          rssi);
578

579
    // if not missed detection (10dB threshold for now)
580
    if (rssi>0) {
581
      UE_scheduling_control->tpc0 = nr_get_tpc(target_snrx10,ul_cqi,30);
582 583
      if (timing_advance != 0xffff)
        UE_scheduling_control->ta_update = timing_advance;
584 585
      UE_scheduling_control->raw_rssi = rssi;
      UE_scheduling_control->pusch_snrx10 = ul_cqi * 5 - 640;
Laurent THOMAS's avatar
Laurent THOMAS committed
586 587

      LOG_D(NR_MAC, "[UE %04x] PUSCH TPC %d and TA %d\n",UE->rnti,UE_scheduling_control->tpc0,UE_scheduling_control->ta_update);
588 589
    }
    else{
Laurent THOMAS's avatar
Laurent THOMAS committed
590
      LOG_D(NR_MAC,"[UE %04x] Detected DTX : increasing UE TX power\n",UE->rnti);
591
      UE_scheduling_control->tpc0 = 1;
592 593
    }

594
#if defined(ENABLE_MAC_PAYLOAD_DEBUG)
Laurent's avatar
Laurent committed
595

596
    LOG_I(NR_MAC, "Printing received UL MAC payload at gNB side: %d \n");
597
    for (int i = 0; i < sdu_lenP ; i++) {
francescomani's avatar
francescomani committed
598 599 600
      //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]);
601 602
    }
    printf("\n");
Laurent's avatar
Laurent committed
603

604 605 606
#endif

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

Laurent THOMAS's avatar
Laurent THOMAS committed
609
      UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt = 0;
610 611
      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;
612 613 614
      if (UE_scheduling_control->sched_ul_bytes < 0)
        UE_scheduling_control->sched_ul_bytes = 0;

francescomani's avatar
francescomani committed
615
      nr_process_mac_pdu(gnb_mod_idP, UE, CC_idP, frameP, slotP, sduP, sdu_lenP, harq_pid);
616 617
    }
    else {
618 619 620
      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){
621 622
        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;
623 624 625
        if (UE_scheduling_control->sched_ul_bytes < 0)
          UE_scheduling_control->sched_ul_bytes = 0;
      }
626
      if (ul_cqi <= 128) {
Laurent THOMAS's avatar
Laurent THOMAS committed
627 628
        UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt++;
        UE->mac_stats.ulsch_DTX++;
629
      }
Laurent THOMAS's avatar
Laurent THOMAS committed
630 631 632 633 634 635

      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);
         UE->UE_sched_ctrl.ul_failure = 1;

rmagueta's avatar
rmagueta committed
636
         nr_mac_gNB_rrc_ul_failure(gnb_mod_idP,CC_idP,frameP,slotP,rntiP);
637
      }
638
    }
639 640 641 642 643 644 645 646 647 648 649 650 651
  } 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");
    }
652

Robert Schmidt's avatar
Robert Schmidt committed
653 654 655
    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
656
    
657 658 659 660 661 662 663
    /* 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
664
      
665
      if(no_sig) {
666
        LOG_D(NR_MAC, "Random Access %i failed at state %i (no signal)\n", i, ra->state);
667
        nr_mac_remove_ra_rnti(gnb_mod_idP, ra->rnti);
668
        nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra);
669 670 671 672
      } else {

        // random access pusch with TC-RNTI
        if (ra->rnti != current_rnti) {
673
          LOG_D(NR_MAC,
rmagueta's avatar
rmagueta committed
674
                "expected TC_RNTI %04x to match current RNTI %04x\n",
675 676
                ra->rnti,
                current_rnti);
rmagueta's avatar
rmagueta committed
677 678

          if( (frameP==ra->Msg3_frame) && (slotP==ra->Msg3_slot) ) {
679
            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
680 681 682 683
            nr_mac_remove_ra_rnti(gnb_mod_idP, ra->rnti);
            nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra);
          }

684 685
          continue;
        }
rmagueta's avatar
rmagueta committed
686

687

Laurent THOMAS's avatar
Laurent THOMAS committed
688 689 690 691
	NR_UE_info_t* UE = add_new_nr_ue(gNB_mac, ra->rnti, ra->CellGroup);
        if (!UE) {
          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);

692 693 694 695 696
          nr_mac_remove_ra_rnti(gnb_mod_idP, ra->rnti);
          nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra);
          return;
        }

Laurent THOMAS's avatar
Laurent THOMAS committed
697
        UE->UE_beam_index = ra->beam_id;
rmagueta's avatar
rmagueta committed
698 699

        // re-initialize ta update variables after RA procedure completion
Laurent THOMAS's avatar
Laurent THOMAS committed
700
        UE->UE_sched_ctrl.ta_frame = frameP;
rmagueta's avatar
rmagueta committed
701

rmagueta's avatar
rmagueta committed
702
        LOG_D(NR_MAC,
703
              "reset RA state information for RA-RNTI 0x%04x/index %d\n",
704
              ra->rnti,
705
              i);
706

707
        LOG_I(NR_MAC,
708
              "[gNB %d][RAPROC] PUSCH with TC_RNTI 0x%04x received correctly, "
Laurent THOMAS's avatar
Laurent THOMAS committed
709
              "adding UE MAC Context RNTI 0x%04x\n",
710 711 712
              gnb_mod_idP,
              current_rnti,
              ra->rnti);
713

francescomani's avatar
francescomani committed
714
        NR_UE_sched_ctrl_t *UE_scheduling_control = &UE->UE_sched_ctrl;
715

francescomani's avatar
francescomani committed
716 717 718 719 720 721
        UE_scheduling_control->tpc0 = nr_get_tpc(target_snrx10,ul_cqi,30);
        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;
        LOG_D(NR_MAC, "[UE %04x] PUSCH TPC %d and TA %d\n",UE->rnti,UE_scheduling_control->tpc0,UE_scheduling_control->ta_update);
722
        if(ra->cfra) {
723

Laurent THOMAS's avatar
Laurent THOMAS committed
724
          LOG_A(NR_MAC, "(rnti 0x%04x) CFRA procedure succeeded!\n", ra->rnti);
725
          UE->ra_timer = 0;
726
          nr_mac_remove_ra_rnti(gnb_mod_idP, ra->rnti);
727
          nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra);
728 729
          process_CellGroup(ra->CellGroup, UE_scheduling_control);

730
        } else {
731

732
          LOG_A(NR_MAC,"[RAPROC] RA-Msg3 received (sdu_lenP %d)\n",sdu_lenP);
rmagueta's avatar
rmagueta committed
733
          LOG_D(NR_MAC,"[RAPROC] Received Msg3:\n");
734
          for (int k = 0; k < sdu_lenP; k++) {
rmagueta's avatar
rmagueta committed
735
            LOG_D(NR_MAC,"(%i): 0x%x\n",k,sduP[k]);
736
          }
737

738 739 740 741
          // 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
742 743
          // 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
francescomani's avatar
francescomani committed
744
          if (nr_process_mac_pdu(gnb_mod_idP, UE, CC_idP, frameP, slotP, sduP, sdu_lenP, -1) == 0) {
745
            ra->state = Msg4;
746 747
            
            if (ra->msg3_dcch_dtch) {
748
              // Check if the UE identified by C-RNTI still exists at the gNB
Laurent THOMAS's avatar
Laurent THOMAS committed
749 750
              NR_UE_info_t * UE_C = find_nr_UE(&gNB_mac->UE_info, ra->crnti);
              if (!UE_C) {
751 752
                // 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
753
                mac_remove_nr_ue(gNB_mac, ra->rnti);
754 755 756
                nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra);
                return;
              } else {
757
                // The UE identified by C-RNTI still exists at the gNB
758
                // Reset uplink failure flags/counters/timers at RRC
759
                nr_mac_gNB_rrc_ul_failure_reset(gnb_mod_idP, frameP, slotP, ra->crnti);
760 761 762 763

                // Reset HARQ processes
                reset_dl_harq_list(&UE_C->UE_sched_ctrl);
                reset_ul_harq_list(&UE_C->UE_sched_ctrl);
764 765
              }
            }
766 767
            LOG_I(NR_MAC, "Activating scheduling RA-Msg4 for TC_RNTI 0x%04x (state %d)\n",
                  (ra->msg3_dcch_dtch?ra->crnti:ra->rnti), ra->state);
Eurecom's avatar
Eurecom committed
768 769 770 771 772
          }
          else {
             nr_mac_remove_ra_rnti(gnb_mod_idP, ra->rnti);
             nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra);
          }
773
        }
774
        return;
775
      }
776 777 778 779 780 781
    }
  } 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;
782

783 784 785
      if( (frameP!=ra->Msg3_frame) || (slotP!=ra->Msg3_slot))
        continue;

786 787
      // for CFRA (NSA) do not schedule retransmission of msg3
      if (ra->cfra) {
788
        LOG_D(NR_MAC, "Random Access %i failed at state %i (NSA msg3 reception failed)\n", i, ra->state);
789 790 791 792 793
        nr_mac_remove_ra_rnti(gnb_mod_idP, ra->rnti);
        nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra);
        return;
      }

794 795
      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);
796 797 798 799 800
        nr_mac_remove_ra_rnti(gnb_mod_idP, ra->rnti);
        nr_clear_ra_proc(gnb_mod_idP, CC_idP, frameP, ra);
        return;
      }

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

803
      ra->msg3_round++;
804
      ra->state = Msg3_retransmission;
805
    }
806
  }
807 808
}

809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 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 926 927 928 929 930 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
uint32_t calc_power_complex(const int16_t *x, const int16_t *y, const uint32_t size) {

  // 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;
}

c16_t nr_h_times_w(c16_t h, char w) {
  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;
}

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) {

  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;
}

1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
void get_precoder_matrix_coef(char *w,
                              const uint8_t ul_ri,
                              const uint16_t num_ue_srs_ports,
                              const uint8_t transform_precoding,
                              const uint8_t tpmi,
                              const uint8_t uI) {
  if (ul_ri == 0) {
    if (num_ue_srs_ports == 2) {
      *w = *table_38211_6_3_1_5_1[tpmi][uI];
    } else {
      if (transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled) {
        *w = *table_38211_6_3_1_5_2[tpmi][uI];
      } else {
        *w = *table_38211_6_3_1_5_3[tpmi][uI];
      }
    }
  } else {
    AssertFatal(1==0,"Function get_precoder_matrix_coef() does not support %i layers yet!\n", ul_ri+1);
  }
1043 1044 1045
}

int nr_srs_tpmi_estimation(const NR_PUSCH_Config_t *pusch_Config,
1046
                           const uint8_t transform_precoding,
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 1089 1090 1091
                           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) {

  uint8_t tpmi_sel = 0;
  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;
  uint32_t max_precoded_signal_power = 0;
  int additional_max_tpmi = -1;
  char w;

  uint8_t max_tpmi = get_max_tpmi(pusch_Config,
                                  num_ue_srs_ports,
                                  &ul_ri,
                                  &additional_max_tpmi);

  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]
  //                           ...                                     ...

  for(uint8_t tpmi = 0; tpmi<=end_tpmi_loop; tpmi++) {

    if (tpmi > max_tpmi) {
      tpmi = end_tpmi_loop;
    }

    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;
        precoded_channel_matrix_re[index_gI_pI] = 0;
        precoded_channel_matrix_im[index_gI_pI] = 0;

        for(int uI = 0; uI < num_ue_srs_ports; uI++) {

          uint16_t index = uI*num_gnb_antenna_elements*num_prgs + index_gI_pI;
1092
          get_precoder_matrix_coef(&w, ul_ri, num_ue_srs_ports, transform_precoding, tpmi, uI);
1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127
          c16_t h_times_w = nr_h_times_w(channel_matrix16[index], w);

          precoded_channel_matrix_re[index_gI_pI] += h_times_w.r;
          precoded_channel_matrix_im[index_gI_pI] += h_times_w.i;

#ifdef SRS_IND_DEBUG
          LOG_I(NR_MAC, "(uI %i, gI %i, pI %i) channel_matrix --> real %i, imag %i\n",
                uI, gI, pI, channel_matrix16[index].r, channel_matrix16[index].i);
#endif
        }

#ifdef SRS_IND_DEBUG
        LOG_I(NR_MAC, "(gI %i, pI %i) precoded_channel_coef --> real %i, imag %i\n",
              gI, pI, precoded_channel_matrix_re[index_gI_pI], precoded_channel_matrix_im[index_gI_pI]);
#endif
      }
    }

    uint32_t precoded_signal_power = calc_power_complex(precoded_channel_matrix_re,
                                                        precoded_channel_matrix_im,
                                                        num_prgs*num_gnb_antenna_elements);

#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;
}

1128 1129 1130
void handle_nr_srs_measurements(const module_id_t module_id,
                                const frame_t frame,
                                const sub_frame_t slot,
1131
                                const nfapi_nr_srs_indication_pdu_t *srs_ind)
luis_pereira87's avatar
luis_pereira87 committed
1132
{
1133
  LOG_D(NR_MAC, "(%d.%d) Received SRS indication for UE %04x\n", frame, slot, srs_ind->rnti);
1134 1135 1136 1137

#ifdef SRS_IND_DEBUG
  LOG_I(NR_MAC, "frame = %i\n", frame);
  LOG_I(NR_MAC, "slot = %i\n", slot);
1138 1139 1140 1141 1142 1143 1144
  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

1145
  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
1146
  if (!UE) {
1147
    LOG_W(NR_MAC, "Could not find UE for RNTI %04x\n", srs_ind->rnti);
luis_pereira87's avatar
luis_pereira87 committed
1148 1149 1150
    return;
  }

1151 1152
  if (srs_ind->timing_advance_offset == 0xFFFF) {
    LOG_W(NR_MAC, "Invalid timing advance offset for RNTI %04x\n", srs_ind->rnti);
1153 1154 1155
    return;
  }

1156 1157 1158
  gNB_MAC_INST *nr_mac = RC.nrmac[module_id];
  NR_mac_stats_t *stats = &UE->mac_stats;

1159 1160
  switch (srs_ind->srs_usage) {
    case NR_SRS_ResourceSet__usage_beamManagement: {
Roberto Louro Magueta's avatar
Roberto Louro Magueta committed
1161
      nfapi_nr_srs_beamforming_report_t nr_srs_beamforming_report;
1162 1163
      unpack_nr_srs_beamforming_report(srs_ind->report_tlv->value,
                                       srs_ind->report_tlv->length,
Roberto Louro Magueta's avatar
Roberto Louro Magueta committed
1164
                                       &nr_srs_beamforming_report,
1165 1166
                                       sizeof(nfapi_nr_srs_beamforming_report_t));

1167 1168 1169 1170 1171 1172 1173
      if (nr_srs_beamforming_report.wide_band_snr == 0xFF) {
        LOG_W(NR_MAC, "Invalid wide_band_snr for RNTI %04x\n", srs_ind->rnti);
        return;
      }

      int wide_band_snr_dB = (nr_srs_beamforming_report.wide_band_snr >> 1) - 64;

1174
#ifdef SRS_IND_DEBUG
Roberto Louro Magueta's avatar
Roberto Louro Magueta committed
1175 1176
      LOG_I(NR_MAC, "nr_srs_beamforming_report.prg_size = %i\n", nr_srs_beamforming_report.prg_size);
      LOG_I(NR_MAC, "nr_srs_beamforming_report.num_symbols = %i\n", nr_srs_beamforming_report.num_symbols);
1177
      LOG_I(NR_MAC, "nr_srs_beamforming_report.wide_band_snr = %i (%i dB)\n", nr_srs_beamforming_report.wide_band_snr, wide_band_snr_dB);
Roberto Louro Magueta's avatar
Roberto Louro Magueta committed
1178 1179
      LOG_I(NR_MAC, "nr_srs_beamforming_report.num_reported_symbols = %i\n", nr_srs_beamforming_report.num_reported_symbols);
      LOG_I(NR_MAC, "nr_srs_beamforming_report.prgs[0].num_prgs = %i\n", nr_srs_beamforming_report.prgs[0].num_prgs);
1180 1181 1182
      for (int prg_idx = 0; prg_idx < nr_srs_beamforming_report.prgs[0].num_prgs; prg_idx++) {
        LOG_I(NR_MAC,
              "nr_srs_beamforming_report.prgs[0].prg_list[%3i].rb_snr = %i (%i dB)\n",
1183
              prg_idx,
Roberto Louro Magueta's avatar
Roberto Louro Magueta committed
1184
              nr_srs_beamforming_report.prgs[0].prg_list[prg_idx].rb_snr,
1185
              (nr_srs_beamforming_report.prgs[0].prg_list[prg_idx].rb_snr >> 1) - 64);
1186 1187 1188
      }
#endif

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

1191
      const int ul_prbblack_SNR_threshold = nr_mac->ul_prbblack_SNR_threshold;
1192
      uint16_t *ulprbbl = nr_mac->ulprbbl;
1193

Roberto Louro Magueta's avatar
Roberto Louro Magueta committed
1194
      uint8_t num_rbs = nr_srs_beamforming_report.prg_size * nr_srs_beamforming_report.prgs[0].num_prgs;
1195
      memset(ulprbbl, 0, num_rbs * sizeof(uint16_t));
1196
      for (int rb = 0; rb < num_rbs; rb++) {
1197 1198
        int snr = (nr_srs_beamforming_report.prgs[0].prg_list[rb / nr_srs_beamforming_report.prg_size].rb_snr >> 1) - 64;
        if (snr < wide_band_snr_dB - ul_prbblack_SNR_threshold) {
1199 1200 1201 1202
          ulprbbl[rb] = 0x3FFF; // all symbols taken
        }
        LOG_D(NR_MAC, "ulprbbl[%3i] = 0x%x\n", rb, ulprbbl[rb]);
      }
1203

1204
      break;
1205
    }
1206 1207

    case NR_SRS_ResourceSet__usage_codebook: {
Roberto Louro Magueta's avatar
Roberto Louro Magueta committed
1208
      nfapi_nr_srs_normalized_channel_iq_matrix_t nr_srs_normalized_channel_iq_matrix;
1209 1210
      unpack_nr_srs_normalized_channel_iq_matrix(srs_ind->report_tlv->value,
                                                 srs_ind->report_tlv->length,
Roberto Louro Magueta's avatar
Roberto Louro Magueta committed
1211
                                                 &nr_srs_normalized_channel_iq_matrix,
1212 1213 1214
                                                 sizeof(nfapi_nr_srs_normalized_channel_iq_matrix_t));

#ifdef SRS_IND_DEBUG
Roberto Louro Magueta's avatar
Roberto Louro Magueta committed
1215 1216 1217 1218 1219
      LOG_I(NR_MAC, "nr_srs_normalized_channel_iq_matrix.normalized_iq_representation = %i\n", nr_srs_normalized_channel_iq_matrix.normalized_iq_representation);
      LOG_I(NR_MAC, "nr_srs_normalized_channel_iq_matrix.num_gnb_antenna_elements = %i\n", nr_srs_normalized_channel_iq_matrix.num_gnb_antenna_elements);
      LOG_I(NR_MAC, "nr_srs_normalized_channel_iq_matrix.num_ue_srs_ports = %i\n", nr_srs_normalized_channel_iq_matrix.num_ue_srs_ports);
      LOG_I(NR_MAC, "nr_srs_normalized_channel_iq_matrix.prg_size = %i\n", nr_srs_normalized_channel_iq_matrix.prg_size);
      LOG_I(NR_MAC, "nr_srs_normalized_channel_iq_matrix.num_prgs = %i\n", nr_srs_normalized_channel_iq_matrix.num_prgs);
1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230
      c16_t *channel_matrix16 = (c16_t *)nr_srs_normalized_channel_iq_matrix.channel_matrix;
      c8_t *channel_matrix8 = (c8_t *)nr_srs_normalized_channel_iq_matrix.channel_matrix;
      for (int uI = 0; uI < nr_srs_normalized_channel_iq_matrix.num_ue_srs_ports; uI++) {
        for (int gI = 0; gI < nr_srs_normalized_channel_iq_matrix.num_gnb_antenna_elements; gI++) {
          for (int pI = 0; pI < nr_srs_normalized_channel_iq_matrix.num_prgs; pI++) {
            uint16_t index = uI * nr_srs_normalized_channel_iq_matrix.num_gnb_antenna_elements * nr_srs_normalized_channel_iq_matrix.num_prgs + gI * nr_srs_normalized_channel_iq_matrix.num_prgs + pI;
            LOG_I(NR_MAC,
                  "(uI %i, gI %i, pI %i) channel_matrix --> real %i, imag %i\n",
                  uI,
                  gI,
                  pI,
Roberto Louro Magueta's avatar
Roberto Louro Magueta committed
1231 1232
                  nr_srs_normalized_channel_iq_matrix.normalized_iq_representation == 0 ? channel_matrix8[index].r : channel_matrix16[index].r,
                  nr_srs_normalized_channel_iq_matrix.normalized_iq_representation == 0 ? channel_matrix8[index].i : channel_matrix16[index].i);
1233 1234 1235 1236 1237
          }
        }
      }
#endif

1238 1239
      // TODO: This should be improved
      NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
1240
      NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP;
1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252
      sched_ctrl->srs_feedback.sri = NR_SRS_SRI_0;
      sched_ctrl->srs_feedback.ul_ri = 0; // TODO: Compute this
      sched_ctrl->srs_feedback.tpmi = nr_srs_tpmi_estimation(current_BWP->pusch_Config,
                                                             current_BWP->transform_precoding,
                                                             nr_srs_normalized_channel_iq_matrix.channel_matrix,
                                                             nr_srs_normalized_channel_iq_matrix.normalized_iq_representation,
                                                             nr_srs_normalized_channel_iq_matrix.num_gnb_antenna_elements,
                                                             nr_srs_normalized_channel_iq_matrix.num_ue_srs_ports,
                                                             nr_srs_normalized_channel_iq_matrix.prg_size,
                                                             nr_srs_normalized_channel_iq_matrix.num_prgs,
                                                             sched_ctrl->srs_feedback.ul_ri);
      sprintf(stats->srs_stats, "UL-RI %d, TPMI %d", sched_ctrl->srs_feedback.ul_ri + 1, sched_ctrl->srs_feedback.tpmi);
1253 1254 1255 1256 1257 1258 1259 1260 1261
      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:
1262
      AssertFatal(1 == 0, "Invalid SRS usage\n");
1263
  }
1264 1265
}

1266
long get_K2(NR_PUSCH_TimeDomainResourceAllocationList_t *tdaList,
1267 1268 1269
            int time_domain_assignment,
            int mu) {

1270
  NR_PUSCH_TimeDomainResourceAllocation_t *tda = tdaList->list.array[time_domain_assignment];
1271

1272 1273
  if (tda->k2)
    return *tda->k2;
1274 1275 1276 1277 1278 1279 1280 1281
  else if (mu < 2)
    return 1;
  else if (mu == 2)
    return 2;
  else
    return 3;
}

Laurent THOMAS's avatar
Laurent THOMAS committed
1282 1283
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)
1284
{
1285
  const int n = nr_slots_per_frame[*scc->ssbSubcarrierSpacing];
1286 1287
  const int now = frame * n + slot;

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

1290 1291 1292
  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
1293
  int last_ul_slot;
1294
  int tdd_period_len[8] = {500,625,1000,1250,2000,2500,5000,10000};
1295
  if (tdd) { // Force the default transmission in a full slot as early as possible in the UL portion of TDD period (last_ul_slot)
1296
    num_slots_per_period = n*tdd_period_len[tdd->dl_UL_TransmissionPeriodicity]/10000;
1297
    last_ul_slot=1+tdd->nrofDownlinkSlots;
1298
  } else {
1299
    num_slots_per_period = n;
1300
    last_ul_slot = sched_ctrl->last_ul_slot;
1301
  }
1302

Laurent THOMAS's avatar
Laurent THOMAS committed
1303
  const int last_ul_sched = sched_ctrl->last_ul_frame * n + last_ul_slot;
1304 1305 1306 1307 1308 1309
  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
1310
  const bool high_inactivity = diff >= (ulsch_max_frame_inactivity > 0 ? ulsch_max_frame_inactivity * n : num_slots_per_period);
1311
  LOG_D(NR_MAC,
1312 1313 1314 1315 1316 1317 1318 1319 1320
        "%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;
}

1321
void update_ul_ue_R_Qm(int mcs, int mcs_table, const NR_PUSCH_Config_t *pusch_Config, uint16_t *R, uint8_t *Qm)
1322
{
1323 1324
  *R = nr_get_code_rate_ul(mcs, mcs_table);
  *Qm = nr_get_Qm_ul(mcs, mcs_table);
1325

1326
  if (pusch_Config && pusch_Config->tp_pi2BPSK && ((mcs_table == 3 && mcs < 2) || (mcs_table == 4 && mcs < 6))) {
1327 1328 1329 1330 1331
    *R >>= 1;
    *Qm <<= 1;
  }
}

francescomani's avatar
francescomani committed
1332
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)
1333
{
francescomani's avatar
francescomani committed
1334
  AssertFatal(*Rb >= minRb, "illegal Rb %d < minRb %d\n", *Rb, minRb);
1335 1336
  AssertFatal(*mcs >= 0 && *mcs <= 28, "illegal MCS %d\n", *mcs);

francescomani's avatar
francescomani committed
1337
  const int tbs_bits = tbs << 3;
1338 1339
  uint16_t R;
  uint8_t Qm;
1340
  update_ul_ue_R_Qm(*mcs, ul_bwp->mcs_table, ul_bwp->pusch_Config, &R, &Qm);
1341

1342
  long *deltaMCS = ul_bwp->pusch_Config ? ul_bwp->pusch_Config->pusch_PowerControl->deltaMCS : NULL;
francescomani's avatar
francescomani committed
1343 1344 1345 1346 1347 1348 1349
  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
1350

francescomani's avatar
francescomani committed
1351
  while (ph_limit < tx_power && *Rb >= minRb) {
francescomani's avatar
francescomani committed
1352
    (*Rb)--;
francescomani's avatar
francescomani committed
1353 1354 1355 1356 1357 1358 1359
    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);
1360 1361
  }

francescomani's avatar
francescomani committed
1362
  while (ph_limit < tx_power && *mcs > 6) {
1363
    (*mcs)--;
1364
    update_ul_ue_R_Qm(*mcs, ul_bwp->mcs_table, ul_bwp->pusch_Config, &R, &Qm);
francescomani's avatar
francescomani committed
1365 1366 1367 1368 1369 1370 1371
    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);
1372 1373
  }

francescomani's avatar
francescomani committed
1374 1375 1376
  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);
1377 1378
}

Laurent THOMAS's avatar
Laurent THOMAS committed
1379 1380 1381 1382 1383 1384 1385 1386 1387 1388
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_SIB1_t *sib1,
				       const NR_ServingCellConfigCommon_t *scc,
				       const int tda)
1389 1390
{
  const int CC_id = 0;
Laurent THOMAS's avatar
Laurent THOMAS committed
1391
  NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
1392
  NR_sched_pusch_t *retInfo = &sched_ctrl->ul_harq_processes[harq_pid].sched_pusch;
1393

1394
  int rbStart = 0; // wrt BWP start
1395
  const uint16_t bwpSize = UE->current_UL_BWP.BWPSize;
1396
  const uint8_t nrOfLayers = 1;
1397
  LOG_D(NR_MAC,"retInfo->time_domain_allocation = %d, tda = %d\n", retInfo->time_domain_allocation, tda);
francescomani's avatar
francescomani committed
1398
  LOG_D(NR_MAC,"tbs %d\n",retInfo->tb_size);
francescomani's avatar
francescomani committed
1399 1400
  if (tda == retInfo->time_domain_allocation &&
      nrOfLayers == retInfo->nrOfLayers) {
1401 1402

    /* Check the resource is enough for retransmission */
francescomani's avatar
francescomani committed
1403
    const uint16_t slbitmap = SL_to_bitmap(retInfo->tda_info.startSymbolIndex, retInfo->tda_info.nrOfSymbols);
1404
    while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap)
1405 1406
      rbStart++;
    if (rbStart + retInfo->rbSize > bwpSize) {
Laurent THOMAS's avatar
Laurent THOMAS committed
1407
      LOG_W(NR_MAC, "cannot allocate retransmission of RNTI %04x: no resources (rbStart %d, retInfo->rbSize %d, bwpSize %d\n", UE->rnti, rbStart, retInfo->rbSize, bwpSize);
1408 1409
      return false;
    }
1410
    LOG_D(NR_MAC, "%s(): retransmission keeping TDA %d and TBS %d\n", __func__, tda, retInfo->tb_size);
1411
  } else {
francescomani's avatar
francescomani committed
1412

francescomani's avatar
francescomani committed
1413 1414 1415 1416 1417
    NR_tda_info_t tda_info = nr_get_pusch_tda_info(&UE->current_UL_BWP, tda);
    NR_pusch_dmrs_t dmrs_info = get_ul_dmrs_params(scc,
                                                   &UE->current_UL_BWP,
                                                   &tda_info,
                                                   nrOfLayers);
1418 1419
    /* the retransmission will use a different time domain allocation, check
     * that we have enough resources */
francescomani's avatar
francescomani committed
1420
    const uint16_t slbitmap = SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols);
1421
    while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap)
1422 1423
      rbStart++;
    int rbSize = 0;
1424
    while (rbStart + rbSize < bwpSize && (rballoc_mask[rbStart + rbSize] & slbitmap) == slbitmap)
1425 1426 1427 1428 1429
      rbSize++;
    uint32_t new_tbs;
    uint16_t new_rbSize;
    bool success = nr_find_nb_rb(retInfo->Qm,
                                 retInfo->R,
1430
                                 1, // layers
francescomani's avatar
francescomani committed
1431 1432
                                 tda_info.nrOfSymbols,
                                 dmrs_info.N_PRB_DMRS * dmrs_info.num_dmrs_symb,
1433
                                 retInfo->tb_size,
1434
                                 1, /* minimum of 1RB: need to find exact TBS, don't preclude any number */
1435 1436 1437 1438
                                 rbSize,
                                 &new_tbs,
                                 &new_rbSize);
    if (!success || new_tbs != retInfo->tb_size) {
1439
      LOG_D(NR_MAC, "%s(): new TBsize %d of new TDA does not match old TBS %d\n", __func__, new_tbs, retInfo->tb_size);
1440 1441
      return false; /* the maximum TBsize we might have is smaller than what we need */
    }
1442
    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);
1443 1444 1445 1446 1447
    /* 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
1448 1449
    retInfo->dmrs_info = dmrs_info;
    retInfo->tda_info = tda_info;
1450 1451
  }

1452
  /* Find a free CCE */
1453
  const uint32_t Y = get_Y(sched_ctrl->search_space, slot, UE->rnti);
1454 1455 1456 1457 1458 1459 1460 1461 1462
  uint8_t nr_of_candidates;
  for (int i=0; i<5; i++) {
    // for now taking the lowest value among the available aggregation levels
    find_aggregation_candidates(&sched_ctrl->aggregation_level,
                                &nr_of_candidates,
                                sched_ctrl->search_space,
                                1<<i);
    if(nr_of_candidates>0) break;
  }
Laurent THOMAS's avatar
Laurent THOMAS committed
1463
  int CCEIndex = find_pdcch_candidate(nrmac,
1464 1465 1466
                                      CC_id,
                                      sched_ctrl->aggregation_level,
                                      nr_of_candidates,
1467
                                      &sched_ctrl->sched_pdcch,
1468 1469 1470 1471
                                      sched_ctrl->coreset,
                                      Y);

  if (CCEIndex<0) {
Laurent THOMAS's avatar
Laurent THOMAS committed
1472
    LOG_D(NR_MAC, "%4d.%2d no free CCE for retransmission UL DCI UE %04x\n", frame, slot, UE->rnti);
1473 1474 1475
    return false;
  }

1476
  sched_ctrl->cce_index = CCEIndex;
Laurent THOMAS's avatar
Laurent THOMAS committed
1477
  fill_pdcch_vrb_map(nrmac,
1478
                     CC_id,
1479
                     &sched_ctrl->sched_pdcch,
1480 1481 1482
                     CCEIndex,
                     sched_ctrl->aggregation_level);

1483 1484 1485 1486 1487 1488 1489 1490 1491
  /* 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;

1492
  LOG_D(NR_MAC,
Laurent THOMAS's avatar
Laurent THOMAS committed
1493
        "%4d.%2d Allocate UL retransmission RNTI %04x sched %4d.%2d (%d RBs)\n",
1494 1495
        frame,
        slot,
Laurent THOMAS's avatar
Laurent THOMAS committed
1496
        UE->rnti,
1497 1498 1499 1500 1501 1502 1503 1504 1505 1506
        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
1507
    rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] ^= SL_to_bitmap(sched_pusch->tda_info.startSymbolIndex, sched_pusch->tda_info.nrOfSymbols);
1508 1509 1510
  return true;
}

Laurent THOMAS's avatar
Laurent THOMAS committed
1511
uint32_t ul_pf_tbs[3][29]; // pre-computed, approximate TBS values for PF coefficient
Laurent THOMAS's avatar
Laurent THOMAS committed
1512 1513 1514 1515 1516 1517 1518 1519 1520
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;
}

ChiehChun's avatar
ChiehChun committed
1521 1522 1523
void pf_ul(module_id_t module_id,
           frame_t frame,
           sub_frame_t slot,
Roberto Louro Magueta's avatar
Roberto Louro Magueta committed
1524
           NR_UE_info_t *UE_list[],
1525
           int max_num_ue,
ChiehChun's avatar
ChiehChun committed
1526
           int n_rb_sched,
1527
           uint16_t *rballoc_mask) {
ChiehChun's avatar
ChiehChun committed
1528 1529

  const int CC_id = 0;
1530 1531
  gNB_MAC_INST *nrmac = RC.nrmac[module_id];
  NR_ServingCellConfigCommon_t *scc = nrmac->common_channels[CC_id].ServingCellConfigCommon;
1532
  const NR_SIB1_t *sib1 = RC.nrmac[module_id]->common_channels[0].sib1 ? RC.nrmac[module_id]->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL;
Laurent THOMAS's avatar
Laurent THOMAS committed
1533 1534
  
  const int min_rb = 5;
1535
  // UEs that could be scheduled
Laurent THOMAS's avatar
Laurent THOMAS committed
1536 1537 1538
  UEsched_t UE_sched[MAX_MOBILES_PER_GNB] = {0};
  int remainUEs=max_num_ue;
  int curUE=0;
ChiehChun's avatar
ChiehChun committed
1539 1540

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

Laurent THOMAS's avatar
Laurent THOMAS committed
1543 1544
    if (UE->Msg4_ACKed != true)
      continue;
1545

Laurent THOMAS's avatar
Laurent THOMAS committed
1546 1547
    LOG_D(NR_MAC,"pf_ul: preparing UL scheduling for UE %04x\n",UE->rnti);
    NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
francescomani's avatar
francescomani committed
1548
    NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP;
1549

1550
    int rbStart = 0; // wrt BWP start
Eurecom's avatar
Eurecom committed
1551

francescomani's avatar
francescomani committed
1552
    const uint16_t bwpSize = current_BWP->BWPSize;
1553
    NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch;
Laurent THOMAS's avatar
Laurent THOMAS committed
1554
    const NR_mac_dir_stats_t *stats = &UE->mac_stats.ul;
ChiehChun's avatar
ChiehChun committed
1555 1556

    /* Calculate throughput */
1557
    const float a = 0.0005f; // corresponds to 200ms window
Robert Schmidt's avatar
Robert Schmidt committed
1558
    const uint32_t b = stats->current_bytes;
Laurent THOMAS's avatar
Laurent THOMAS committed
1559
    UE->ul_thr_ue = (1 - a) * UE->ul_thr_ue + a * b;
ChiehChun's avatar
ChiehChun committed
1560

1561
    /* Check if retransmission is necessary */
1562
    sched_pusch->ul_harq_pid = sched_ctrl->retrans_ul_harq.head;
Laurent THOMAS's avatar
Laurent THOMAS committed
1563
    LOG_D(NR_MAC,"pf_ul: UE %04x harq_pid %d\n",UE->rnti,sched_pusch->ul_harq_pid);
1564 1565
    if (sched_pusch->ul_harq_pid >= 0) {
      /* Allocate retransmission*/
1566
      const int tda = get_ul_tda(nrmac, scc, sched_pusch->slot);
Laurent THOMAS's avatar
Laurent THOMAS committed
1567
      bool r = allocate_ul_retransmission(nrmac, frame, slot, rballoc_mask, &n_rb_sched, UE, sched_pusch->ul_harq_pid, sib1, scc, tda);
1568
      if (!r) {
Laurent THOMAS's avatar
Laurent THOMAS committed
1569
        LOG_D(NR_MAC, "%4d.%2d UL retransmission UE RNTI %04x can NOT be allocated\n", frame, slot, UE->rnti);
1570 1571
        continue;
      }
Laurent THOMAS's avatar
Laurent THOMAS committed
1572
      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);
1573

1574
      /* reduce max_num_ue once we are sure UE can be allocated, i.e., has CCE */
Laurent THOMAS's avatar
Laurent THOMAS committed
1575
      remainUEs--;
1576

1577 1578
      // we have filled all with mandatory retransmissions
      // no need to schedule new transmissions
Laurent THOMAS's avatar
Laurent THOMAS committed
1579
      if (remainUEs == 0)
1580 1581
	      return;

Laurent THOMAS's avatar
Laurent THOMAS committed
1582 1583
      continue;
    } 
1584 1585 1586 1587 1588 1589 1590 1591 1592

    /* 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) {
      LOG_D(NR_MAC, "RNTI %04x has no free UL HARQ process, skipping\n", UE->rnti);
      continue;
    }

1593 1594
    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
1595
    const bool do_sched = nr_UE_is_to_be_scheduled(scc, 0, UE, sched_pusch->frame, sched_pusch->slot, nrmac->ulsch_max_frame_inactivity);
1596

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

Robert Schmidt's avatar
Robert Schmidt committed
1602 1603
    const NR_bler_options_t *bo = &nrmac->ul_bler;
    const int max_mcs = bo->max_mcs; /* no per-user maximum MCS yet */
1604 1605 1606 1607
    if (bo->harq_round_max == 1)
      sched_pusch->mcs = max_mcs;
    else
      sched_pusch->mcs = get_mcs_from_bler(bo, stats, &UE->UE_sched_ctrl.ul_bler_stats, max_mcs, frame);
Robert Schmidt's avatar
Robert Schmidt committed
1608

1609 1610 1611
    /* Schedule UE on SR or UL inactivity and no data (otherwise, will be scheduled
     * based on data to transmit) */
    if (B == 0 && do_sched) {
1612
      /* if no data, pre-allocate 5RB */
1613
      /* Find a free CCE */
1614
      const uint32_t Y = get_Y(sched_ctrl->search_space, slot, UE->rnti);
1615 1616 1617 1618 1619 1620 1621 1622 1623 1624
      uint8_t nr_of_candidates;
      for (int i=0; i<5; i++) {
        // for now taking the lowest value among the available aggregation levels
        find_aggregation_candidates(&sched_ctrl->aggregation_level,
                                    &nr_of_candidates,
                                    sched_ctrl->search_space,
                                    1<<i);
        if(nr_of_candidates>0) break;
      }
      int CCEIndex = find_pdcch_candidate(RC.nrmac[module_id],
Laurent THOMAS's avatar
Laurent THOMAS committed
1625 1626 1627 1628 1629 1630
					  CC_id,
					  sched_ctrl->aggregation_level,
					  nr_of_candidates,
					  &sched_ctrl->sched_pdcch,
					  sched_ctrl->coreset,
					  Y);
1631 1632

      if (CCEIndex<0) {
1633
        LOG_D(NR_MAC, "%4d.%2d no free CCE for UL DCI UE %04x (BSR 0)\n", frame, slot, UE->rnti);
1634 1635
        continue;
      }
1636

1637
      /* reduce max_num_ue once we are sure UE can be allocated, i.e., has CCE */
Laurent THOMAS's avatar
Laurent THOMAS committed
1638
      remainUEs--;
1639 1640 1641

      // we have filled all with mandatory retransmissions
      // no need to schedule new transmissions
Laurent THOMAS's avatar
Laurent THOMAS committed
1642
      if (remainUEs == 0)
1643 1644
        return;

francescomani's avatar
francescomani committed
1645 1646
      sched_pusch->nrOfLayers = 1;
      sched_pusch->time_domain_allocation = get_ul_tda(nrmac, scc, sched_pusch->slot);
francescomani's avatar
francescomani committed
1647 1648 1649 1650 1651
      sched_pusch->tda_info = nr_get_pusch_tda_info(current_BWP, sched_pusch->time_domain_allocation);
      sched_pusch->dmrs_info = get_ul_dmrs_params(scc,
                                                  current_BWP,
                                                  &sched_pusch->tda_info,
                                                  sched_pusch->nrOfLayers);
1652

1653
      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
1654 1655
            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);
1656
      while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap)
1657 1658
        rbStart++;
      if (rbStart + min_rb >= bwpSize) {
Laurent THOMAS's avatar
Laurent THOMAS committed
1659 1660
        LOG_W(NR_MAC, "cannot allocate continuous UL data for RNTI %04x: no resources (rbStart %d, min_rb %d, bwpSize %d\n",
              UE->rnti,rbStart,min_rb,bwpSize);
1661 1662 1663
        return;
      }

francescomani's avatar
francescomani committed
1664 1665 1666 1667 1668 1669 1670
      sched_ctrl->cce_index = CCEIndex;
      fill_pdcch_vrb_map(RC.nrmac[module_id],
                         CC_id,
                         &sched_ctrl->sched_pdcch,
                         CCEIndex,
                         sched_ctrl->aggregation_level);

1671
      NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch;
Robert Schmidt's avatar
Robert Schmidt committed
1672
      sched_pusch->mcs = min(nrmac->min_grant_mcs, sched_pusch->mcs);
1673
      update_ul_ue_R_Qm(sched_pusch->mcs, current_BWP->mcs_table, current_BWP->pusch_Config, &sched_pusch->R, &sched_pusch->Qm);
1674 1675 1676 1677 1678
      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
1679 1680
                                            sched_pusch->tda_info.nrOfSymbols,
                                            sched_pusch->dmrs_info.N_PRB_DMRS * sched_pusch->dmrs_info.num_dmrs_symb,
1681 1682
                                            0, // nb_rb_oh
                                            0,
francescomani's avatar
francescomani committed
1683
                                            sched_pusch->nrOfLayers)
1684 1685 1686 1687 1688
                             >> 3;

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

      continue;
1692
    }
1693 1694

    /* Create UE_sched for UEs eligibale for new data transmission*/
Robert Schmidt's avatar
Robert Schmidt committed
1695
    /* Calculate coefficient*/
francescomani's avatar
francescomani committed
1696
    const uint32_t tbs = ul_pf_tbs[current_BWP->mcs_table][sched_pusch->mcs];
Laurent THOMAS's avatar
Laurent THOMAS committed
1697 1698 1699 1700 1701 1702
    float coeff_ue = (float) tbs / UE->ul_thr_ue;
    LOG_D(NR_MAC,"rnti %04x b %d, ul_thr_ue %f, tbs %d, coeff_ue %f\n",
          UE->rnti, b, UE->ul_thr_ue, tbs, coeff_ue);
    UE_sched[curUE].coef=coeff_ue;
    UE_sched[curUE].UE=UE;
    curUE++;
1703 1704
  }

Laurent THOMAS's avatar
Laurent THOMAS committed
1705 1706 1707
  qsort(UE_sched, sizeof(*UE_sched), sizeofArray(UE_sched), comparator);
  UEsched_t *iterator=UE_sched;
  
1708
  const int min_rbSize = 5;
Robert Schmidt's avatar
Robert Schmidt committed
1709
  /* Loop UE_sched to find max coeff and allocate transmission */
Laurent THOMAS's avatar
Laurent THOMAS committed
1710
  while (remainUEs> 0 && n_rb_sched >= min_rbSize && iterator->UE != NULL) {
Robert Schmidt's avatar
Robert Schmidt committed
1711

Laurent THOMAS's avatar
Laurent THOMAS committed
1712
    NR_UE_sched_ctrl_t *sched_ctrl = &iterator->UE->UE_sched_ctrl;
1713

1714
    const uint32_t Y = get_Y(sched_ctrl->search_space, slot, iterator->UE->rnti);
1715 1716 1717 1718 1719 1720 1721
    uint8_t nr_of_candidates;
    for (int i=0; i<5; i++) {
      // for now taking the lowest value among the available aggregation levels
      find_aggregation_candidates(&sched_ctrl->aggregation_level,
                                  &nr_of_candidates,
                                  sched_ctrl->search_space,
                                  1<<i);
Laurent THOMAS's avatar
Laurent THOMAS committed
1722
      if(nr_of_candidates>0)
1723
        break;
1724 1725 1726 1727 1728
    }
    int CCEIndex = find_pdcch_candidate(RC.nrmac[module_id],
                                        CC_id,
                                        sched_ctrl->aggregation_level,
                                        nr_of_candidates,
1729
                                        &sched_ctrl->sched_pdcch,
1730 1731 1732
                                        sched_ctrl->coreset,
                                        Y);
    if (CCEIndex<0) {
Laurent THOMAS's avatar
Laurent THOMAS committed
1733 1734
      LOG_D(NR_MAC, "%4d.%2d no free CCE for UL DCI UE %04x\n", frame, slot, iterator->UE->rnti);
      iterator++;
1735 1736
      continue;
    }
Laurent THOMAS's avatar
Laurent THOMAS committed
1737
    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
1738

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

francescomani's avatar
francescomani committed
1741
    const uint16_t bwpSize = current_BWP->BWPSize;
Robert Schmidt's avatar
Robert Schmidt committed
1742
    NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch;
francescomani's avatar
francescomani committed
1743 1744 1745

    sched_pusch->nrOfLayers = 1;
    sched_pusch->time_domain_allocation = get_ul_tda(nrmac, scc, sched_pusch->slot);
francescomani's avatar
francescomani committed
1746 1747 1748 1749 1750
    sched_pusch->tda_info = nr_get_pusch_tda_info(current_BWP, sched_pusch->time_domain_allocation);
    sched_pusch->dmrs_info = get_ul_dmrs_params(scc,
                                                current_BWP,
                                                &sched_pusch->tda_info,
                                                sched_pusch->nrOfLayers);
1751

1752
    update_ul_ue_R_Qm(sched_pusch->mcs, current_BWP->mcs_table, current_BWP->pusch_Config, &sched_pusch->R, &sched_pusch->Qm);
ChiehChun's avatar
ChiehChun committed
1753

francescomani's avatar
francescomani committed
1754
    int rbStart = 0;
francescomani's avatar
francescomani committed
1755
    const uint16_t slbitmap = SL_to_bitmap(sched_pusch->tda_info.startSymbolIndex, sched_pusch->tda_info.nrOfSymbols);
1756
    while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap)
1757 1758 1759
      rbStart++;
    sched_pusch->rbStart = rbStart;
    uint16_t max_rbSize = 1;
1760
    while (rbStart + max_rbSize < bwpSize && (rballoc_mask[rbStart + max_rbSize] & slbitmap) == slbitmap)
1761 1762 1763
      max_rbSize++;

    if (rbStart + min_rb >= bwpSize) {
Laurent THOMAS's avatar
Laurent THOMAS committed
1764 1765
      LOG_W(NR_MAC, "cannot allocate UL data for RNTI %04x: no resources (rbStart %d, min_rb %d, bwpSize %d)\n",
	    iterator->UE->rnti,rbStart,min_rb,bwpSize);
1766 1767
      return;
    }
Laurent THOMAS's avatar
Laurent THOMAS committed
1768 1769
    else
      LOG_D(NR_MAC,"allocating UL data for RNTI %04x (rbStsart %d, min_rb %d, bwpSize %d)\n", iterator->UE->rnti,rbStart,min_rb,bwpSize);
1770

1771
    /* Calculate the current scheduling bytes */
ChiehChun's avatar
ChiehChun committed
1772
    const int B = cmax(sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes, 0);
francescomani's avatar
francescomani committed
1773 1774
    /* adjust rbSize and MCS according to PHR and BPRE */
    sched_pusch->mu  = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing;
francescomani's avatar
francescomani committed
1775 1776
    if(sched_ctrl->pcmax!=0 ||
       sched_ctrl->ph!=0) // verify if the PHR related parameter have been initialized
francescomani's avatar
francescomani committed
1777
      nr_ue_max_mcs_min_rb(current_BWP->scs, sched_ctrl->ph, sched_pusch, current_BWP, min_rbSize, B, &max_rbSize, &sched_pusch->mcs);
1778 1779 1780

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

1782 1783
    uint16_t rbSize = 0;
    uint32_t TBS = 0;
1784

1785 1786
    nr_find_nb_rb(sched_pusch->Qm,
                  sched_pusch->R,
1787
                  1, // layers
francescomani's avatar
francescomani committed
1788 1789
                  sched_pusch->tda_info.nrOfSymbols,
                  sched_pusch->dmrs_info.N_PRB_DMRS * sched_pusch->dmrs_info.num_dmrs_symb,
1790
                  B,
1791
                  min_rbSize,
1792 1793 1794
                  max_rbSize,
                  &TBS,
                  &rbSize);
francescomani's avatar
francescomani committed
1795

1796 1797
    sched_pusch->rbSize = rbSize;
    sched_pusch->tb_size = TBS;
1798
    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
1799 1800
          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
1801 1802

    /* Mark the corresponding RBs as used */
1803 1804 1805 1806

    sched_ctrl->cce_index = CCEIndex;
    fill_pdcch_vrb_map(RC.nrmac[module_id],
                       CC_id,
1807
                       &sched_ctrl->sched_pdcch,
1808 1809 1810
                       CCEIndex,
                       sched_ctrl->aggregation_level);

1811
    n_rb_sched -= sched_pusch->rbSize;
ChiehChun's avatar
ChiehChun committed
1812
    for (int rb = 0; rb < sched_ctrl->sched_pusch.rbSize; rb++)
1813
      rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] ^= slbitmap;
1814

Laurent THOMAS's avatar
Laurent THOMAS committed
1815 1816 1817
    /* reduce max_num_ue once we are sure UE can be allocated, i.e., has CCE */
    remainUEs--;
    iterator++;
1818 1819 1820
  }
}

1821 1822
bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t slot)
{
1823 1824 1825
  gNB_MAC_INST *nr_mac = RC.nrmac[module_id];
  NR_COMMON_channels_t *cc = nr_mac->common_channels;
  NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
1826 1827
  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;
1828 1829 1830

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

1831
  // no UEs
Laurent THOMAS's avatar
Laurent THOMAS committed
1832
  if (nr_mac->UE_info.list[0] == NULL)
1833
    return false;
1834 1835 1836

  const int CC_id = 0;

1837 1838 1839 1840
  /* 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
1841
  NR_UE_sched_ctrl_t *sched_ctrl = &nr_mac->UE_info.list[0]->UE_sched_ctrl;
francescomani's avatar
francescomani committed
1842 1843
  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
1844
  const int temp_tda = get_ul_tda(nr_mac, scc, slot);
francescomani's avatar
francescomani committed
1845
  int K2 = get_K2(current_BWP->tdaList, temp_tda, mu);
luis_pereira87's avatar
luis_pereira87 committed
1846
  const int sched_frame = (frame + (slot + K2 >= nr_slots_per_frame[mu])) & 1023;
ChiehChun's avatar
ChiehChun committed
1847
  const int sched_slot = (slot + K2) % nr_slots_per_frame[mu];
francescomani's avatar
francescomani committed
1848 1849 1850
  const int tda = get_ul_tda(nr_mac, scc, sched_slot);
  if (tda < 0)
    return false;
francescomani's avatar
francescomani committed
1851
  DevAssert(K2 == get_K2(current_BWP->tdaList, tda, mu));
1852

1853
  if (!is_xlsch_in_slot(nr_mac->ulsch_slot_bitmap[sched_slot / 64], sched_slot))
1854
    return false;
1855

1856
  // Avoid slots with the SRS
Laurent THOMAS's avatar
Laurent THOMAS committed
1857 1858
  UE_iterator(nr_mac->UE_info.list, UE) {
    NR_sched_srs_t sched_srs = UE->UE_sched_ctrl.sched_srs;
1859 1860 1861 1862 1863
    if(sched_srs.srs_scheduled && sched_srs.frame==sched_frame && sched_srs.slot==sched_slot) {
      return false;
    }
  }

1864 1865
  sched_ctrl->sched_pusch.slot = sched_slot;
  sched_ctrl->sched_pusch.frame = sched_frame;
Laurent THOMAS's avatar
Laurent THOMAS committed
1866 1867
  UE_iterator(nr_mac->UE_info.list, UE2) {
    NR_UE_sched_ctrl_t *sched_ctrl = &UE2->UE_sched_ctrl;
francescomani's avatar
francescomani committed
1868
    AssertFatal(K2 == get_K2(current_BWP->tdaList, tda, mu),
Laurent THOMAS's avatar
Laurent THOMAS committed
1869
                "Different K2, %d(UE%d) != %ld(UE%04x)\n",
francescomani's avatar
francescomani committed
1870
		K2, 0, get_K2(current_BWP->tdaList, tda, mu), UE2->rnti);
ChiehChun's avatar
ChiehChun committed
1871 1872
    sched_ctrl->sched_pusch.slot = sched_slot;
    sched_ctrl->sched_pusch.frame = sched_frame;
1873
  }
Robert Schmidt's avatar
Robert Schmidt committed
1874

1875 1876 1877
  /* 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 */
1878 1879
  uint16_t *vrb_map_UL =
      &RC.nrmac[module_id]->common_channels[CC_id].vrb_map_UL[sched_slot * MAX_BWP_SIZE];
1880

francescomani's avatar
francescomani committed
1881 1882
  const uint16_t bwpSize = current_BWP->BWPSize;
  const uint16_t bwpStart = current_BWP->BWPStart;
1883

francescomani's avatar
francescomani committed
1884
  const int startSymbolAndLength = current_BWP->tdaList->list.array[tda]->startSymbolAndLength;
1885 1886
  int startSymbolIndex, nrOfSymbols;
  SLIV2SL(startSymbolAndLength, &startSymbolIndex, &nrOfSymbols);
1887
  const uint16_t symb = SL_to_bitmap(startSymbolIndex, nrOfSymbols);
1888

1889
  int st = 0, e = 0, len = 0;
1890

1891
  for (int i = 0; i < bwpSize; i++) {
1892
    while ((vrb_map_UL[bwpStart + i] & symb) != 0 && i < bwpSize)
1893 1894
      i++;
    st = i;
1895
    while ((vrb_map_UL[bwpStart + i] & symb) == 0 && i < bwpSize)
1896 1897 1898 1899 1900
      i++;
    if (i - st > len) {
      len = i - st;
      e = i - 1;
    }
1901
  }
1902 1903
  st = e - len + 1;

Raymond Knopp's avatar
Raymond Knopp committed
1904
  LOG_D(NR_MAC,"UL %d.%d : start_prb %d, end PRB %d\n",frame,slot,st,e);
1905
  
1906
  uint16_t rballoc_mask[bwpSize];
1907 1908 1909

  /* 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++)
1910
    rballoc_mask[i] = (i >= st && i <= e)*SL_to_bitmap(startSymbolIndex, nrOfSymbols);
1911

ChiehChun's avatar
ChiehChun committed
1912 1913 1914 1915
  /* proportional fair scheduling algorithm */
  pf_ul(module_id,
        frame,
        slot,
Laurent THOMAS's avatar
Laurent THOMAS committed
1916
        nr_mac->UE_info.list,
1917
        2,
1918
        len,
1919
        rballoc_mask);
1920
  return true;
1921 1922
}

1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936
nr_pp_impl_ul nr_init_fr1_ulsch_preprocessor(module_id_t module_id, int CC_id)
{
  /* 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);
1937
      const uint16_t R = nr_get_code_rate_ul(mcs, mcsTableIdx);
1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955
      /* 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;
}

void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot)
{
  gNB_MAC_INST *nr_mac = RC.nrmac[module_id];
1956 1957
  /* 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 */
1958
  if (!is_xlsch_in_slot(nr_mac->dlsch_slot_bitmap[slot / 64], slot)) {
1959
    LOG_D(NR_MAC, "Current slot %d is NOT DL slot, cannot schedule DCI0 for UL data\n", slot);
1960 1961
    return;
  }
1962
  bool do_sched = RC.nrmac[module_id]->pre_processor_ul(module_id, frame, slot);
1963 1964
  if (!do_sched)
    return;
1965

1966 1967 1968 1969 1970 1971 1972
  const int CC_id = 0;
  nfapi_nr_ul_dci_request_t *ul_dci_req = &RC.nrmac[module_id]->UL_dci_req[CC_id];
  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 */
1973 1974
  nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_coreset[MAX_NUM_CORESET] = {0};

1975

1976
  NR_ServingCellConfigCommon_t *scc = RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon;
Laurent THOMAS's avatar
Laurent THOMAS committed
1977
  NR_UEs_t *UE_info = &RC.nrmac[module_id]->UE_info;
1978
  const NR_SIB1_t *sib1 = RC.nrmac[module_id]->common_channels[0].sib1 ? RC.nrmac[module_id]->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL;
Laurent THOMAS's avatar
Laurent THOMAS committed
1979 1980
  UE_iterator( UE_info->list, UE) {
    NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
1981
    if (sched_ctrl->ul_failure == 1 && get_softmodem_params()->phy_test==0) continue;
1982

Laurent THOMAS's avatar
Laurent THOMAS committed
1983
    NR_CellGroupConfig_t *cg = UE->CellGroup;
1984
    NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP;
1985

Laurent THOMAS's avatar
Laurent THOMAS committed
1986
    UE->mac_stats.ul.current_bytes = 0;
Robert Schmidt's avatar
Robert Schmidt committed
1987
    UE->mac_stats.ul.current_rbs = 0;
1988

1989 1990
    /* 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
1991
    NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch;
Laurent THOMAS's avatar
Laurent THOMAS committed
1992
    LOG_D(NR_MAC,"UE %04x : sched_pusch->rbSize %d\n",UE->rnti,sched_pusch->rbSize);
Robert Schmidt's avatar
Robert Schmidt committed
1993
    if (sched_pusch->rbSize <= 0)
1994 1995
      continue;

Laurent THOMAS's avatar
Laurent THOMAS committed
1996
    uint16_t rnti = UE->rnti;
Robert Schmidt's avatar
Robert Schmidt committed
1997
    sched_ctrl->SR = false;
1998

1999 2000 2001 2002 2003
    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
2004 2005
                  "no free HARQ process available for UE %04x\n",
                  UE->rnti);
2006
      remove_front_nr_list(&sched_ctrl->available_ul_harq);
2007
      sched_pusch->ul_harq_pid = harq_id;
2008 2009 2010 2011 2012 2013 2014 2015 2016
    } 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
2017
    NR_UE_ul_harq_t *cur_harq = &sched_ctrl->ul_harq_processes[harq_id];
2018 2019 2020 2021
    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
2022

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

2025
    /* Statistics */
2026
    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
2027
    UE->mac_stats.ul.rounds[cur_harq->round]++;
2028
    if (cur_harq->round == 0) {
Laurent THOMAS's avatar
Laurent THOMAS committed
2029
      UE->mac_stats.ulsch_total_bytes_scheduled += sched_pusch->tb_size;
2030 2031 2032
      /* 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;
2033 2034
      /* save which time allocation has been used, to be used on
       * retransmissions */
francescomani's avatar
francescomani committed
2035
      cur_harq->sched_pusch.time_domain_allocation = sched_pusch->time_domain_allocation;
2036
      sched_ctrl->sched_ul_bytes += sched_pusch->tb_size;
Robert Schmidt's avatar
Robert Schmidt committed
2037 2038
      UE->mac_stats.ul.total_rbs += sched_pusch->rbSize;

2039
    } else {
2040
      LOG_D(NR_MAC,
2041
            "%d.%2d UL retransmission RNTI %04x sched %d.%2d HARQ PID %d round %d NDI %d\n",
2042 2043 2044 2045 2046
            frame,
            slot,
            rnti,
            sched_pusch->frame,
            sched_pusch->slot,
2047 2048 2049
            harq_id,
            cur_harq->round,
            cur_harq->ndi);
Robert Schmidt's avatar
Robert Schmidt committed
2050
      UE->mac_stats.ul.total_rbs_retx += sched_pusch->rbSize;
2051
    }
Laurent THOMAS's avatar
Laurent THOMAS committed
2052
    UE->mac_stats.ul.current_bytes = sched_pusch->tb_size;
Robert Schmidt's avatar
Robert Schmidt committed
2053
    UE->mac_stats.ul.current_rbs = sched_pusch->rbSize;
2054 2055
    sched_ctrl->last_ul_frame = sched_pusch->frame;
    sched_ctrl->last_ul_slot = sched_pusch->slot;
2056

rmagueta's avatar
rmagueta committed
2057
    LOG_D(NR_MAC,
2058
          "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 %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",
2059 2060 2061 2062 2063
          frame,
          slot,
          rnti,
          sched_pusch->frame,
          sched_pusch->slot,
Eurecom's avatar
Eurecom committed
2064
          sched_ctrl->aggregation_level,
2065 2066
          sched_pusch->rbStart,
          sched_pusch->rbSize,
francescomani's avatar
francescomani committed
2067 2068 2069
          sched_pusch->tda_info.startSymbolIndex,
          sched_pusch->tda_info.nrOfSymbols,
          sched_pusch->dmrs_info.ul_dmrs_symb_pos,
2070
          sched_pusch->mcs,
francescomani's avatar
francescomani committed
2071 2072
          sched_pusch->nrOfLayers,
          sched_pusch->dmrs_info.num_dmrs_cdm_grps_no_data,
2073 2074 2075
          sched_pusch->tb_size,
          harq_id,
          cur_harq->round,
2076
          nr_rv_round_map[cur_harq->round%4],
2077 2078 2079
          cur_harq->ndi,
          sched_ctrl->estimated_ul_buffer,
          sched_ctrl->sched_ul_bytes,
2080 2081
          sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes,
          sched_ctrl->tpc0);
2082

2083
    /* PUSCH in a later slot, but corresponding DCI now! */
Robert Schmidt's avatar
Robert Schmidt committed
2084
    nfapi_nr_ul_tti_request_t *future_ul_tti_req = &RC.nrmac[module_id]->UL_tti_req_ahead[0][sched_pusch->slot];
2085 2086 2087 2088 2089 2090 2091 2092
    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);
2093 2094 2095
    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);
2096

2097 2098 2099 2100 2101 2102
    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;

2103
    LOG_D(NR_MAC, "%4d.%2d Scheduling UE specific PUSCH for sched %d.%d, ul_tti_req %d.%d\n", frame, slot,
2104
    sched_pusch->frame,sched_pusch->slot,future_ul_tti_req->SFN,future_ul_tti_req->Slot);
2105 2106 2107 2108 2109

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

2110
    /* FAPI: BWP */
2111

2112 2113 2114
    pusch_pdu->bwp_size  = current_BWP->BWPSize;
    pusch_pdu->bwp_start = current_BWP->BWPStart;
    pusch_pdu->subcarrier_spacing = current_BWP->scs;
2115 2116
    pusch_pdu->cyclic_prefix = 0;

2117
    /* FAPI: PUSCH information always included */
2118 2119 2120
    pusch_pdu->target_code_rate = sched_pusch->R;
    pusch_pdu->qam_mod_order = sched_pusch->Qm;
    pusch_pdu->mcs_index = sched_pusch->mcs;
2121 2122 2123 2124
    pusch_pdu->mcs_table = current_BWP->mcs_table;
    pusch_pdu->transform_precoding = current_BWP->transform_precoding;
    if (current_BWP->pusch_Config && current_BWP->pusch_Config->dataScramblingIdentityPUSCH)
      pusch_pdu->data_scrambling_id = *current_BWP->pusch_Config->dataScramblingIdentityPUSCH;
2125 2126
    else
      pusch_pdu->data_scrambling_id = *scc->physCellId;
francescomani's avatar
francescomani committed
2127 2128
    pusch_pdu->nrOfLayers = sched_pusch->nrOfLayers;
    pusch_pdu->num_dmrs_cdm_grps_no_data = sched_pusch->dmrs_info.num_dmrs_cdm_grps_no_data;
2129

2130
    /* FAPI: DMRS */
francescomani's avatar
francescomani committed
2131 2132 2133
    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;
    const NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig = sched_pusch->dmrs_info.NR_DMRS_UplinkConfig;
2134
    if (pusch_pdu->transform_precoding) { // transform precoding disabled
2135
      long *scramblingid=NULL;
francescomani's avatar
francescomani committed
2136 2137 2138 2139
      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;
2140 2141 2142 2143 2144 2145 2146
      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;
francescomani's avatar
francescomani committed
2147 2148 2149
      if (NR_DMRS_UplinkConfig && NR_DMRS_UplinkConfig->transformPrecodingEnabled->nPUSCH_Identity != NULL)
        pusch_pdu->pusch_identity = *NR_DMRS_UplinkConfig->transformPrecodingEnabled->nPUSCH_Identity;
      else if (NR_DMRS_UplinkConfig)
2150 2151
        pusch_pdu->pusch_identity = *scc->physCellId;
    }
2152
    pusch_pdu->scid = 0;      // DMRS sequence initialization [TS38.211, sec 6.4.1.1.1]
francescomani's avatar
francescomani committed
2153 2154
    pusch_pdu->num_dmrs_cdm_grps_no_data = sched_pusch->dmrs_info.num_dmrs_cdm_grps_no_data;
    pusch_pdu->dmrs_ports = ((1<<sched_pusch->nrOfLayers) - 1);
2155

2156 2157 2158 2159 2160
    /* 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;
2161
    if (current_BWP->pusch_Config==NULL || current_BWP->pusch_Config->frequencyHopping==NULL)
2162 2163 2164 2165 2166
      pusch_pdu->frequency_hopping = 0;
    else
      pusch_pdu->frequency_hopping = 1;

    /* FAPI: Resource Allocation in time domain */
francescomani's avatar
francescomani committed
2167 2168
    pusch_pdu->start_symbol_index = sched_pusch->tda_info.startSymbolIndex;
    pusch_pdu->nr_of_symbols = sched_pusch->tda_info.nrOfSymbols;
2169 2170

    /* PUSCH PDU */
2171
    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);
2172
    pusch_pdu->pusch_data.rv_index = nr_rv_round_map[cur_harq->round%4];
2173
    pusch_pdu->pusch_data.harq_process_id = harq_id;
2174
    pusch_pdu->pusch_data.new_data_indicator = (cur_harq->round == 0) ? 1 : 0;  // not NDI but indicator for new transmission
2175
    pusch_pdu->pusch_data.tb_size = sched_pusch->tb_size;
2176 2177
    pusch_pdu->pusch_data.num_cb = 0; //CBG not supported

2178
    pusch_pdu->maintenance_parms_v3.ldpcBaseGraph = get_BG(sched_pusch->tb_size<<3,sched_pusch->R);
2179 2180 2181 2182 2183 2184 2185 2186
    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");
      const int scc_bwpsize = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
francescomani's avatar
francescomani committed
2187
      int bw_tbslbrm = get_ulbw_tbslbrm(scc_bwpsize, cg);
2188 2189 2190 2191 2192 2193
      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;
2194

2195
    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);
2196 2197 2198 2199 2200 2201 2202 2203
    /* 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
francescomani's avatar
francescomani committed
2204 2205
      if ((NR_DMRS_UplinkConfig==NULL) || ((NR_DMRS_UplinkConfig->transformPrecodingEnabled->sequenceGroupHopping == NULL) &&
					       (NR_DMRS_UplinkConfig->transformPrecodingEnabled->sequenceHopping == NULL)))
2206 2207 2208 2209
        pusch_pdu->dfts_ofdm.low_papr_sequence_number = 0;
      else
        AssertFatal(1==0,"SequenceGroupHopping or sequenceHopping are NOT Supported\n");

2210
      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);
2211 2212 2213 2214
    }

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

2215
    /* PUSCH PTRS */
francescomani's avatar
francescomani committed
2216
    if (NR_DMRS_UplinkConfig && NR_DMRS_UplinkConfig->phaseTrackingRS != NULL) {
2217
      bool valid_ptrs_setup = false;
2218
      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
2219
      valid_ptrs_setup = set_ul_ptrs_values(NR_DMRS_UplinkConfig->phaseTrackingRS->choice.setup,
2220 2221 2222 2223 2224 2225 2226
                                            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
      }
2227 2228 2229 2230
    }
    else{
      pusch_pdu->pdu_bit_map &= ~PUSCH_PDU_BITMAP_PUSCH_PTRS; // disable PUSCH PTRS
    }
2231

2232 2233
    /* look up the PDCCH PDU for this BWP and CORESET. If it does not exist,
     * create it */
2234 2235
    NR_SearchSpace_t *ss = sched_ctrl->search_space;
    NR_ControlResourceSet_t *coreset = sched_ctrl->coreset;
2236
    const int coresetid = coreset->controlResourceSetId;
2237
    nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu = pdcch_pdu_coreset[coresetid];
2238 2239 2240 2241 2242 2243 2244
    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;
2245
      nr_configure_pdcch(pdcch_pdu, coreset, false, &sched_ctrl->sched_pdcch);
2246
      pdcch_pdu_coreset[coresetid] = pdcch_pdu;
2247
    }
2248

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

2251 2252 2253 2254
    /* 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;
2255 2256 2257
    if (coreset->pdcch_DMRS_ScramblingID &&
        ss->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_ue_Specific) {
      dci_pdu->ScramblingId = *coreset->pdcch_DMRS_ScramblingID;
2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269
      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));
2270

2271
    config_uldci(sib1,
2272
                 scc,
2273
                 pusch_pdu,
2274
                 &uldci_payload,
2275
                 &sched_ctrl->srs_feedback,
francescomani's avatar
francescomani committed
2276
                 sched_pusch->time_domain_allocation,
Laurent THOMAS's avatar
Laurent THOMAS committed
2277
                 UE->UE_sched_ctrl.tpc0,
2278
                 cur_harq->ndi,
2279
                 current_BWP);
2280

2281
    fill_dci_pdu_rel15(scc,
2282
                       cg,
2283
                       &UE->current_DL_BWP,
2284 2285
                       dci_pdu,
                       &uldci_payload,
2286
                       current_BWP->dci_format,
2287
                       rnti_types[0],
2288
                       pusch_pdu->bwp_size,
2289
                       current_BWP->bwp_id,
2290
                       coreset,
2291
                       nr_mac->cset0_bwp_size);
2292

Robert Schmidt's avatar
Robert Schmidt committed
2293
    memset(sched_pusch, 0, sizeof(*sched_pusch));
2294
  }
2295
}