nr_ue_scheduler.c 140 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        nr_ue_scheduler.c
 * \brief       Routines for UE scheduling
 * \author      Guido Casati
 * \date        Jan 2021
 * \version     0.1
 * \company     Fraunhofer IIS
 * \email       guido.casati@iis.fraunhofer.de
 */

#include <stdio.h>
#include <math.h>
33
#include <pthread.h>
34 35 36 37

/* exe */
#include <common/utils/nr/nr_common.h>

38 39 40
/* PHY */
#include "openair1/PHY/impl_defs_top.h"

41 42
/* MAC */
#include "NR_MAC_COMMON/nr_mac.h"
43
#include "NR_MAC_COMMON/nr_mac_common.h"
44 45 46 47 48
#include "NR_MAC_UE/mac_proto.h"
#include "NR_MAC_UE/mac_extern.h"

/* utils */
#include "assertions.h"
49
#include "oai_asn1.h"
50
#include "SIMULATION/TOOLS/sim.h" // for taus
51
#include "utils.h"
52

53 54
#include <executables/softmodem-common.h>

55
#include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h"
56
#include "LAYER2/RLC/rlc.h"
mjoang's avatar
mjoang committed
57

58 59
//#define SRS_DEBUG

60
static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, sub_frame_t slotP);
61
static void schedule_ta_command(fapi_nr_dl_config_request_t *dl_config, NR_UL_TIME_ALIGNMENT_t *ul_time_alignment);
62

63
fapi_nr_ul_config_request_pdu_t *lockGet_ul_config(NR_UE_MAC_INST_t *mac, frame_t frame_tx, int slot_tx, uint8_t pdu_type)
64
{
65 66 67 68 69 70 71 72 73 74 75
  NR_TDD_UL_DL_ConfigCommon_t *tdd_config = mac->tdd_UL_DL_ConfigurationCommon;

  // Check if requested on the right slot
  AssertFatal(is_nr_UL_slot(tdd_config, slot_tx, mac->frame_type) != 0, "UL config_request called at wrong slot %d\n", slot_tx);

  AssertFatal(mac->ul_config_request != NULL, "mac->ul_config_request not initialized, logic bug\n");
  fapi_nr_ul_config_request_t *ul_config = mac->ul_config_request + slot_tx;

  pthread_mutex_lock(&ul_config->mutex_ul_config);
  if (ul_config->number_pdus != 0 && (ul_config->frame != frame_tx || ul_config->slot != slot_tx)) {
    LOG_E(NR_MAC, "Error in ul config consistency, clearing slot %d\n", slot_tx);
76 77
    ul_config->number_pdus = 0;
  }
78
  ul_config->frame = frame_tx;
79 80 81 82 83 84 85 86 87 88 89 90 91 92
  ul_config->slot = slot_tx;
  if (ul_config->number_pdus >= FAPI_NR_UL_CONFIG_LIST_NUM) {
    LOG_E(NR_MAC, "Error in ul config for slot %d, no memory\n", slot_tx);
    pthread_mutex_unlock(&ul_config->mutex_ul_config);
    return NULL;
  }
  fapi_nr_ul_config_request_pdu_t *pdu = ul_config->ul_config_list + ul_config->number_pdus++;
  pdu->pdu_type = pdu_type;
  AssertFatal(!pdu->lock, "no lock in fapi_nr_ul_config_request_pdu_t, aborting");
  pdu->lock = &ul_config->mutex_ul_config;
  pdu->privateNBpdus = &ul_config->number_pdus;
  LOG_D(NR_MAC, "Added ul pdu for %d.%d, type %d\n", frame_tx, slot_tx, pdu_type);
  return pdu;
}
93

94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
static nr_lcordered_info_t *get_lc_info_from_lcid(NR_UE_MAC_INST_t *mac, NR_LogicalChannelIdentity_t lcid)
{
  nr_lcordered_info_t *lc_info = NULL;
  for (int i = 0; i < mac->lc_ordered_list.count; i++) {
    if (mac->lc_ordered_list.array[i]->lcid == lcid) {
      lc_info = mac->lc_ordered_list.array[i];
      break;
    }
  }
  return lc_info;
}

static int lcid_buffer_index(NR_LogicalChannelIdentity_t lcid)
{
  AssertFatal(lcid > 0 && lcid <= NR_MAX_NUM_LCID, "Invalid LCID %ld\n", lcid);
  return lcid - 1;
}

112
NR_LC_SCHEDULING_INFO *get_scheduling_info_from_lcid(NR_UE_MAC_INST_t *mac, NR_LogicalChannelIdentity_t lcid)
113 114 115 116 117
{
  int idx = lcid_buffer_index(lcid);
  return &mac->scheduling_info.lc_sched_info[idx];
}

118
static void trigger_regular_bsr(NR_UE_MAC_INST_t *mac, NR_LogicalChannelIdentity_t lcid, bool sr_DelayTimerApplied)
119 120
{
  // Regular BSR trigger
121 122 123
  mac->scheduling_info.BSR_reporting_active |= NR_BSR_TRIGGER_REGULAR;
  mac->scheduling_info.regularBSR_trigger_lcid = lcid;
  LOG_D(NR_MAC, "Triggering regular BSR for LCID %ld\n", lcid);
124 125 126 127 128 129 130 131 132
  // if the BSR is triggered for a logical channel for which logicalChannelSR-DelayTimerApplied with value true
  // start or restart the logicalChannelSR-DelayTimer
  // else stop the logicalChannelSR-DelayTimer
  if (sr_DelayTimerApplied)
    nr_timer_start(&mac->scheduling_info.sr_DelayTimer);
  else
    nr_timer_stop(&mac->scheduling_info.sr_DelayTimer);
}

133 134 135
void update_mac_timers(NR_UE_MAC_INST_t *mac)
{
  nr_timer_tick(&mac->ra.contention_resolution_timer);
136
  nr_timer_tick(&mac->scheduling_info.sr_DelayTimer);
137 138 139 140 141 142 143 144
  bool retxBSR_expired = nr_timer_tick(&mac->scheduling_info.retxBSR_Timer);
  if (retxBSR_expired) {
    LOG_D(NR_MAC, "retxBSR timer expired\n");
    for (int i = 0; i < mac->lc_ordered_list.count; i++) {
      nr_lcordered_info_t *lc_info = mac->lc_ordered_list.array[i];
      NR_LogicalChannelIdentity_t lcid = lc_info->lcid;
      // if at least one of the logical channels which belong to an LCG contains UL data
      NR_LC_SCHEDULING_INFO *lc_sched_info = get_scheduling_info_from_lcid(mac, lcid);
145
      if (lc_sched_info->LCGID != NR_INVALID_LCGID && lc_sched_info->LCID_buffer_remain > 0) {
146
        LOG_D(NR_MAC, "Triggering regular BSR after retxBSR timer expired\n");
147 148
        trigger_regular_bsr(mac, lcid, lc_info->sr_DelayTimerApplied);
        break;
149 150 151
      }
    }
  }
152 153 154
  bool periodicBSR_expired = nr_timer_tick(&mac->scheduling_info.periodicBSR_Timer);
  if (periodicBSR_expired) {
    // periodicBSR-Timer expires, trigger BSR
155
    mac->scheduling_info.BSR_reporting_active |= NR_BSR_TRIGGER_PERIODIC;
156 157
    LOG_D(NR_MAC, "[UE %d] MAC BSR Triggered PeriodicBSR Timer expiry\n", mac->ue_id);
  }
158 159 160 161
  for (int i = 0; i < NR_MAX_NUM_LCID; i++)
    AssertFatal(!nr_timer_tick(&mac->scheduling_info.lc_sched_info[i].Bj_timer),
                "Bj timer for LCID %d expired! That should never happen\n",
                i);
162 163
}

164 165 166
void remove_ul_config_last_item(fapi_nr_ul_config_request_pdu_t *pdu)
{
  pdu->privateNBpdus--;
167 168
}

169
void release_ul_config(fapi_nr_ul_config_request_pdu_t *configPerSlot, bool clearIt)
170
{
171 172 173 174 175 176
  pthread_mutex_t *lock = configPerSlot->lock;
  configPerSlot->lock = NULL;
  if (clearIt)
    *configPerSlot->privateNBpdus = 0;
  pthread_mutex_unlock(lock);
}
francescomani's avatar
francescomani committed
177

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
fapi_nr_ul_config_request_pdu_t *fapiLockIterator(fapi_nr_ul_config_request_t *ul_config, frame_t frame_tx, int slot_tx)
{
  pthread_mutex_lock(&ul_config->mutex_ul_config);
  if (ul_config->number_pdus >= FAPI_NR_UL_CONFIG_LIST_NUM) {
    LOG_E(NR_MAC, "Error in ul config in slot %d no memory\n", ul_config->slot);
    pthread_mutex_unlock(&ul_config->mutex_ul_config);
    return NULL;
  }
  if (ul_config->number_pdus != 0 && (ul_config->frame != frame_tx || ul_config->slot != slot_tx)) {
    LOG_E(NR_MAC, "Error in ul config consistency, clearing it slot %d\n", slot_tx);
    ul_config->number_pdus = 0;
    pthread_mutex_unlock(&ul_config->mutex_ul_config);
    return NULL;
  }
  if (ul_config->number_pdus >= FAPI_NR_UL_CONFIG_LIST_NUM) {
    LOG_E(NR_MAC, "Error in ul config for slot %d, no memory\n", slot_tx);
    pthread_mutex_unlock(&ul_config->mutex_ul_config);
    return NULL;
  }
  fapi_nr_ul_config_request_pdu_t *pdu = ul_config->ul_config_list + ul_config->number_pdus;
  pdu->pdu_type = FAPI_NR_END;
  pdu->lock = &ul_config->mutex_ul_config;
  pdu->privateNBpdus = &ul_config->number_pdus;
  return ul_config->ul_config_list;
}
203

204 205 206
fapi_nr_ul_config_request_pdu_t *lockGet_ul_iterator(NR_UE_MAC_INST_t *mac, frame_t frame_tx, int slot_tx)
{
  NR_TDD_UL_DL_ConfigCommon_t *tdd_config = mac->tdd_UL_DL_ConfigurationCommon;
207
  //Check if requested on the right slot
208
  AssertFatal(is_nr_UL_slot(tdd_config, slot_tx, mac->frame_type) != 0, "UL config_request called at wrong slot %d\n", slot_tx);
francescomani's avatar
francescomani committed
209
  AssertFatal(mac->ul_config_request != NULL, "mac->ul_config_request not initialized, logic bug\n");
210
  return fapiLockIterator(mac->ul_config_request + slot_tx, frame_tx, slot_tx);
211 212 213 214 215 216 217 218
}

/*
 * This function returns the DL config corresponding to a given DL slot
 * from MAC instance .
 */
fapi_nr_dl_config_request_t *get_dl_config_request(NR_UE_MAC_INST_t *mac, int slot)
{
francescomani's avatar
francescomani committed
219 220
  AssertFatal(mac->dl_config_request != NULL, "mac->dl_config_request not initialized, logic bug\n");
  return &mac->dl_config_request[slot];
221 222
}

223
void ul_layers_config(NR_UE_MAC_INST_t *mac, nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu, dci_pdu_rel15_t *dci, nr_dci_format_t dci_format)
224
{
225
  NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
226
  NR_SRS_Config_t *srs_config = current_UL_BWP->srs_Config;
227
  NR_PUSCH_Config_t *pusch_Config = current_UL_BWP->pusch_Config;
228

229
  long transformPrecoder = pusch_config_pdu->transform_precoding;
230

231 232 233
  /* PRECOD_NBR_LAYERS */
  // 0 bits if the higher layer parameter txConfig = nonCodeBook

234
  if (*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook){
235

236 237 238 239
    // The UE shall transmit PUSCH using the same antenna port(s) as the SRS port(s) in the SRS resource indicated by the DCI format 0_1
    // 38.214  Section 6.1.1

    uint8_t n_antenna_port = get_pusch_nb_antenna_ports(pusch_Config, srs_config, dci->srs_resource_indicator);
240

241
    // 1 antenna port and the higher layer parameter txConfig = codebook 0 bits
242

francescomani's avatar
francescomani committed
243
    if (n_antenna_port == 4) { // 4 antenna port and the higher layer parameter txConfig = codebook
244 245

      // Table 7.3.1.1.2-2: transformPrecoder=disabled and maxRank = 2 or 3 or 4
246
      if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled)
247
          && ((*pusch_Config->maxRank == 2) || (*pusch_Config->maxRank == 3) || (*pusch_Config->maxRank == 4))) {
248
        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) {
249
          pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][0];
250
          pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][1];
251 252
        }

253
        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent){
254
          pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][2];
255
          pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][3];
256 257
        }

258
        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent){
259
          pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][4];
260
          pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][5];
261 262 263 264
        }
      }

      // Table 7.3.1.1.2-3: transformPrecoder= enabled, or transformPrecoder=disabled and maxRank = 1
265
      if (((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled)
266 267
           || (transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled))
          && (*pusch_Config->maxRank == 1)) {
268
        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) {
269
          pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][6];
270
          pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][7];
271 272
        }

273
        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent){
274
          pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][8];
275
          pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][9];
276 277
        }

278
        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent){
279
          pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][10];
280
          pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][11];
281 282 283 284
        }
      }
    }

francescomani's avatar
francescomani committed
285 286
    if (n_antenna_port == 2) {
      // 2 antenna port and the higher layer parameter txConfig = codebook
287
      // Table 7.3.1.1.2-4: transformPrecoder=disabled and maxRank = 2
francescomani's avatar
francescomani committed
288
      if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (*pusch_Config->maxRank == 2)) {
289
        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) {
290
          pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][12];
291
          pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][13];
292 293
        }

294
        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent){
295
          pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][14];
296
          pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][15];
297 298 299 300 301
        }

      }

      // Table 7.3.1.1.2-5: transformPrecoder= enabled, or transformPrecoder= disabled and maxRank = 1
302
      if (((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled)
303 304
           || (transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled))
          && (*pusch_Config->maxRank == 1)) {
305
        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) {
306
          pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][16];
307
          pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][17];
308 309
        }

310
        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent){
311
          pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][18];
312
          pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][19];
313 314 315 316 317 318 319
        }
      }
    }
  }
}

// todo: this function shall be reviewed completely because of the many comments left by the author
320 321
void ul_ports_config(NR_UE_MAC_INST_t *mac, int *n_front_load_symb, nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu, dci_pdu_rel15_t *dci, nr_dci_format_t dci_format)
{
322
  uint8_t rank = pusch_config_pdu->nrOfLayers;
323

324
  NR_PUSCH_Config_t *pusch_Config = mac->current_UL_BWP->pusch_Config;
325
  AssertFatal(pusch_Config!=NULL,"pusch_Config shouldn't be null\n");
326

327 328 329
  long transformPrecoder = pusch_config_pdu->transform_precoding;
  LOG_D(NR_MAC,"transformPrecoder %s\n", transformPrecoder==NR_PUSCH_Config__transformPrecoder_disabled ? "disabled" : "enabled");

330 331 332 333 334 335 336 337 338 339 340
  long *max_length = NULL;
  long *dmrs_type = NULL;
  if (pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA) {
    max_length = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup->maxLength;
    dmrs_type = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup->dmrs_Type;
  }
  else {
    max_length = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->maxLength;
    dmrs_type = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->dmrs_Type;
  }

francescomani's avatar
francescomani committed
341 342
  LOG_D(NR_MAC,"MappingType%s max_length %s, dmrs_type %s, antenna_ports %d\n",
        pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA?"A":"B",max_length?"len2":"len1",dmrs_type?"type2":"type1",dci->antenna_ports.val);
343

344
  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) &&
345
      (dmrs_type == NULL) && (max_length == NULL)) { // tables 7.3.1.1.2-6
346 347
    pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2;
    pusch_config_pdu->dmrs_ports = 1 << dci->antenna_ports.val;
348 349
  }

350
  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) &&
351
      (dmrs_type == NULL) && (max_length != NULL)) { // tables 7.3.1.1.2-7
352 353

    pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; //TBC
354 355
    pusch_config_pdu->dmrs_ports = 1<<((dci->antenna_ports.val > 3)?(dci->antenna_ports.val-4):(dci->antenna_ports.val));
    *n_front_load_symb = (dci->antenna_ports.val > 3)?2:1;
356 357
  }

358 359
  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (dmrs_type == NULL)
      && (max_length == NULL)) { // tables 7.3.1.1.2-8/9/10/11
360 361

    if (rank == 1) {
362 363
      pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 1)?2:1;
      pusch_config_pdu->dmrs_ports =1<<((dci->antenna_ports.val > 1)?(dci->antenna_ports.val-2):(dci->antenna_ports.val));
364 365 366
    }

    if (rank == 2){
367 368
      pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 0)?2:1;
      pusch_config_pdu->dmrs_ports = (dci->antenna_ports.val > 1)?((dci->antenna_ports.val> 2)?0x5:0xc):0x3;
369 370 371
    }

    if (rank == 3){
372
      pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2;
373
      pusch_config_pdu->dmrs_ports = 0x7;  // ports 0-2
374 375 376
    }

    if (rank == 4){
377
      pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2;
378
      pusch_config_pdu->dmrs_ports = 0xf;  // ports 0-3
379 380 381
    }
  }

382 383
  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (dmrs_type == NULL)
      && (max_length != NULL)) { // tables 7.3.1.1.2-12/13/14/15
384 385 386

    if (rank == 1){
      pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 1)?2:1; //TBC
387 388
      pusch_config_pdu->dmrs_ports = 1<<((dci->antenna_ports.val > 1)?(dci->antenna_ports.val > 5 ?(dci->antenna_ports.val-6):(dci->antenna_ports.val-2)):dci->antenna_ports.val);
      *n_front_load_symb = (dci->antenna_ports.val > 6)?2:1;
389 390 391 392 393 394 395
    }

    if (rank == 2){
      pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 0)?2:1; //TBC
      pusch_config_pdu->dmrs_ports = 0; //FIXME
      //pusch_config_pdu->dmrs_ports[0] = table_7_3_1_1_2_13[dci->antenna_ports.val][1];
      //pusch_config_pdu->dmrs_ports[1] = table_7_3_1_1_2_13[dci->antenna_ports.val][2];
396
      //n_front_load_symb = (dci->antenna_ports.val > 3)?2:1; // FIXME
397 398 399 400 401 402 403 404
    }

    if (rank == 3){
      pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; //TBC
      pusch_config_pdu->dmrs_ports = 0; //FIXME
      //pusch_config_pdu->dmrs_ports[0] = table_7_3_1_1_2_14[dci->antenna_ports.val][1];
      //pusch_config_pdu->dmrs_ports[1] = table_7_3_1_1_2_14[dci->antenna_ports.val][2];
      //pusch_config_pdu->dmrs_ports[2] = table_7_3_1_1_2_14[dci->antenna_ports.val][3];
405
      //n_front_load_symb = (dci->antenna_ports.val > 1)?2:1; //FIXME
406 407 408 409 410 411 412 413 414
    }

    if (rank == 4){
      pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; //TBC
      pusch_config_pdu->dmrs_ports = 0; //FIXME
      //pusch_config_pdu->dmrs_ports[0] = table_7_3_1_1_2_15[dci->antenna_ports.val][1];
      //pusch_config_pdu->dmrs_ports[1] = table_7_3_1_1_2_15[dci->antenna_ports.val][2];
      //pusch_config_pdu->dmrs_ports[2] = table_7_3_1_1_2_15[dci->antenna_ports.val][3];
      //pusch_config_pdu->dmrs_ports[3] = table_7_3_1_1_2_15[dci->antenna_ports.val][4];
415
      //n_front_load_symb = (dci->antenna_ports.val > 1)?2:1; //FIXME
416 417 418
    }
  }

419 420
  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (dmrs_type != NULL)
      && (max_length == NULL)) { // tables 7.3.1.1.2-16/17/18/19
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451

    if (rank == 1){
      pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 1)?((dci->antenna_ports.val > 5)?3:2):1; //TBC
      pusch_config_pdu->dmrs_ports = (dci->antenna_ports.val > 1)?(dci->antenna_ports.val > 5 ?(dci->antenna_ports.val-6):(dci->antenna_ports.val-2)):dci->antenna_ports.val; //TBC
    }

    if (rank == 2){
      pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 0)?((dci->antenna_ports.val > 2)?3:2):1; //TBC
      pusch_config_pdu->dmrs_ports = 0; //FIXME
      //pusch_config_pdu->dmrs_ports[0] = table_7_3_1_1_2_17[dci->antenna_ports.val][1];
      //pusch_config_pdu->dmrs_ports[1] = table_7_3_1_1_2_17[dci->antenna_ports.val][2];
    }

    if (rank == 3){
      pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 0)?3:2; //TBC
      pusch_config_pdu->dmrs_ports = 0; //FIXME
      //pusch_config_pdu->dmrs_ports[0] = table_7_3_1_1_2_18[dci->antenna_ports.val][1];
      //pusch_config_pdu->dmrs_ports[1] = table_7_3_1_1_2_18[dci->antenna_ports.val][2];
      //pusch_config_pdu->dmrs_ports[2] = table_7_3_1_1_2_18[dci->antenna_ports.val][3];
    }

    if (rank == 4){
      pusch_config_pdu->num_dmrs_cdm_grps_no_data = dci->antenna_ports.val + 2; //TBC
      pusch_config_pdu->dmrs_ports = 0; //FIXME
      //pusch_config_pdu->dmrs_ports[0] = 0;
      //pusch_config_pdu->dmrs_ports[1] = 1;
      //pusch_config_pdu->dmrs_ports[2] = 2;
      //pusch_config_pdu->dmrs_ports[3] = 3;
    }
  }

452 453
  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (dmrs_type != NULL)
      && (max_length != NULL)) { // tables 7.3.1.1.2-20/21/22/23
454 455 456 457

    if (rank == 1){
      pusch_config_pdu->num_dmrs_cdm_grps_no_data = table_7_3_1_1_2_20[dci->antenna_ports.val][0]; //TBC
      pusch_config_pdu->dmrs_ports = table_7_3_1_1_2_20[dci->antenna_ports.val][1]; //TBC
458
      //n_front_load_symb = table_7_3_1_1_2_20[dci->antenna_ports.val][2]; //FIXME
459 460 461 462 463 464 465
    }

    if (rank == 2){
      pusch_config_pdu->num_dmrs_cdm_grps_no_data = table_7_3_1_1_2_21[dci->antenna_ports.val][0]; //TBC
      pusch_config_pdu->dmrs_ports = 0; //FIXME
      //pusch_config_pdu->dmrs_ports[0] = table_7_3_1_1_2_21[dci->antenna_ports.val][1];
      //pusch_config_pdu->dmrs_ports[1] = table_7_3_1_1_2_21[dci->antenna_ports.val][2];
466
      //n_front_load_symb = table_7_3_1_1_2_21[dci->antenna_ports.val][3]; //FIXME
467
    }
468 469 470 471 472 473 474

    if (rank == 3){
      pusch_config_pdu->num_dmrs_cdm_grps_no_data = table_7_3_1_1_2_22[dci->antenna_ports.val][0]; //TBC
      pusch_config_pdu->dmrs_ports = 0; //FIXME
      //pusch_config_pdu->dmrs_ports[0] = table_7_3_1_1_2_22[dci->antenna_ports.val][1];
      //pusch_config_pdu->dmrs_ports[1] = table_7_3_1_1_2_22[dci->antenna_ports.val][2];
      //pusch_config_pdu->dmrs_ports[2] = table_7_3_1_1_2_22[dci->antenna_ports.val][3];
475
      //n_front_load_symb = table_7_3_1_1_2_22[dci->antenna_ports.val][4]; //FIXME
476 477 478 479 480 481 482 483 484
    }

    if (rank == 4){
      pusch_config_pdu->num_dmrs_cdm_grps_no_data = table_7_3_1_1_2_23[dci->antenna_ports.val][0]; //TBC
      pusch_config_pdu->dmrs_ports = 0; //FIXME
      //pusch_config_pdu->dmrs_ports[0] = table_7_3_1_1_2_23[dci->antenna_ports.val][1];
      //pusch_config_pdu->dmrs_ports[1] = table_7_3_1_1_2_23[dci->antenna_ports.val][2];
      //pusch_config_pdu->dmrs_ports[2] = table_7_3_1_1_2_23[dci->antenna_ports.val][3];
      //pusch_config_pdu->dmrs_ports[3] = table_7_3_1_1_2_23[dci->antenna_ports.val][4];
485
      //n_front_load_symb = table_7_3_1_1_2_23[dci->antenna_ports.val][5]; //FIXME
486 487
    }
  }
488
  LOG_D(NR_MAC,"num_dmrs_cdm_grps_no_data %d, dmrs_ports %d\n",pusch_config_pdu->num_dmrs_cdm_grps_no_data,pusch_config_pdu->dmrs_ports);
489 490 491 492 493 494 495 496 497 498
}

// Configuration of Msg3 PDU according to clauses:
// - 8.3 of 3GPP TS 38.213 version 16.3.0 Release 16
// - 6.1.2.2 of TS 38.214
// - 6.1.3 of TS 38.214
// - 6.2.2 of TS 38.214
// - 6.1.4.2 of TS 38.214
// - 6.4.1.1.1 of TS 38.211
// - 6.3.1.7 of 38.211
499 500 501 502 503 504
int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac,
                        NR_tda_info_t *tda_info,
                        nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu,
                        dci_pdu_rel15_t *dci,
                        RAR_grant_t *rar_grant,
                        uint16_t rnti,
505
                        int ss_type,
506
                        const nr_dci_format_t dci_format)
507
{
508 509
  uint16_t l_prime_mask = 0;
  int N_PRB_oh  = 0;
510 511

  int rnti_type = get_rnti_type(mac, rnti);
512
  NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
513
  NR_UE_ServingCell_Info_t *sc_info = &mac->sc_info;
514 515 516

  // Common configuration
  pusch_config_pdu->dmrs_config_type = pusch_dmrs_type1;
517 518 519 520
  pusch_config_pdu->pdu_bit_map = PUSCH_PDU_BITMAP_PUSCH_DATA;
  pusch_config_pdu->nrOfLayers = 1;
  pusch_config_pdu->Tpmi = 0;
  pusch_config_pdu->rnti = rnti;
521

522
  pusch_dmrs_AdditionalPosition_t add_pos = pusch_dmrs_pos2;
523
  int dmrslength = 1;
524
  NR_PUSCH_Config_t *pusch_Config = current_UL_BWP->pusch_Config;
525

526 527 528
  if (rar_grant) {

    // Note: for Msg3 or MsgA PUSCH transmission the N_PRB_oh is always set to 0
529 530
    int ibwp_start = sc_info->initial_ul_BWPStart;
    int ibwp_size = sc_info->initial_ul_BWPSize;
531 532 533
    int abwp_start = current_UL_BWP->BWPStart;
    int abwp_size = current_UL_BWP->BWPSize;
    int scs = current_UL_BWP->scs;
534

535
    // BWP start selection according to 8.3 of TS 38.213
536
    if ((ibwp_start < abwp_start) || (ibwp_size > abwp_size)) {
537
      pusch_config_pdu->bwp_start = abwp_start;
538 539
      pusch_config_pdu->bwp_size = abwp_size;
    } else {
540
      pusch_config_pdu->bwp_start = ibwp_start;
541 542
      pusch_config_pdu->bwp_size = ibwp_size;
    }
543 544 545

    //// Resource assignment from RAR
    // Frequency domain allocation according to 8.3 of TS 38.213
546
    int mask;
547 548 549 550
    if (ibwp_size < 180)
      mask = (1 << ((int) ceil(log2((ibwp_size*(ibwp_size+1))>>1)))) - 1;
    else
      mask = (1 << (28 - (int)(ceil(log2((ibwp_size*(ibwp_size+1))>>1))))) - 1;
551

552 553 554 555 556 557 558 559
    dci_field_t f_alloc;
    f_alloc.val = rar_grant->Msg3_f_alloc & mask;
    if (nr_ue_process_dci_freq_dom_resource_assignment(pusch_config_pdu,
                                                       NULL,
                                                       NULL,
                                                       ibwp_size,
                                                       0,
                                                       0,
560
                                                       f_alloc) < 0) {
561
      LOG_E(NR_MAC, "can't nr_ue_process_dci_freq_dom_resource_assignment()\n");
562
      return -1;
563
    }
564 565

    // virtual resource block to physical resource mapping for Msg3 PUSCH (6.3.1.7 in 38.211)
566
    //pusch_config_pdu->rb_start += ibwp_start - abwp_start;
567 568

    // Time domain allocation
569 570
    pusch_config_pdu->start_symbol_index = tda_info->startSymbolIndex;
    pusch_config_pdu->nr_of_symbols = tda_info->nrOfSymbols;
571

572 573 574 575 576 577
    l_prime_mask = get_l_prime(tda_info->nrOfSymbols,
                               tda_info->mapping_type,
                               add_pos,
                               dmrslength,
                               tda_info->startSymbolIndex,
                               mac->dmrs_TypeA_Position);
578
    LOG_D(NR_MAC, "MSG3 start_sym:%d NR Symb:%d mappingtype:%d, DMRS_MASK:%x\n", pusch_config_pdu->start_symbol_index, pusch_config_pdu->nr_of_symbols, tda_info->mapping_type, l_prime_mask);
579

580
#ifdef DEBUG_MSG3
581
    LOG_D(NR_MAC, "In %s BWP assignment (BWP (start %d, size %d) \n", __FUNCTION__, pusch_config_pdu->bwp_start, pusch_config_pdu->bwp_size);
582
#endif
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597

    // MCS
    pusch_config_pdu->mcs_index = rar_grant->mcs;
    // Frequency hopping
    pusch_config_pdu->frequency_hopping = rar_grant->freq_hopping;

    // DM-RS configuration according to 6.2.2 UE DM-RS transmission procedure in 38.214
    pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2;
    pusch_config_pdu->dmrs_ports = 1;

    // DMRS sequence initialization [TS 38.211, sec 6.4.1.1.1].
    // Should match what is sent in DCI 0_1, otherwise set to 0.
    pusch_config_pdu->scid = 0;

    // Transform precoding according to 6.1.3 UE procedure for applying transform precoding on PUSCH in 38.214
598
    pusch_config_pdu->transform_precoding = get_transformPrecoding(current_UL_BWP, NR_UL_DCI_FORMAT_0_0, 0); // as if it was DCI 0_0
599 600

    // Resource allocation in frequency domain according to 6.1.2.2 in TS 38.214
601
    pusch_config_pdu->resource_alloc = 1;
602 603 604 605

    //// Completing PUSCH PDU
    pusch_config_pdu->mcs_table = 0;
    pusch_config_pdu->cyclic_prefix = 0;
606 607 608
    pusch_config_pdu->data_scrambling_id = mac->physCellId;
    pusch_config_pdu->ul_dmrs_scrambling_id = mac->physCellId;
    pusch_config_pdu->subcarrier_spacing = scs;
609 610 611 612 613
    pusch_config_pdu->vrb_to_prb_mapping = 0;
    pusch_config_pdu->uplink_frequency_shift_7p5khz = 0;
    //Optional Data only included if indicated in pduBitmap
    pusch_config_pdu->pusch_data.rv_index = 0;  // 8.3 in 38.213
    pusch_config_pdu->pusch_data.harq_process_id = 0;
614
    pusch_config_pdu->pusch_data.new_data_indicator = true; // new data
615
    pusch_config_pdu->pusch_data.num_cb = 0;
616
    pusch_config_pdu->tbslbrm = 0;
617 618

  } else if (dci) {
francescomani's avatar
francescomani committed
619 620
    pusch_config_pdu->bwp_start = current_UL_BWP->BWPStart;
    pusch_config_pdu->bwp_size = current_UL_BWP->BWPSize;
621

622 623 624
    pusch_config_pdu->start_symbol_index = tda_info->startSymbolIndex;
    pusch_config_pdu->nr_of_symbols = tda_info->nrOfSymbols;

625
    /* Transform precoding */
626
    pusch_config_pdu->transform_precoding = get_transformPrecoding(current_UL_BWP, dci_format, 0);
627 628

    /*DCI format-related configuration*/
629
    if (dci_format == NR_UL_DCI_FORMAT_0_0) {
630 631 632 633 634
      if ((pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_disabled) &&
          pusch_config_pdu->nr_of_symbols < 3)
        pusch_config_pdu->num_dmrs_cdm_grps_no_data = 1;
      else
        pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2;
635 636 637
    } else if (dci_format == NR_UL_DCI_FORMAT_0_1) {
      ul_layers_config(mac, pusch_config_pdu, dci, dci_format);
      ul_ports_config(mac, &dmrslength, pusch_config_pdu, dci, dci_format);
638
    } else {
639
      LOG_E(NR_MAC, "In %s: UL grant from DCI format %d is not handled...\n", __FUNCTION__, dci_format);
640 641 642
      return -1;
    }

643
    int mappingtype = tda_info->mapping_type;
644 645

    NR_DMRS_UplinkConfig_t *NR_DMRS_ulconfig = NULL;
646 647
    if(pusch_Config) {
      NR_DMRS_ulconfig = (mappingtype == NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeA)
648 649
                             ? pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup
                             : pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup;
650
    }
651

652
    pusch_config_pdu->scid = 0;
653
    pusch_config_pdu->data_scrambling_id = mac->physCellId;
654 655
    if (pusch_Config
        && pusch_Config->dataScramblingIdentityPUSCH
656 657 658 659
        && rnti_type == TYPE_C_RNTI_
        && !(dci_format == NR_UL_DCI_FORMAT_0_0 && ss_type == NR_SearchSpace__searchSpaceType_PR_common))
      pusch_config_pdu->data_scrambling_id = *pusch_Config->dataScramblingIdentityPUSCH;

660
    pusch_config_pdu->ul_dmrs_scrambling_id = mac->physCellId;
661
    if (dci_format == NR_UL_DCI_FORMAT_0_1)
662 663
      pusch_config_pdu->scid = dci->dmrs_sequence_initialization.val;

664
    /* TRANSFORM PRECODING ------------------------------------------------------------------------------------------*/
665
    if (pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled) {
666 667

      uint32_t n_RS_Id = 0;
rmagueta's avatar
rmagueta committed
668 669
      if (NR_DMRS_ulconfig->transformPrecodingEnabled &&
          NR_DMRS_ulconfig->transformPrecodingEnabled->nPUSCH_Identity != NULL)
670 671
        n_RS_Id = *NR_DMRS_ulconfig->transformPrecodingEnabled->nPUSCH_Identity;
      else
672
        n_RS_Id = mac->physCellId;
673 674 675 676 677

      // U as specified in section 6.4.1.1.1.2 in 38.211, if sequence hopping and group hopping are disabled
      pusch_config_pdu->dfts_ofdm.low_papr_group_number = n_RS_Id % 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
678 679 680
      if (!NR_DMRS_ulconfig || !NR_DMRS_ulconfig->transformPrecodingEnabled ||
          (!NR_DMRS_ulconfig->transformPrecodingEnabled->sequenceGroupHopping && !NR_DMRS_ulconfig->transformPrecodingEnabled->sequenceHopping))
        pusch_config_pdu->dfts_ofdm.low_papr_sequence_number = 0;
681 682 683
      else
        AssertFatal(1==0,"SequenceGroupHopping or sequenceHopping are NOT Supported\n");

684 685 686 687
      LOG_D(NR_MAC,
            "TRANSFORM PRECODING IS ENABLED. CDM groups: %d, U: %d \n",
            pusch_config_pdu->num_dmrs_cdm_grps_no_data,
            pusch_config_pdu->dfts_ofdm.low_papr_group_number);
688
    }
689
    else {
690
      if (pusch_config_pdu->scid == 0 && NR_DMRS_ulconfig &&
691 692
          NR_DMRS_ulconfig->transformPrecodingDisabled->scramblingID0)
        pusch_config_pdu->ul_dmrs_scrambling_id = *NR_DMRS_ulconfig->transformPrecodingDisabled->scramblingID0;
693
      if (pusch_config_pdu->scid == 1 && NR_DMRS_ulconfig &&
694 695 696
          NR_DMRS_ulconfig->transformPrecodingDisabled->scramblingID1)
        pusch_config_pdu->ul_dmrs_scrambling_id = *NR_DMRS_ulconfig->transformPrecodingDisabled->scramblingID1;
    }
697 698 699

    /* TRANSFORM PRECODING --------------------------------------------------------------------------------------------------------*/

700 701
    /* IDENTIFIER_DCI_FORMATS */
    /* FREQ_DOM_RESOURCE_ASSIGNMENT_UL */
702 703 704 705 706 707 708
    if (nr_ue_process_dci_freq_dom_resource_assignment(pusch_config_pdu,
                                                       NULL,
                                                       NULL,
                                                       current_UL_BWP->BWPSize,
                                                       0,
                                                       0,
                                                       dci->frequency_domain_assignment) < 0) {
709
      LOG_E(NR_MAC, "can't nr_ue_process_dci_freq_dom_resource_assignment()\n");
710 711
      return -1;
    }
712

713
    /* FREQ_HOPPING_FLAG */
714 715
    if (pusch_Config
        && pusch_Config->frequencyHopping
716
        && (pusch_Config->resourceAllocation != NR_PUSCH_Config__resourceAllocation_resourceAllocationType0)) {
717 718 719 720 721 722 723
      pusch_config_pdu->frequency_hopping = dci->frequency_hopping_flag.val;
    }

    /* MCS */
    pusch_config_pdu->mcs_index = dci->mcs;

    /* MCS TABLE */
724 725 726 727 728 729
    pusch_config_pdu->mcs_table = get_pusch_mcs_table(pusch_Config ? pusch_Config->mcs_TableTransformPrecoder : NULL,
                                                      pusch_config_pdu->transform_precoding != NR_PUSCH_Config__transformPrecoder_disabled,
                                                      dci_format,
                                                      rnti_type,
                                                      ss_type,
                                                      false);
730 731

    /* NDI */
732 733 734 735
    NR_UL_HARQ_INFO_t *harq = &mac->ul_harq_info[dci->harq_pid];
    pusch_config_pdu->pusch_data.new_data_indicator = false;
    if (dci->ndi != harq->last_ndi) {
      pusch_config_pdu->pusch_data.new_data_indicator = true;
736
      // if new data reset harq structure
737
      memset(harq, 0, sizeof(*harq));
738
    }
739
    harq->last_ndi = dci->ndi;
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758
    /* RV */
    pusch_config_pdu->pusch_data.rv_index = dci->rv;
    /* HARQ_PROCESS_NUMBER */
    pusch_config_pdu->pusch_data.harq_process_id = dci->harq_pid;
    /* TPC_PUSCH */
    // according to TS 38.213 Table Table 7.1.1-1
    if (dci->tpc == 0) {
      pusch_config_pdu->absolute_delta_PUSCH = -4;
    }
    if (dci->tpc == 1) {
      pusch_config_pdu->absolute_delta_PUSCH = -1;
    }
    if (dci->tpc == 2) {
      pusch_config_pdu->absolute_delta_PUSCH = 1;
    }
    if (dci->tpc == 3) {
      pusch_config_pdu->absolute_delta_PUSCH = 4;
    }

759
    if (NR_DMRS_ulconfig != NULL)
760 761
      add_pos = (NR_DMRS_ulconfig->dmrs_AdditionalPosition == NULL) ? 2 : *NR_DMRS_ulconfig->dmrs_AdditionalPosition;

762
    /* DMRS */
763 764 765
    l_prime_mask = get_l_prime(pusch_config_pdu->nr_of_symbols,
                               mappingtype, add_pos, dmrslength,
                               pusch_config_pdu->start_symbol_index,
766
                               mac->dmrs_TypeA_Position);
767

768 769
    if (sc_info->xOverhead_PUSCH)
      N_PRB_oh = 6 * (1 + *sc_info->xOverhead_PUSCH);
770 771 772
    else
      N_PRB_oh = 0;

773
    if (sc_info->rateMatching_PUSCH) {
774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
      long maxMIMO_Layers = 0;
      if (sc_info->maxMIMO_Layers_PUSCH)
        maxMIMO_Layers = *sc_info->maxMIMO_Layers_PUSCH;
      else if (pusch_Config && pusch_Config->maxRank)
        maxMIMO_Layers = *pusch_Config->maxRank;
      else {
        if (pusch_Config && pusch_Config->txConfig) {
          if (*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook)
            maxMIMO_Layers = mac->uecap_maxMIMO_PUSCH_layers_cb;
          else
            maxMIMO_Layers = mac->uecap_maxMIMO_PUSCH_layers_nocb;
        } else
          maxMIMO_Layers = 1; // single antenna port
      }
      AssertFatal (maxMIMO_Layers > 0, "Invalid number of max MIMO layers for PUSCH\n");
      pusch_config_pdu->tbslbrm = nr_compute_tbslbrm(pusch_config_pdu->mcs_table, sc_info->ul_bw_tbslbrm, maxMIMO_Layers);
790
    } else
791 792
      pusch_config_pdu->tbslbrm = 0;

793
    /* PTRS */
794 795
    if (pusch_Config && pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB &&
        pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS) {
796
      if (pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_disabled) {
797 798
        nfapi_nr_ue_ptrs_ports_t ptrs_ports_list;
        pusch_config_pdu->pusch_ptrs.ptrs_ports_list = &ptrs_ports_list;
799 800 801 802 803 804 805 806 807 808 809
        bool valid_ptrs_setup = set_ul_ptrs_values(pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup,
                                                   pusch_config_pdu->rb_size,
                                                   pusch_config_pdu->mcs_index,
                                                   pusch_config_pdu->mcs_table,
                                                   &pusch_config_pdu->pusch_ptrs.ptrs_freq_density,
                                                   &pusch_config_pdu->pusch_ptrs.ptrs_time_density,
                                                   &pusch_config_pdu->pusch_ptrs.ptrs_ports_list->ptrs_re_offset,
                                                   &pusch_config_pdu->pusch_ptrs.num_ptrs_ports,
                                                   &pusch_config_pdu->pusch_ptrs.ul_ptrs_power,
                                                   pusch_config_pdu->nr_of_symbols);
        if(valid_ptrs_setup == true) {
810 811
          pusch_config_pdu->pdu_bit_map |= PUSCH_PDU_BITMAP_PUSCH_PTRS;
        }
812 813
        LOG_D(NR_MAC, "UL PTRS values: PTRS time den: %d, PTRS freq den: %d\n",
              pusch_config_pdu->pusch_ptrs.ptrs_time_density, pusch_config_pdu->pusch_ptrs.ptrs_freq_density);
814
      }
815 816 817
    }
  }

818 819
  LOG_D(NR_MAC,
        "Received UL grant (rb_start %d, rb_size %d, start_symbol_index %d, nr_of_symbols %d) for RNTI type %s \n",
820 821 822 823
        pusch_config_pdu->rb_start,
        pusch_config_pdu->rb_size,
        pusch_config_pdu->start_symbol_index,
        pusch_config_pdu->nr_of_symbols,
824
        rnti_types(rnti_type));
825

826
  pusch_config_pdu->ul_dmrs_symb_pos = l_prime_mask;
827
  pusch_config_pdu->qam_mod_order = nr_get_Qm_ul(pusch_config_pdu->mcs_index, pusch_config_pdu->mcs_table);
828 829
  if (pusch_config_pdu->qam_mod_order == 0) {
    LOG_W(NR_MAC, "Invalid Mod order, likely due to unexpected UL DCI. Ignoring DCI! \n");
830 831 832
    return -1;
  }

francescomani's avatar
francescomani committed
833 834
  int start_symbol = pusch_config_pdu->start_symbol_index;
  int number_of_symbols = pusch_config_pdu->nr_of_symbols;
835
  int number_dmrs_symbols = 0;
francescomani's avatar
francescomani committed
836 837 838 839 840
  for (int i = start_symbol; i < start_symbol + number_of_symbols; i++) {
    if((pusch_config_pdu->ul_dmrs_symb_pos >> i) & 0x01)
      number_dmrs_symbols += 1;
  }

841
  int nb_dmrs_re_per_rb = ((pusch_config_pdu->dmrs_config_type == pusch_dmrs_type1) ? 6 : 4) * pusch_config_pdu->num_dmrs_cdm_grps_no_data;
842 843

  // Compute TBS
844 845 846 847
  uint16_t R = nr_get_code_rate_ul(pusch_config_pdu->mcs_index, pusch_config_pdu->mcs_table);
  int pid = pusch_config_pdu->pusch_data.harq_process_id;
  if (R > 0) {
    pusch_config_pdu->target_code_rate = R;
848 849 850 851
    pusch_config_pdu->pusch_data.tb_size = nr_compute_tbs(pusch_config_pdu->qam_mod_order,
                                                          R,
                                                          pusch_config_pdu->rb_size,
                                                          pusch_config_pdu->nr_of_symbols,
852
                                                          nb_dmrs_re_per_rb * number_dmrs_symbols,
853 854
                                                          N_PRB_oh,
                                                          0, // TBR to verify tb scaling
855 856 857 858 859 860 861 862
                                                          pusch_config_pdu->nrOfLayers) >> 3;
    mac->ul_harq_info[pid].TBS = pusch_config_pdu->pusch_data.tb_size;
    mac->ul_harq_info[pid].R = R;
  }
  else {
    pusch_config_pdu->target_code_rate = mac->ul_harq_info[pid].R;
    pusch_config_pdu->pusch_data.tb_size = mac->ul_harq_info[pid].TBS;
  }
863

864
  pusch_config_pdu->ldpcBaseGraph = get_BG(pusch_config_pdu->pusch_data.tb_size << 3, pusch_config_pdu->target_code_rate);
865

866 867 868 869
  //The MAC entity shall restart retxBSR-Timer upon reception of a grant for transmission of new data on any UL-SCH
  if (pusch_config_pdu->pusch_data.new_data_indicator && dci && dci->ulsch_indicator)
    nr_timer_start(&mac->scheduling_info.retxBSR_Timer);

870 871 872 873 874
  if (pusch_config_pdu->pusch_data.tb_size == 0) {
    LOG_E(MAC, "Invalid TBS = 0. Probably caused by missed detection of DCI\n");
    return -1;
  }

875 876 877
  return 0;
}

878 879 880 881 882
int configure_srs_pdu(NR_UE_MAC_INST_t *mac,
                      NR_SRS_Resource_t *srs_resource,
                      fapi_nr_ul_config_srs_pdu *srs_config_pdu,
                      int period,
                      int offset)
883
{
884
  NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
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

  srs_config_pdu->rnti = mac->crnti;
  srs_config_pdu->handle = 0;
  srs_config_pdu->bwp_size = current_UL_BWP->BWPSize;
  srs_config_pdu->bwp_start = current_UL_BWP->BWPStart;
  srs_config_pdu->subcarrier_spacing = current_UL_BWP->scs;
  srs_config_pdu->cyclic_prefix = 0;
  srs_config_pdu->num_ant_ports = srs_resource->nrofSRS_Ports;
  srs_config_pdu->num_symbols = srs_resource->resourceMapping.nrofSymbols;
  srs_config_pdu->num_repetitions = srs_resource->resourceMapping.repetitionFactor;
  srs_config_pdu->time_start_position = srs_resource->resourceMapping.startPosition;
  srs_config_pdu->config_index = srs_resource->freqHopping.c_SRS;
  srs_config_pdu->sequence_id = srs_resource->sequenceId;
  srs_config_pdu->bandwidth_index = srs_resource->freqHopping.b_SRS;
  srs_config_pdu->comb_size = srs_resource->transmissionComb.present - 1;

  switch(srs_resource->transmissionComb.present) {
    case NR_SRS_Resource__transmissionComb_PR_n2:
      srs_config_pdu->comb_offset = srs_resource->transmissionComb.choice.n2->combOffset_n2;
      srs_config_pdu->cyclic_shift = srs_resource->transmissionComb.choice.n2->cyclicShift_n2;
      break;
    case NR_SRS_Resource__transmissionComb_PR_n4:
      srs_config_pdu->comb_offset = srs_resource->transmissionComb.choice.n4->combOffset_n4;
      srs_config_pdu->cyclic_shift = srs_resource->transmissionComb.choice.n4->cyclicShift_n4;
      break;
    default:
      LOG_W(NR_MAC, "Invalid or not implemented comb_size!\n");
  }

  srs_config_pdu->frequency_position = srs_resource->freqDomainPosition;
  srs_config_pdu->frequency_shift = srs_resource->freqDomainShift;
  srs_config_pdu->frequency_hopping = srs_resource->freqHopping.b_hop;
  srs_config_pdu->group_or_sequence_hopping = srs_resource->groupOrSequenceHopping;
  srs_config_pdu->resource_type = srs_resource->resourceType.present - 1;
  if(srs_config_pdu->resource_type > 0) { // not aperiodic
    srs_config_pdu->t_srs = period;
    srs_config_pdu->t_offset = offset;
  }

#ifdef SRS_DEBUG
  LOG_I(NR_MAC,"Frame = %i, slot = %i\n", frame, slot);
  LOG_I(NR_MAC,"srs_config_pdu->rnti = 0x%04x\n", srs_config_pdu->rnti);
  LOG_I(NR_MAC,"srs_config_pdu->handle = %u\n", srs_config_pdu->handle);
  LOG_I(NR_MAC,"srs_config_pdu->bwp_size = %u\n", srs_config_pdu->bwp_size);
  LOG_I(NR_MAC,"srs_config_pdu->bwp_start = %u\n", srs_config_pdu->bwp_start);
  LOG_I(NR_MAC,"srs_config_pdu->subcarrier_spacing = %u\n", srs_config_pdu->subcarrier_spacing);
  LOG_I(NR_MAC,"srs_config_pdu->cyclic_prefix = %u (0: Normal; 1: Extended)\n", srs_config_pdu->cyclic_prefix);
  LOG_I(NR_MAC,"srs_config_pdu->num_ant_ports = %u (0 = 1 port, 1 = 2 ports, 2 = 4 ports)\n", srs_config_pdu->num_ant_ports);
  LOG_I(NR_MAC,"srs_config_pdu->num_symbols = %u (0 = 1 symbol, 1 = 2 symbols, 2 = 4 symbols)\n", srs_config_pdu->num_symbols);
  LOG_I(NR_MAC,"srs_config_pdu->num_repetitions = %u (0 = 1, 1 = 2, 2 = 4)\n", srs_config_pdu->num_repetitions);
  LOG_I(NR_MAC,"srs_config_pdu->time_start_position = %u\n", srs_config_pdu->time_start_position);
  LOG_I(NR_MAC,"srs_config_pdu->config_index = %u\n", srs_config_pdu->config_index);
  LOG_I(NR_MAC,"srs_config_pdu->sequence_id = %u\n", srs_config_pdu->sequence_id);
  LOG_I(NR_MAC,"srs_config_pdu->bandwidth_index = %u\n", srs_config_pdu->bandwidth_index);
  LOG_I(NR_MAC,"srs_config_pdu->comb_size = %u (0 = comb size 2, 1 = comb size 4, 2 = comb size 8)\n", srs_config_pdu->comb_size);
  LOG_I(NR_MAC,"srs_config_pdu->comb_offset = %u\n", srs_config_pdu->comb_offset);
  LOG_I(NR_MAC,"srs_config_pdu->cyclic_shift = %u\n", srs_config_pdu->cyclic_shift);
  LOG_I(NR_MAC,"srs_config_pdu->frequency_position = %u\n", srs_config_pdu->frequency_position);
  LOG_I(NR_MAC,"srs_config_pdu->frequency_shift = %u\n", srs_config_pdu->frequency_shift);
  LOG_I(NR_MAC,"srs_config_pdu->frequency_hopping = %u\n", srs_config_pdu->frequency_hopping);
  LOG_I(NR_MAC,"srs_config_pdu->group_or_sequence_hopping = %u (0 = No hopping, 1 = Group hopping groupOrSequenceHopping, 2 = Sequence hopping)\n", srs_config_pdu->group_or_sequence_hopping);
  LOG_I(NR_MAC,"srs_config_pdu->resource_type = %u (0: aperiodic, 1: semi-persistent, 2: periodic)\n", srs_config_pdu->resource_type);
  LOG_I(NR_MAC,"srs_config_pdu->t_srs = %u\n", srs_config_pdu->t_srs);
  LOG_I(NR_MAC,"srs_config_pdu->t_offset = %u\n", srs_config_pdu->t_offset);
#endif
950
  return 0;
951 952 953 954 955
}

// Aperiodic SRS scheduling
void nr_ue_aperiodic_srs_scheduling(NR_UE_MAC_INST_t *mac, long resource_trigger, int frame, int slot)
{
956
  NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
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
  NR_SRS_Config_t *srs_config = current_UL_BWP->srs_Config;

  if (!srs_config) {
    LOG_E(NR_MAC, "DCI is triggering aperiodic SRS but there is no SRS configuration\n");
    return;
  }

  int slot_offset = 0;
  NR_SRS_Resource_t *srs_resource = NULL;
  for(int rs = 0; rs < srs_config->srs_ResourceSetToAddModList->list.count; rs++) {

    // Find aperiodic resource set
    NR_SRS_ResourceSet_t *srs_resource_set = srs_config->srs_ResourceSetToAddModList->list.array[rs];
    if(srs_resource_set->resourceType.present != NR_SRS_ResourceSet__resourceType_PR_aperiodic)
      continue;
    // the resource trigger need to match the DCI one
    if(srs_resource_set->resourceType.choice.aperiodic->aperiodicSRS_ResourceTrigger != resource_trigger)
      continue;
    // if slotOffset is null -> offset = 0
    if(srs_resource_set->resourceType.choice.aperiodic->slotOffset)
      slot_offset = *srs_resource_set->resourceType.choice.aperiodic->slotOffset;

    // Find the corresponding srs resource
    for(int r1 = 0; r1 < srs_resource_set->srs_ResourceIdList->list.count; r1++) {
      for (int r2 = 0; r2 < srs_config->srs_ResourceToAddModList->list.count; r2++) {
        if ((*srs_resource_set->srs_ResourceIdList->list.array[r1] == srs_config->srs_ResourceToAddModList->list.array[r2]->srs_ResourceId) &&
            (srs_config->srs_ResourceToAddModList->list.array[r2]->resourceType.present == NR_SRS_Resource__resourceType_PR_aperiodic)) {
          srs_resource = srs_config->srs_ResourceToAddModList->list.array[r2];
          break;
        }
      }
    }
  }

  if(srs_resource == NULL) {
    LOG_E(NR_MAC, "Couldn't find SRS aperiodic resource with trigger %ld\n", resource_trigger);
    return;
  }

996 997
  AssertFatal(slot_offset > DURATION_RX_TO_TX,
              "Slot offset between DCI and aperiodic SRS (%d) needs to be higher than DURATION_RX_TO_TX (%d)\n",
998 999 1000
              slot_offset, DURATION_RX_TO_TX);
  int n_slots_frame = nr_slots_per_frame[current_UL_BWP->scs];
  int sched_slot = (slot + slot_offset) % n_slots_frame;
1001
  NR_TDD_UL_DL_ConfigCommon_t *tdd_config = mac->tdd_UL_DL_ConfigurationCommon;
1002 1003 1004 1005 1006
  if (!is_nr_UL_slot(tdd_config, sched_slot, mac->frame_type)) {
    LOG_E(NR_MAC, "Slot for scheduling aperiodic SRS %d is not an UL slot\n", sched_slot);
    return;
  }
  int sched_frame = frame + (slot + slot_offset >= n_slots_frame) % 1024;
1007 1008 1009 1010 1011 1012 1013
  fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, sched_frame, sched_slot, FAPI_NR_UL_CONFIG_TYPE_SRS);
  if (!pdu)
    return;
  int ret = configure_srs_pdu(mac, srs_resource, &pdu->srs_config_pdu, 0, 0);
  if (ret != 0)
    remove_ul_config_last_item(pdu);
  release_ul_config(pdu, false);
1014 1015 1016
}


1017
// Periodic SRS scheduling
1018
static bool nr_ue_periodic_srs_scheduling(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot)
francescomani's avatar
francescomani committed
1019
{
1020
  bool srs_scheduled = false;
1021
  NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
1022

1023
  NR_SRS_Config_t *srs_config = current_UL_BWP ? current_UL_BWP->srs_Config : NULL;
1024 1025

  if (!srs_config) {
1026
    return false;
1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
  }

  for(int rs = 0; rs < srs_config->srs_ResourceSetToAddModList->list.count; rs++) {

    // Find periodic resource set
    NR_SRS_ResourceSet_t *srs_resource_set = srs_config->srs_ResourceSetToAddModList->list.array[rs];
    if(srs_resource_set->resourceType.present != NR_SRS_ResourceSet__resourceType_PR_periodic) {
      continue;
    }

    // Find the corresponding srs resource
    NR_SRS_Resource_t *srs_resource = NULL;
    for(int r1 = 0; r1 < srs_resource_set->srs_ResourceIdList->list.count; r1++) {
      for (int r2 = 0; r2 < srs_config->srs_ResourceToAddModList->list.count; r2++) {
        if ((*srs_resource_set->srs_ResourceIdList->list.array[r1] == srs_config->srs_ResourceToAddModList->list.array[r2]->srs_ResourceId) &&
            (srs_config->srs_ResourceToAddModList->list.array[r2]->resourceType.present == NR_SRS_Resource__resourceType_PR_periodic)) {
          srs_resource = srs_config->srs_ResourceToAddModList->list.array[r2];
          break;
        }
      }
    }

    if(srs_resource == NULL) {
      continue;
    }

    uint16_t period = srs_period[srs_resource->resourceType.choice.periodic->periodicityAndOffset_p.present];
1054
    uint16_t offset = get_nr_srs_offset(srs_resource->resourceType.choice.periodic->periodicityAndOffset_p);
1055

francescomani's avatar
francescomani committed
1056
    int n_slots_frame = nr_slots_per_frame[current_UL_BWP->scs];
1057 1058 1059

    // Check if UE should transmit the SRS
    if((frame*n_slots_frame+slot-offset)%period == 0) {
1060 1061 1062 1063 1064 1065 1066 1067 1068
      fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frame, slot, FAPI_NR_UL_CONFIG_TYPE_SRS);
      if (!pdu)
        return false;
      int ret = configure_srs_pdu(mac, srs_resource, &pdu->srs_config_pdu, period, offset);
      if (ret != 0)
        remove_ul_config_last_item(pdu);
      else
        srs_scheduled = true;
      release_ul_config(pdu, false);
1069 1070
    }
  }
1071
  return srs_scheduled;
1072 1073
}

1074 1075 1076 1077
// Performs :
// 1. TODO: Call RRC for link status return to PHY
// 2. TODO: Perform SR/BSR procedures for scheduling feedback
// 3. TODO: Perform PHR procedures
1078
void nr_ue_dl_scheduler(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info)
francescomani's avatar
francescomani committed
1079
{
1080 1081
  frame_t rx_frame = dl_info->frame;
  slot_t rx_slot = dl_info->slot;
1082

1083 1084 1085
  fapi_nr_dl_config_request_t *dl_config = get_dl_config_request(mac, rx_slot);
  dl_config->sfn  = rx_frame;
  dl_config->slot = rx_slot;
1086
  dl_config->number_pdus = 0;
1087

1088
  if (mac->state == UE_NOT_SYNC || mac->state == UE_DETACHING)
1089
    return;
francescomani's avatar
francescomani committed
1090

1091 1092
  ue_dci_configuration(mac, dl_config, rx_frame, rx_slot);

1093
  if (mac->ul_time_alignment.ta_apply != no_ta)
1094 1095 1096 1097
    schedule_ta_command(dl_config, &mac->ul_time_alignment);
  if (mac->state == UE_CONNECTED) {
    nr_schedule_csirs_reception(mac, rx_frame, rx_slot);
    nr_schedule_csi_for_im(mac, rx_frame, rx_slot);
francescomani's avatar
francescomani committed
1098
  }
1099 1100

  nr_scheduled_response_t scheduled_response = {.dl_config = dl_config,
1101
                                                .module_id = mac->ue_id,
1102 1103 1104 1105 1106
                                                .CC_id = dl_info->cc_id,
                                                .phy_data = dl_info->phy_data,
                                                .mac = mac};
  if (mac->if_module != NULL && mac->if_module->scheduled_response != NULL)
    mac->if_module->scheduled_response(&scheduled_response);
francescomani's avatar
francescomani committed
1107
  else
1108
    LOG_E(NR_MAC, "Internal error, no scheduled_response function\n");
francescomani's avatar
francescomani committed
1109
}
1110

1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
static void nr_trigger_sr(NR_UE_MAC_INST_t *mac)
{
  NR_UE_SCHEDULING_INFO *sched_info = &mac->scheduling_info;
  // if a Regular BSR has been triggered and logicalChannelSR-DelayTimer is not running
  if (((sched_info->BSR_reporting_active & NR_BSR_TRIGGER_REGULAR) == 0)
      || is_nr_timer_active(sched_info->sr_DelayTimer))
    return;

  nr_lcordered_info_t *lc_info = get_lc_info_from_lcid(mac, sched_info->regularBSR_trigger_lcid);
  AssertFatal(lc_info, "Couldn't find logical channel with LCID %ld\n", sched_info->regularBSR_trigger_lcid);

  // if there is no UL-SCH resource available for a new transmission (ie we are at this point)

  // if the MAC entity is configured with configured uplink grant(s) and the Regular BSR was triggered for a
  // logical channel for which logicalChannelSR-Mask is set to false or
  if (mac->current_UL_BWP->configuredGrantConfig && lc_info->lc_SRMask)
    return;
  // if the UL-SCH resources available for a new transmission do not meet the LCP mapping restrictions
  // TODO not implemented

  // trigger SR
  sched_info->SR_pending = 1;
}

static void nr_update_bsr(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP, uint8_t gNB_index)
{
  // Reset All BSR Infos
  for (int id = 0; id < NR_MAX_NUM_LCID; id++) {
    // Reset transmission status
    mac->scheduling_info.lc_sched_info[id].LCID_buffer_with_data = false;
  }

  for (int lcgid = 0; lcgid < NR_MAX_NUM_LCGID; lcgid++) {
    // Reset Buffer Info
    mac->scheduling_info.lcg_sched_info[lcgid].BSR = 0;
    mac->scheduling_info.lcg_sched_info[lcgid].BSR_bytes = 0;
  }

  bool bsr_regular_triggered = mac->scheduling_info.BSR_reporting_active & NR_BSR_TRIGGER_REGULAR;
  for (int i = 0; i < mac->lc_ordered_list.count; i++) {
    nr_lcordered_info_t *lc_info = mac->lc_ordered_list.array[i];
    int lcid = lc_info->lcid;
    NR_LC_SCHEDULING_INFO *lc_sched_info = get_scheduling_info_from_lcid(mac, lcid);
    int lcgid = lc_sched_info->LCGID;

    // check if UL data for a logical channel which belongs to a LCG becomes available for transmission
    if (lcgid != NR_INVALID_LCGID) {
      mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mac->ue_id,
                                                            mac->ue_id,
                                                            gNB_index,
                                                            frameP,
                                                            slotP,
                                                            ENB_FLAG_NO,
                                                            MBMS_FLAG_NO,
                                                            lcid,
                                                            0,
                                                            0);

      lc_sched_info->LCID_buffer_remain = rlc_status.bytes_in_buffer;

      if (rlc_status.bytes_in_buffer > 0) {
        LOG_D(NR_MAC,
              "[UE %d] LCID %d LCGID %d has %d bytes to transmit at frame %d slot %d\n",
              mac->ue_id,
              lcid,
              lcgid,
              rlc_status.bytes_in_buffer,
              frameP,
              slotP);

        lc_sched_info->LCID_buffer_with_data = true;

        //Update BSR_bytes
        mac->scheduling_info.lcg_sched_info[lcgid].BSR_bytes += rlc_status.bytes_in_buffer;

        if (!bsr_regular_triggered) {
          bsr_regular_triggered = true;
          trigger_regular_bsr(mac, lcid, lc_info->sr_DelayTimerApplied);
          LOG_D(NR_MAC,
                "[UE %d] MAC BSR Triggered LCID %d LCGID %d data become available at %d.%d\n",
                mac->ue_id,
                lcid,
                lcgid,
                frameP,
                slotP);
        }
      }
    }
  }
}

1202
void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info)
francescomani's avatar
francescomani committed
1203
{
1204
  int cc_id = ul_info->cc_id;
1205 1206
  frame_t frame_tx = ul_info->frame;
  slot_t slot_tx = ul_info->slot;
1207
  uint32_t gNB_index = ul_info->gNB_index;
1208

1209
  RA_config_t *ra = &mac->ra;
1210
  if(mac->state > UE_NOT_SYNC && mac->state < UE_CONNECTED) {
1211 1212
    nr_ue_get_rach(mac, cc_id, frame_tx, gNB_index, slot_tx);
    nr_ue_prach_scheduler(mac, frame_tx, slot_tx);
francescomani's avatar
francescomani committed
1213 1214 1215 1216
  }

  // Periodic SRS scheduling
  if(mac->state == UE_CONNECTED)
1217
    nr_ue_periodic_srs_scheduling(mac, frame_tx, slot_tx);
1218

1219 1220 1221 1222 1223
  // Call BSR procedure as described in Section 5.4.5 in 38.321
  // Check whether BSR is triggered before scheduling ULSCH
  if(mac->state == UE_CONNECTED)
    nr_update_bsr(mac, frame_tx, slot_tx, gNB_index);

francescomani's avatar
francescomani committed
1224 1225
  // Schedule ULSCH only if the current frame and slot match those in ul_config_req
  // AND if a UL grant (UL DCI or Msg3) has been received (as indicated by num_pdus)
1226 1227
  uint8_t ulsch_input_buffer_array[NFAPI_MAX_NUM_UL_PDU][MAX_ULSCH_PAYLOAD_BYTES];
  int number_of_pdus = 0;
1228

1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244
  fapi_nr_ul_config_request_pdu_t *ulcfg_pdu = lockGet_ul_iterator(mac, frame_tx, slot_tx);
  if (!ulcfg_pdu)
    return;
  LOG_D(NR_MAC, "number of UL PDUs: %d with UL transmission in sfn [%d.%d]\n", *ulcfg_pdu->privateNBpdus, frame_tx, slot_tx);

  while (ulcfg_pdu->pdu_type != FAPI_NR_END) {
    uint8_t *ulsch_input_buffer = ulsch_input_buffer_array[number_of_pdus];
    if (ulcfg_pdu->pdu_type == FAPI_NR_UL_CONFIG_TYPE_PUSCH) {
      int mac_pdu_exist = 0;
      uint16_t TBS_bytes = ulcfg_pdu->pusch_config_pdu.pusch_data.tb_size;
      LOG_D(NR_MAC,
            "harq_id %d, new_data_indicator %d, TBS_bytes %d (ra_state %d)\n",
            ulcfg_pdu->pusch_config_pdu.pusch_data.harq_process_id,
            ulcfg_pdu->pusch_config_pdu.pusch_data.new_data_indicator,
            TBS_bytes,
            ra->ra_state);
1245
      if (ra->ra_state == nrRA_WAIT_RAR && !ra->cfra) {
1246
        nr_get_msg3_payload(mac, ulsch_input_buffer, TBS_bytes);
1247 1248 1249 1250 1251 1252
        for (int k = 0; k < TBS_bytes; k++) {
          LOG_D(NR_MAC, "(%i): 0x%x\n", k, ulsch_input_buffer[k]);
        }
        mac_pdu_exist = 1;
      } else {
        if (ulcfg_pdu->pusch_config_pdu.pusch_data.new_data_indicator
1253
            && (mac->state == UE_CONNECTED || (ra->ra_state == nrRA_WAIT_RAR && ra->cfra))) {
1254
          // Getting IP traffic to be transmitted
1255
          nr_ue_get_sdu(mac, cc_id, frame_tx, slot_tx, gNB_index, ulsch_input_buffer, TBS_bytes);
1256
          mac_pdu_exist = 1;
1257 1258
        }
      }
1259 1260 1261 1262 1263 1264 1265

      // Config UL TX PDU
      if (mac_pdu_exist) {
        ulcfg_pdu->pusch_config_pdu.tx_request_body.pdu = ulsch_input_buffer;
        ulcfg_pdu->pusch_config_pdu.tx_request_body.pdu_length = TBS_bytes;
        number_of_pdus++;
      }
1266
      if (ra->ra_state == nrRA_WAIT_CONTENTION_RESOLUTION && !ra->cfra) {
1267 1268 1269
        LOG_I(NR_MAC, "[RAPROC][%d.%d] RA-Msg3 retransmitted\n", frame_tx, slot_tx);
        // 38.321 restart the ra-ContentionResolutionTimer at each HARQ retransmission in the first symbol after the end of the Msg3
        // transmission
1270
        nr_Msg3_transmitted(mac, cc_id, frame_tx, slot_tx, gNB_index);
1271
      }
1272
      if (ra->ra_state == nrRA_WAIT_RAR && !ra->cfra) {
1273
        LOG_A(NR_MAC, "[RAPROC][%d.%d] RA-Msg3 transmitted\n", frame_tx, slot_tx);
1274
        nr_Msg3_transmitted(mac, cc_id, frame_tx, slot_tx, gNB_index);
francescomani's avatar
francescomani committed
1275
      }
1276
    }
1277 1278 1279 1280 1281 1282 1283
    ulcfg_pdu++;
  }
  release_ul_config(ulcfg_pdu, false);
  if (mac->if_module != NULL && mac->if_module->scheduled_response != NULL) {
    LOG_D(NR_MAC, "3# scheduled_response transmitted,%d, %d\n", frame_tx, slot_tx);
    nr_scheduled_response_t scheduled_response = {.ul_config = mac->ul_config_request + slot_tx,
                                                  .mac = mac,
1284 1285
                                                  .module_id = mac->ue_id,
                                                  .CC_id = cc_id,
1286 1287
                                                  .phy_data = ul_info->phy_data};
    mac->if_module->scheduled_response(&scheduled_response);
1288 1289
  }

1290 1291 1292
  if(mac->state == UE_CONNECTED)
    nr_trigger_sr(mac);

1293
  // update Bj for all active lcids before LCP procedure
1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315
  if (mac->current_UL_BWP) {
    LOG_D(NR_MAC, "%4d.%2d Logical Channel Prioritization\n", frame_tx, slot_tx);
    for (int i = 0; i < mac->lc_ordered_list.count; i++) {
      nr_lcordered_info_t *lc_info = mac->lc_ordered_list.array[i];
      int lcid = lc_info->lcid;
      // max amount of data that can be buffered/accumulated in a logical channel buffer
      uint32_t bucketSize_max = lc_info->bucket_size;
      //  measure Bj increment the value of Bj by product PBR  * T
      NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid);
      int32_t bj = sched_info->Bj;
      if (lc_info->pbr < UINT_MAX) {
        uint32_t slots_elapsed = nr_timer_elapsed_time(sched_info->Bj_timer); // slots elapsed since Bj was last incremented
        // it is safe to divide by 1k since pbr in lc_info is computed multiplying by 1000 the RRC value to convert kB/s to B/s
        uint32_t pbr_ms = lc_info->pbr / 1000;
        bj += ((pbr_ms * slots_elapsed) >> mac->current_UL_BWP->scs); // each slot length is 1/scs ms
      }
      else
        bj = INT_MAX;
      // bj > max bucket size, set bj to max bucket size, as in ts38.321 5.4.3.1 Logical Channel Prioritization
      sched_info->Bj = min(bj, bucketSize_max);
      // reset bj timer
      nr_timer_start(&sched_info->Bj_timer);
1316
    }
1317 1318
  }

1319
  if(mac->state >= UE_PERFORMING_RA && mac->state < UE_DETACHING)
1320
    nr_ue_pucch_scheduler(mac, frame_tx, slot_tx, ul_info->phy_data);
1321 1322
}

1323
static uint8_t nr_locate_BsrIndexByBufferSize(const uint32_t *table, int size, int value)
1324
{
mjoang's avatar
mjoang committed
1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346
  uint8_t ju, jm, jl;
  int ascend;
  //DevAssert(size > 0);
  //DevAssert(size <= 256);

  if (value == 0) {
    return 0;   //elseif (value > 150000) return 63;
  }

  jl = 0;     // lower bound
  ju = size - 1;    // upper bound
  ascend = (table[ju] >= table[jl]) ? 1 : 0;  // determine the order of the the table:  1 if ascending order of table, 0 otherwise

  while (ju - jl > 1) { //If we are not yet done,
    jm = (ju + jl) >> 1;  //compute a midpoint,

    if ((value >= table[jm]) == ascend) {
      jl = jm;    // replace the lower limit
    } else {
      ju = jm;    //replace the upper limit
    }

1347
    LOG_T(NR_MAC, "[UE] searching BSR index %d for (BSR TABLE %d < value %d)\n",
mjoang's avatar
mjoang committed
1348 1349 1350 1351 1352 1353 1354 1355 1356 1357
          jm, table[jm], value);
  }

  if (value == table[jl]) {
    return jl;
  } else {
    return jl + 1;    //equally  ju
  }
}

1358 1359 1360 1361 1362 1363 1364
// PUSCH scheduler:
// - Calculate the slot in which ULSCH should be scheduled. This is current slot + K2,
// - where K2 is the offset between the slot in which UL DCI is received and the slot
// - in which ULSCH should be scheduled. K2 is configured in RRC configuration.  
// PUSCH Msg3 scheduler:
// - scheduled by RAR UL grant according to 8.3 of TS 38.213
// Note: Msg3 tx in the uplink symbols of mixed slot
1365 1366 1367 1368 1369 1370 1371
int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac,
                          const uint8_t is_Msg3,
                          const frame_t current_frame,
                          const int current_slot,
                          frame_t *frame_tx,
                          int *slot_tx,
                          const long k2)
1372
{
1373
  int delta = 0;
1374
  const NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
1375

1376
  // Get the numerology to calculate the Tx frame and slot
francescomani's avatar
francescomani committed
1377
  int mu = current_UL_BWP->scs;
1378

1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396
  // k2 as per 3GPP TS 38.214 version 15.9.0 Release 15 ch 6.1.2.1.1
  // PUSCH time domain resource allocation is higher layer configured from uschTimeDomainAllocationList in either pusch-ConfigCommon

  if (is_Msg3) {

    switch (mu) {
      case 0:
        delta = 2;
        break;
      case 1:
        delta = 3;
        break;
      case 2:
        delta = 4;
        break;
      case 3:
        delta = 6;
        break;
1397 1398
      default:
        AssertFatal(1 == 0, "Invalid numerology %i\n", mu);
1399 1400
    }

1401 1402
    AssertFatal((k2 + delta) > DURATION_RX_TO_TX,
                "Slot offset (%ld) for Msg3 needs to be higher than DURATION_RX_TO_TX (%d). Please set min_rxtxtime at least to %d in gNB config file or gNBs.[0].min_rxtxtime=%d via command line.\n",
1403 1404 1405 1406
                k2,
                DURATION_RX_TO_TX,
                DURATION_RX_TO_TX,
                DURATION_RX_TO_TX);
1407

1408
    *slot_tx = (current_slot + k2 + delta) % nr_slots_per_frame[mu];
1409
    if (current_slot + k2 + delta >= nr_slots_per_frame[mu]){
1410 1411 1412 1413 1414 1415 1416
      *frame_tx = (current_frame + 1) % 1024;
    } else {
      *frame_tx = current_frame;
    }

  } else {

1417 1418 1419 1420 1421 1422 1423
    AssertFatal(k2 > DURATION_RX_TO_TX,
                "Slot offset K2 (%ld) needs to be higher than DURATION_RX_TO_TX (%d). Please set min_rxtxtime at least to %d in gNB config file or gNBs.[0].min_rxtxtime=%d via command line.\n",
                k2,
                DURATION_RX_TO_TX,
                DURATION_RX_TO_TX,
                DURATION_RX_TO_TX);

1424
    if (k2 < 0) { // This can happen when a false DCI is received
1425
      LOG_W(PHY, "%d.%d. Received k2 %ld\n", current_frame, current_slot, k2);
1426 1427 1428 1429 1430
      return -1;
    }

    // Calculate TX slot and frame
    *slot_tx = (current_slot + k2) % nr_slots_per_frame[mu];
1431
    *frame_tx = ((current_slot + k2) > (nr_slots_per_frame[mu]-1)) ? (current_frame + 1) % 1024 : current_frame;
1432 1433 1434

  }

1435
  LOG_D(NR_MAC, "[%04d.%02d] UL transmission in [%04d.%02d] (k2 %ld delta %d)\n", current_frame, current_slot, *frame_tx, *slot_tx, k2, delta);
1436 1437 1438 1439 1440

  return 0;
}

// Build the list of all the valid RACH occasions in the maximum association pattern period according to the PRACH config
1441 1442
static void build_ro_list(NR_UE_MAC_INST_t *mac)
{
1443 1444 1445 1446
  int x,y; // PRACH Configuration Index table variables used to compute the valid frame numbers
  int y2;  // PRACH Configuration Index table additional variable used to compute the valid frame numbers
  uint8_t slot_shift_for_map;
  uint8_t map_shift;
1447
  bool even_slot_invalid;
1448 1449 1450 1451 1452 1453 1454 1455 1456
  int64_t s_map;
  uint8_t prach_conf_start_symbol; // Starting symbol of the PRACH occasions in the PRACH slot
  uint8_t N_t_slot; // Number of PRACH occasions in a 14-symbols PRACH slot
  uint8_t N_dur; // Duration of a PRACH occasion (nb of symbols)
  uint8_t frame; // Maximum is NB_FRAMES_IN_MAX_ASSOCIATION_PATTERN_PERIOD
  uint16_t format = 0xffff;
  uint8_t format2 = 0xff;
  int nb_fdm;

1457
  uint8_t config_index;
1458 1459 1460 1461
  int msg1_FDM;

  uint8_t nb_of_frames_per_prach_conf_period;

1462
  NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon;
1463 1464 1465 1466
  NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric;

  config_index = rach_ConfigGeneric->prach_ConfigurationIndex;

1467 1468
  int mu;
  if (setup->msg1_SubcarrierSpacing)
1469
    mu = *setup->msg1_SubcarrierSpacing;
1470
  else
1471
    mu = mac->current_UL_BWP->scs;
1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488

  msg1_FDM = rach_ConfigGeneric->msg1_FDM;

  switch (msg1_FDM){
    case 0:
    case 1:
    case 2:
    case 3:
      nb_fdm = 1 << msg1_FDM;
      break;
    default:
      AssertFatal(1 == 0, "Unknown msg1_FDM from rach_ConfigGeneric %d\n", msg1_FDM);
  }

  // Create the PRACH occasions map
  // WIP: For now assume no rejected PRACH occasions because of conflict with SSB or TDD_UL_DL_ConfigurationCommon schedule

1489
  int unpaired = mac->phy_config.config_req.cell_config.frame_duplex_type;
1490

laurent's avatar
laurent committed
1491
  const int64_t *prach_config_info_p = get_prach_config_info(mac->frequency_range, config_index, unpaired);
1492

1493
  // Identify the proper PRACH Configuration Index table according to the operating frequency
1494
  LOG_D(NR_MAC,"mu = %u, PRACH config index  = %u, unpaired = %u\n", mu, config_index, unpaired);
1495

1496
  if (mac->frequency_range == FR2) { //FR2
1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526

    x = prach_config_info_p[2];
    y = prach_config_info_p[3];
    y2 = prach_config_info_p[4];

    s_map = prach_config_info_p[5];

    prach_conf_start_symbol = prach_config_info_p[6];
    N_t_slot = prach_config_info_p[8];
    N_dur = prach_config_info_p[9];
    if (prach_config_info_p[1] != -1)
      format2 = (uint8_t) prach_config_info_p[1];
    format = ((uint8_t) prach_config_info_p[0]) | (format2<<8);

    slot_shift_for_map = mu-2;
    if ( (mu == 3) && (prach_config_info_p[7] == 1) )
      even_slot_invalid = true;
    else
      even_slot_invalid = false;
  }
  else { // FR1
    x = prach_config_info_p[2];
    y = prach_config_info_p[3];
    y2 = y;

    s_map = prach_config_info_p[4];

    prach_conf_start_symbol = prach_config_info_p[5];
    N_t_slot = prach_config_info_p[7];
    N_dur = prach_config_info_p[8];
1527
    LOG_D(NR_MAC,"N_t_slot %d, N_dur %d\n",N_t_slot,N_dur);
1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539
    if (prach_config_info_p[1] != -1)
      format2 = (uint8_t) prach_config_info_p[1];
    format = ((uint8_t) prach_config_info_p[0]) | (format2<<8);

    slot_shift_for_map = mu;
    if ( (mu == 1) && (prach_config_info_p[6] <= 1) )
      // no prach in even slots @ 30kHz for 1 prach per subframe
      even_slot_invalid = true;
    else
      even_slot_invalid = false;
  } // FR2 / FR1

1540 1541
  const int bwp_id = mac->current_UL_BWP->bwp_id;
  prach_association_pattern_t *prach_assoc_pattern = &mac->prach_assoc_pattern[bwp_id];
1542
  prach_assoc_pattern->nb_of_prach_conf_period_in_max_period = MAX_NB_PRACH_CONF_PERIOD_IN_ASSOCIATION_PATTERN_PERIOD / x;
1543 1544
  nb_of_frames_per_prach_conf_period = x;

1545
  LOG_D(NR_MAC,"nb_of_prach_conf_period_in_max_period %d\n", prach_assoc_pattern->nb_of_prach_conf_period_in_max_period);
1546 1547 1548 1549 1550 1551

  // Fill in the PRACH occasions table for every slot in every frame in every PRACH configuration periods in the maximum association pattern period
  // ----------------------------------------------------------------------------------------------------------------------------------------------
  // ----------------------------------------------------------------------------------------------------------------------------------------------
  // For every PRACH configuration periods
  // -------------------------------------
1552 1553 1554 1555 1556
  for (int period_idx = 0; period_idx < prach_assoc_pattern->nb_of_prach_conf_period_in_max_period; period_idx++) {
    prach_conf_period_t *prach_conf_period_list = &prach_assoc_pattern->prach_conf_period_list[period_idx];
    prach_conf_period_list->nb_of_prach_occasion = 0;
    prach_conf_period_list->nb_of_frame = nb_of_frames_per_prach_conf_period;
    prach_conf_period_list->nb_of_slot = nr_slots_per_frame[mu];
1557

1558
    LOG_D(NR_MAC,"PRACH Conf Period Idx %d\n", period_idx);
1559 1560 1561

    // For every frames in a PRACH configuration period
    // ------------------------------------------------
1562 1563
    for (int frame_idx = 0; frame_idx < nb_of_frames_per_prach_conf_period; frame_idx++) {
      frame = (period_idx * nb_of_frames_per_prach_conf_period) + frame_idx;
1564

1565
      LOG_D(NR_MAC,"PRACH Conf Period Frame Idx %d - Frame %d\n", frame_idx, frame);
1566
      // Is it a valid frame for this PRACH configuration index? (n_sfn mod x = y)
1567
      if ((frame%x)==y || (frame%x)==y2) {
1568 1569 1570

        // For every slot in a frame
        // -------------------------
1571
        for (int slot = 0; slot < nr_slots_per_frame[mu]; slot++) {
1572 1573
          // Is it a valid slot?
          map_shift = slot >> slot_shift_for_map; // in PRACH configuration index table slots are numbered wrt 60kHz
1574
          if ((s_map>>map_shift) & 0x01) {
1575 1576 1577
            // Valid slot

            // Additionally, for 30kHz/120kHz, we must check for the n_RA_Slot param also
1578 1579
            if (even_slot_invalid && (slot%2 == 0))
              continue; // no prach in even slots @ 30kHz/120kHz for 1 prach per 60khz slot/subframe
1580 1581 1582 1583

            // We're good: valid frame and valid slot
            // Compute all the PRACH occasions in the slot

1584 1585 1586
            prach_occasion_slot_t *slot_map = &prach_conf_period_list->prach_occasion_slot_map[frame_idx][slot];
            slot_map->nb_of_prach_occasion_in_time = N_t_slot;
            slot_map->nb_of_prach_occasion_in_freq = nb_fdm;
1587 1588
            slot_map->prach_occasion = malloc(N_t_slot * nb_fdm * sizeof(*slot_map->prach_occasion));
            AssertFatal(slot_map->prach_occasion, "no memory available\n");
1589
            for (int n_prach_occ_in_time = 0; n_prach_occ_in_time < N_t_slot; n_prach_occ_in_time++) {
1590
              uint8_t start_symbol = prach_conf_start_symbol + n_prach_occ_in_time * N_dur;
1591
              LOG_D(NR_MAC,"PRACH Occ in time %d\n", n_prach_occ_in_time);
1592

1593
              for (int n_prach_occ_in_freq = 0; n_prach_occ_in_freq < nb_fdm; n_prach_occ_in_freq++) {
1594 1595 1596 1597 1598 1599
                slot_map->prach_occasion[n_prach_occ_in_time * nb_fdm + n_prach_occ_in_freq] =
                    (prach_occasion_info_t){.start_symbol = start_symbol,
                                            .fdm = n_prach_occ_in_freq,
                                            .frame = frame,
                                            .slot = slot,
                                            .format = format};
1600
                prach_assoc_pattern->prach_conf_period_list[period_idx].nb_of_prach_occasion++;
1601

1602
                LOG_D(NR_MAC,"Adding a PRACH occasion: frame %u, slot-symbol %d-%d, occ_in_time-occ_in-freq %d-%d, nb ROs in conf period %d, for this slot: RO# in time %d, RO# in freq %d\n",
1603 1604 1605
                      frame, slot, start_symbol, n_prach_occ_in_time, n_prach_occ_in_freq, prach_conf_period_list->nb_of_prach_occasion,
                      slot_map->nb_of_prach_occasion_in_time,
                      slot_map->nb_of_prach_occasion_in_freq);
1606 1607 1608 1609 1610 1611 1612 1613 1614 1615
              } // For every freq in the slot
            } // For every time occasions in the slot
          } // Valid slot?
        } // For every slots in a frame
      } // Valid frame?
    } // For every frames in a prach configuration period
  } // For every prach configuration periods in the maximum association pattern period (160ms)
}

// Build the list of all the valid/transmitted SSBs according to the config
1616 1617
static void build_ssb_list(NR_UE_MAC_INST_t *mac)
{
1618
  // Create the list of transmitted SSBs
1619 1620
  const int bwp_id = mac->current_UL_BWP->bwp_id;
  ssb_list_info_t *ssb_list = &mac->ssb_list[bwp_id];
1621 1622 1623
  fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
  ssb_list->nb_tx_ssb = 0;

1624
  for (int ssb_index = 0; ssb_index < MAX_NB_SSB; ssb_index++) {
1625 1626 1627
    uint32_t curr_mask = cfg->ssb_table.ssb_mask_list[ssb_index / 32].ssb_mask;
    // check if if current SSB is transmitted
    if ((curr_mask >> (31 - (ssb_index % 32))) & 0x01) {
1628
      ssb_list->nb_ssb_per_index[ssb_index]=ssb_list->nb_tx_ssb;
1629
      ssb_list->nb_tx_ssb++;
1630
    }
1631
  }
1632
  ssb_list->tx_ssb = calloc(ssb_list->nb_tx_ssb, sizeof(*ssb_list->tx_ssb));
1633 1634 1635
}

// Map the transmitted SSBs to the ROs and create the association pattern according to the config
1636 1637
static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac)
{
1638 1639
  // Map SSBs to PRACH occasions
  // WIP: Assumption: No PRACH occasion is rejected because of a conflict with SSBs or TDD_UL_DL_ConfigurationCommon schedule
1640
  NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon;
1641 1642
  NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR ssb_perRACH_config = setup->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present;

1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653
  const struct {
    // true if more than one or exactly one SSB per RACH occasion, false if more than one RO per SSB
    bool multiple_ssb_per_ro;
    // Nb of SSBs per RACH or RACHs per SSB
    int ssb_rach_ratio;
  } config[] = {{false, 0}, {false, 8}, {false, 4}, {false, 2}, {true, 1}, {true, 2}, {true, 4}, {true, 8}, {true, 16}};
  AssertFatal(ssb_perRACH_config <= NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_sixteen,
              "Unsupported ssb_perRACH_config %d\n",
              ssb_perRACH_config);
  const bool multiple_ssb_per_ro = config[ssb_perRACH_config].multiple_ssb_per_ro;
  const int ssb_rach_ratio = config[ssb_perRACH_config].ssb_rach_ratio;
1654

1655
  LOG_D(NR_MAC,"SSB rach ratio %d, Multiple SSB per RO %d\n", ssb_rach_ratio, multiple_ssb_per_ro);
1656

1657 1658 1659
  const int bwp_id = mac->current_UL_BWP->bwp_id;
  ssb_list_info_t *ssb_list = &mac->ssb_list[bwp_id];

1660
  // Evaluate the number of PRACH configuration periods required to map all the SSBs and set the association period
1661 1662
  // WIP: Assumption for now is that all the PRACH configuration periods within a maximum association pattern period have the same
  // number of PRACH occasions
1663 1664
  //      (No PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule)
  //      There is only one possible association period which can contain up to 16 PRACH configuration periods
1665
  LOG_D(NR_MAC,"Evaluate the number of PRACH configuration periods required to map all the SSBs and set the association period\n");
1666 1667
  const int required_nb_of_prach_occasion =
      multiple_ssb_per_ro ? ((ssb_list->nb_tx_ssb - 1) + ssb_rach_ratio) / ssb_rach_ratio : ssb_list->nb_tx_ssb * ssb_rach_ratio;
1668

1669
  prach_association_pattern_t *prach_assoc_pattern = &mac->prach_assoc_pattern[bwp_id];
1670 1671 1672 1673 1674 1675 1676 1677
  const prach_conf_period_t *prach_conf_period = &prach_assoc_pattern->prach_conf_period_list[0];
  AssertFatal(prach_conf_period->nb_of_prach_occasion > 0,
              "prach_conf_period->nb_of_prach_occasion shouldn't be 0 (nb_tx_ssb %d, ssb_rach_ratio %d)\n",
              ssb_list->nb_tx_ssb,
              ssb_rach_ratio);
  prach_association_period_t *prach_association_period = &prach_assoc_pattern->prach_association_period_list[0];
  const int required_nb_of_prach_conf_period =
      ((required_nb_of_prach_occasion - 1) + prach_conf_period->nb_of_prach_occasion) / prach_conf_period->nb_of_prach_occasion;
1678 1679

  if (required_nb_of_prach_conf_period == 1) {
1680
    prach_association_period->nb_of_prach_conf_period = 1;
1681 1682
  }
  else if (required_nb_of_prach_conf_period == 2) {
1683
    prach_association_period->nb_of_prach_conf_period = 2;
1684 1685
  }
  else if (required_nb_of_prach_conf_period <= 4) {
1686
    prach_association_period->nb_of_prach_conf_period = 4;
1687 1688
  }
  else if (required_nb_of_prach_conf_period <= 8) {
1689
    prach_association_period->nb_of_prach_conf_period = 8;
1690 1691
  }
  else if (required_nb_of_prach_conf_period <= 16) {
1692
    prach_association_period->nb_of_prach_conf_period = 16;
1693 1694 1695 1696 1697
  }
  else {
    AssertFatal(1 == 0, "Invalid number of PRACH config periods within an association period %d\n", required_nb_of_prach_conf_period);
  }

1698
  prach_assoc_pattern->nb_of_assoc_period = 1; // WIP: only one possible association period
1699 1700
  prach_association_period->nb_of_frame = prach_association_period->nb_of_prach_conf_period * prach_conf_period->nb_of_frame;
  prach_assoc_pattern->nb_of_frame = prach_association_period->nb_of_frame;
1701

1702 1703 1704 1705
  LOG_D(NR_MAC,
        "Assoc period %d, Nb of frames in assoc period %d\n",
        prach_association_period->nb_of_prach_conf_period,
        prach_association_period->nb_of_frame);
1706

1707 1708 1709
  // Set the starting PRACH Configuration period index in the association_pattern map for this particular association period
  int prach_configuration_period_idx =
      0; // WIP: only one possible association period so the starting PRACH configuration period is automatically 0
1710 1711

  // Map all the association periods within the association pattern period
1712
  LOG_D(NR_MAC,"Proceed to the SSB to RO mapping\n");
1713 1714 1715 1716 1717 1718 1719 1720
  // Check if we need to map multiple SSBs per RO or multiple ROs per SSB
  if (multiple_ssb_per_ro) {
    const prach_association_period_t *end =
        prach_assoc_pattern->prach_association_period_list + prach_assoc_pattern->nb_of_assoc_period;
    for (prach_association_period_t *prach_period = prach_assoc_pattern->prach_association_period_list; prach_period < end;
         prach_period++) {
      // Set the starting PRACH Configuration period index in the association_pattern map for this particular association period
      // WIP: only one possible association period so the starting PRACH configuration period is automatically 0
1721 1722
      // WIP: For the moment, only map each SSB idx once per association period if configuration is multiple SSBs per RO
      //      this is true if no PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule
1723 1724 1725 1726 1727
      int ssb_idx = 0;
      bool done = false;
      for (int i = 0; i < prach_period->nb_of_prach_conf_period && !done; i++, prach_configuration_period_idx++) {
        prach_period->prach_conf_period_list[i] = &prach_assoc_pattern->prach_conf_period_list[prach_configuration_period_idx];
        prach_conf_period_t *prach_conf = prach_period->prach_conf_period_list[i];
1728 1729
        // Build the association period with its association PRACH Configuration indexes
        // Go through all the ROs within the PRACH config period
1730 1731 1732 1733 1734 1735 1736
        for (int frame = 0; frame < prach_conf->nb_of_frame && !done; frame++) {
          for (int slot = 0; slot < prach_conf->nb_of_slot && !done; slot++) {
            prach_occasion_slot_t *slot_map = &prach_conf->prach_occasion_slot_map[frame][slot];
            for (int ro_in_time = 0; ro_in_time < slot_map->nb_of_prach_occasion_in_time && !done; ro_in_time++) {
              for (int ro_in_freq = 0; ro_in_freq < slot_map->nb_of_prach_occasion_in_freq && !done; ro_in_freq++) {
                prach_occasion_info_t *ro_p =
                    slot_map->prach_occasion + ro_in_time * slot_map->nb_of_prach_occasion_in_freq + ro_in_freq;
1737 1738 1739
                // Go through the list of transmitted SSBs and map the required amount of SSBs to this RO
                // WIP: For the moment, only map each SSB idx once per association period if configuration is multiple SSBs per RO
                //      this is true if no PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule
1740 1741
                for (; ssb_idx < ssb_list->nb_tx_ssb; ssb_idx++) {
                  ssb_info_t *tx_ssb = ssb_list->tx_ssb + ssb_idx;
1742
                  // Map only the transmitted ssb_idx
1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762
                  ro_p->mapped_ssb_idx[ro_p->nb_mapped_ssb] = ssb_idx;
                  ro_p->nb_mapped_ssb++;
                  AssertFatal(MAX_NB_RO_PER_SSB_IN_ASSOCIATION_PATTERN > tx_ssb->nb_mapped_ro + 1,
                              "Too many mapped ROs (%d) to a single SSB\n",
                              tx_ssb->nb_mapped_ro);
                  tx_ssb->mapped_ro[tx_ssb->nb_mapped_ro] = ro_p;
                  tx_ssb->nb_mapped_ro++;
                  LOG_D(NR_MAC,
                        "Mapped ssb_idx %u to RO slot-symbol %u-%u, %u-%u-%u/%u\n"
                        "Nb mapped ROs for this ssb idx: in the association period only %u\n",
                        ssb_idx,
                        ro_p->slot,
                        ro_p->start_symbol,
                        slot,
                        ro_in_time,
                        ro_in_freq,
                        slot_map->nb_of_prach_occasion_in_freq,
                        tx_ssb->nb_mapped_ro);
                  // If all the required SSBs are mapped to this RO, exit the loop of SSBs
                  if (ro_p->nb_mapped_ssb == ssb_rach_ratio) {
1763 1764 1765
                      ssb_idx++;
                      break;
                    }
1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777
                }
                done = MAX_NB_SSB == ssb_idx;
              }
            }
          }
        }
      }
    }
  } else {
    prach_association_period_t *end = prach_assoc_pattern->prach_association_period_list + prach_assoc_pattern->nb_of_assoc_period;
    for (prach_association_period_t *prach_period = prach_assoc_pattern->prach_association_period_list; prach_period < end;
         prach_period++) {
1778
      // Go through the list of transmitted SSBs
1779 1780
      for (int ssb_idx = 0; ssb_idx < ssb_list->nb_tx_ssb; ssb_idx++) {
        ssb_info_t *tx_ssb = ssb_list->tx_ssb + ssb_idx;
1781
        uint8_t nb_mapped_ro_in_association_period=0; // Reset the nb of mapped ROs for the new SSB index
1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817
        bool done = false;
        // Map all the required ROs to this SSB
        // Go through the list of PRACH config periods within this association period
        for (int i = 0; i < prach_period->nb_of_prach_conf_period && !done; i++, prach_configuration_period_idx++) {
          // Build the association period with its association PRACH Configuration indexes
          prach_period->prach_conf_period_list[i] = &prach_assoc_pattern->prach_conf_period_list[prach_configuration_period_idx];
	  prach_conf_period_t *prach_conf = prach_period->prach_conf_period_list[i];
          for (int frame = 0; frame < prach_conf->nb_of_frame && !done; frame++) {
            for (int slot = 0; slot < prach_conf->nb_of_slot && !done; slot++) {
              prach_occasion_slot_t *slot_map = &prach_conf->prach_occasion_slot_map[frame][slot];
              for (int ro_in_time = 0; ro_in_time < slot_map->nb_of_prach_occasion_in_time && !done; ro_in_time++) {
                for (int ro_in_freq = 0; ro_in_freq < slot_map->nb_of_prach_occasion_in_freq && !done; ro_in_freq++) {
                  prach_occasion_info_t *ro_p =
                      slot_map->prach_occasion + ro_in_time * slot_map->nb_of_prach_occasion_in_freq + ro_in_freq;
                  ro_p->mapped_ssb_idx[0] = ssb_idx;
                  ro_p->nb_mapped_ssb = 1;
                  AssertFatal(MAX_NB_RO_PER_SSB_IN_ASSOCIATION_PATTERN > tx_ssb->nb_mapped_ro + 1,
                              "Too many mapped ROs (%d) to a single SSB\n",
                              tx_ssb->nb_mapped_ro);
                  tx_ssb->mapped_ro[tx_ssb->nb_mapped_ro] = ro_p;
                  tx_ssb->nb_mapped_ro++;
                  nb_mapped_ro_in_association_period++;
                  done = nb_mapped_ro_in_association_period == ssb_rach_ratio;

                  LOG_D(NR_MAC,
                        "Mapped ssb_idx %u to RO slot-symbol %u-%u, %u-%u-%u/%u\n"
                        "Nb mapped ROs for this ssb idx: in the association period only %u / total %u\n",
                        ssb_idx,
                        ro_p->slot,
                        ro_p->start_symbol,
                        slot,
                        ro_in_time,
                        ro_in_freq,
                        slot_map->nb_of_prach_occasion_in_freq,
                        tx_ssb->nb_mapped_ro,
                        nb_mapped_ro_in_association_period);
1818 1819

                  // Exit the loop if this SSB has been mapped to all the required ROs
1820 1821 1822
                  // WIP: Assuming that ssb_rach_ratio equals the maximum nb of times a given ssb_idx is mapped within an
                  // association period:
                  //      this is true if no PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule
1823 1824 1825
                }
              }
            }
1826 1827 1828 1829 1830
          }
        }
      }
    }
  }
1831 1832 1833
}

// Returns a RACH occasion if any matches the SSB idx, the frame and the slot
1834 1835
static int get_nr_prach_info_from_ssb_index(prach_association_pattern_t *prach_assoc_pattern,
                                            uint8_t ssb_idx,
1836 1837
                                            int frame,
                                            int slot,
francescomani's avatar
francescomani committed
1838 1839 1840
                                            ssb_list_info_t *ssb_list,
                                            prach_occasion_info_t **prach_occasion_info_pp)
{
1841 1842 1843 1844 1845 1846 1847 1848 1849 1850
  ssb_info_t *ssb_info_p;
  prach_occasion_slot_t *prach_occasion_slot_p = NULL;

  *prach_occasion_info_pp = NULL;

  // Search for a matching RO slot in the SSB_to_RO map
  // A valid RO slot will match:
  //      - ssb_idx mapped to one of the ROs in that RO slot
  //      - exact slot number
  //      - frame offset
francescomani's avatar
francescomani committed
1851
  ssb_info_p = &ssb_list->tx_ssb[ssb_idx];
1852
  LOG_D(NR_MAC, "checking for prach : ssb_info_p->nb_mapped_ro %d\n", ssb_info_p->nb_mapped_ro);
1853
  for (uint8_t n_mapped_ro=0; n_mapped_ro<ssb_info_p->nb_mapped_ro; n_mapped_ro++) {
1854 1855
    LOG_D(NR_MAC,"%d.%d: mapped_ro[%d]->frame.slot %d.%d, prach_assoc_pattern->nb_of_frame %d\n",
          frame,slot,n_mapped_ro,ssb_info_p->mapped_ro[n_mapped_ro]->frame,ssb_info_p->mapped_ro[n_mapped_ro]->slot,prach_assoc_pattern->nb_of_frame);
1856
    if ((slot == ssb_info_p->mapped_ro[n_mapped_ro]->slot) &&
1857
        (ssb_info_p->mapped_ro[n_mapped_ro]->frame == (frame % prach_assoc_pattern->nb_of_frame))) {
1858

1859 1860 1861
      uint8_t prach_config_period_nb = ssb_info_p->mapped_ro[n_mapped_ro]->frame / prach_assoc_pattern->prach_conf_period_list[0].nb_of_frame;
      uint8_t frame_nb_in_prach_config_period = ssb_info_p->mapped_ro[n_mapped_ro]->frame % prach_assoc_pattern->prach_conf_period_list[0].nb_of_frame;
      prach_occasion_slot_p = &prach_assoc_pattern->prach_conf_period_list[prach_config_period_nb].prach_occasion_slot_map[frame_nb_in_prach_config_period][slot];
1862 1863 1864 1865
    }
  }

  // If there is a matching RO slot in the SSB_to_RO map
1866
  if (NULL != prach_occasion_slot_p) {
1867 1868 1869 1870 1871 1872 1873
    // A random RO mapped to the SSB index should be selected in the slot

    // First count the number of times the SSB index is found in that RO
    uint8_t nb_mapped_ssb = 0;

    for (int ro_in_time=0; ro_in_time < prach_occasion_slot_p->nb_of_prach_occasion_in_time; ro_in_time++) {
      for (int ro_in_freq=0; ro_in_freq < prach_occasion_slot_p->nb_of_prach_occasion_in_freq; ro_in_freq++) {
1874 1875 1876 1877
        prach_occasion_info_t *ro_p =
            prach_occasion_slot_p->prach_occasion + ro_in_time * prach_occasion_slot_p->nb_of_prach_occasion_in_freq + ro_in_freq;
        for (uint8_t ssb_nb = 0; ssb_nb < ro_p->nb_mapped_ssb; ssb_nb++) {
          if (ro_p->mapped_ssb_idx[ssb_nb] == ssb_idx) {
1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892
            nb_mapped_ssb++;
          }
        }
      }
    }

    // Choose a random SSB nb
    uint8_t random_ssb_nb = 0;

    random_ssb_nb = ((taus()) % nb_mapped_ssb);

    // Select the RO according to the chosen random SSB nb
    nb_mapped_ssb=0;
    for (int ro_in_time=0; ro_in_time < prach_occasion_slot_p->nb_of_prach_occasion_in_time; ro_in_time++) {
      for (int ro_in_freq=0; ro_in_freq < prach_occasion_slot_p->nb_of_prach_occasion_in_freq; ro_in_freq++) {
1893 1894 1895 1896
        prach_occasion_info_t *ro_p =
            prach_occasion_slot_p->prach_occasion + ro_in_time * prach_occasion_slot_p->nb_of_prach_occasion_in_freq + ro_in_freq;
        for (uint8_t ssb_nb = 0; ssb_nb < ro_p->nb_mapped_ssb; ssb_nb++) {
          if (ro_p->mapped_ssb_idx[ssb_nb] == ssb_idx) {
1897
            if (nb_mapped_ssb == random_ssb_nb) {
1898
              *prach_occasion_info_pp = ro_p;
1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913
              return 1;
            }
            else {
              nb_mapped_ssb++;
            }
          }
        }
      }
    }
  }

  return 0;
}

// Build the SSB to RO mapping upon RRC configuration update
1914 1915
void build_ssb_to_ro_map(NR_UE_MAC_INST_t *mac)
{
1916
  // Clear all the lists and maps
1917
  const int bwp_id = mac->current_UL_BWP->bwp_id;
1918
  free_rach_structures(mac, bwp_id);
1919 1920
  memset(&mac->ssb_list[bwp_id], 0, sizeof(ssb_list_info_t));
  memset(&mac->prach_assoc_pattern[bwp_id], 0, sizeof(prach_association_pattern_t));
1921 1922

  // Build the list of all the valid RACH occasions in the maximum association pattern period according to the PRACH config
1923 1924
  LOG_D(NR_MAC,"Build RO list\n");
  build_ro_list(mac);
1925 1926

  // Build the list of all the valid/transmitted SSBs according to the config
1927 1928
  LOG_D(NR_MAC,"Build SSB list\n");
  build_ssb_list(mac);
1929 1930

  // Map the transmitted SSBs to the ROs and create the association pattern according to the config
1931 1932 1933
  LOG_D(NR_MAC,"Map SSB to RO\n");
  map_ssb_to_ro(mac);
  LOG_D(NR_MAC,"Map SSB to RO done\n");
1934 1935
}

1936
void nr_ue_pucch_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, int slotP, void *phy_data)
1937 1938 1939 1940 1941 1942 1943
{
  PUCCH_sched_t pucch[3] = {0}; // TODO the size might change in the future in case of multiple SR or multiple CSI in a slot

  mac->nr_ue_emul_l1.num_srs = 0;
  mac->nr_ue_emul_l1.num_harqs = 0;
  mac->nr_ue_emul_l1.num_csi_reports = 0;
  int num_res = 0;
1944 1945

  // SR
1946 1947
  if (mac->state == UE_CONNECTED && trigger_periodic_scheduling_request(mac, &pucch[0], frameP, slotP)) {
    num_res++;
1948
    /* sr_payload = 1 means that this is a positive SR, sr_payload = 0 means that it is a negative SR */
1949
    pucch[0].sr_payload = nr_ue_get_SR(mac, frameP, slotP);
1950
  }
1951 1952

  // CSI
1953
  int csi_res = 0;
francescomani's avatar
francescomani committed
1954
  if (mac->state == UE_CONNECTED)
1955 1956 1957
    csi_res = nr_get_csi_measurements(mac, frameP, slotP, &pucch[num_res]);
  if (csi_res > 0) {
    num_res += csi_res;
1958 1959
  }

1960 1961 1962 1963
  // ACKNACK
  bool any_harq = get_downlink_ack(mac, frameP, slotP, &pucch[num_res]);
  if (any_harq)
    num_res++;
1964

1965 1966
  if (num_res == 0)
    return;
1967
  // do no transmit pucch if only SR scheduled and it is negative
1968
  if (num_res == 1 && pucch[0].n_sr > 0 && pucch[0].sr_payload == 0)
1969 1970
    return;

1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984
  if (num_res > 1)
    multiplex_pucch_resource(mac, pucch, num_res);
  for (int j = 0; j < num_res; j++) {
    if (pucch[j].n_harq + pucch[j].n_sr + pucch[j].n_csi != 0) {
      LOG_D(NR_MAC,
            "%d.%d configure pucch, O_ACK %d, O_SR %d, O_CSI %d\n",
            frameP,
            slotP,
            pucch[j].n_harq,
            pucch[j].n_sr,
            pucch[j].n_csi);
      mac->nr_ue_emul_l1.num_srs = pucch[j].n_sr;
      mac->nr_ue_emul_l1.num_harqs = pucch[j].n_harq;
      mac->nr_ue_emul_l1.num_csi_reports = pucch[j].n_csi;
1985 1986 1987 1988 1989
      fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frameP, slotP, FAPI_NR_UL_CONFIG_TYPE_PUCCH);
      if (!pdu) {
        LOG_E(NR_MAC, "Error in pucch allocation\n");
        return;
      }
1990
      mac->nr_ue_emul_l1.active_uci_sfn_slot = NFAPI_SFNSLOT2HEX(frameP, slotP);
1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001
      int ret = nr_ue_configure_pucch(mac,
                                      slotP,
                                      mac->crnti, // FIXME not sure this is valid for all pucch instances
                                      &pucch[j],
                                      &pdu->pucch_config_pdu);
      if (ret != 0)
        remove_ul_config_last_item(pdu);
      release_ul_config(pdu, false);
    }
    if (mac->if_module != NULL && mac->if_module->scheduled_response != NULL) {
      nr_scheduled_response_t scheduled_response = {.ul_config = mac->ul_config_request + slotP,
2002
                                                    .mac = mac,
2003
                                                    .module_id = mac->ue_id,
2004 2005
                                                    .CC_id = 0 /*TBR fix*/,
                                                    .phy_data = phy_data};
2006
      mac->if_module->scheduled_response(&scheduled_response);
2007
    }
2008 2009 2010
  }
}

2011 2012 2013
void nr_schedule_csi_for_im(NR_UE_MAC_INST_t *mac, int frame, int slot)
{
  if (!mac->sc_info.csi_MeasConfig)
francescomani's avatar
francescomani committed
2014
    return;
francescomani's avatar
francescomani committed
2015

2016
  NR_CSI_MeasConfig_t *csi_measconfig = mac->sc_info.csi_MeasConfig;
2017

francescomani's avatar
francescomani committed
2018 2019
  if (csi_measconfig->csi_IM_ResourceToAddModList == NULL)
    return;
francescomani's avatar
francescomani committed
2020

2021
  fapi_nr_dl_config_request_t *dl_config = get_dl_config_request(mac, slot);
francescomani's avatar
francescomani committed
2022 2023
  NR_CSI_IM_Resource_t *imcsi;
  int period, offset;
2024

2025
  NR_UE_DL_BWP_t *current_DL_BWP = mac->current_DL_BWP;
francescomani's avatar
francescomani committed
2026 2027 2028
  int mu = current_DL_BWP->scs;
  uint16_t bwp_size = current_DL_BWP->BWPSize;
  uint16_t bwp_start = current_DL_BWP->BWPStart;
francescomani's avatar
francescomani committed
2029 2030 2031 2032 2033 2034 2035

  for (int id = 0; id < csi_measconfig->csi_IM_ResourceToAddModList->list.count; id++){
    imcsi = csi_measconfig->csi_IM_ResourceToAddModList->list.array[id];
    csi_period_offset(NULL,imcsi->periodicityAndOffset,&period,&offset);
    if((frame*nr_slots_per_frame[mu]+slot-offset)%period != 0)
      continue;
    fapi_nr_dl_config_csiim_pdu_rel15_t *csiim_config_pdu = &dl_config->dl_config_list[dl_config->number_pdus].csiim_config_pdu.csiim_config_rel15;
2036 2037
    csiim_config_pdu->bwp_size = bwp_size;
    csiim_config_pdu->bwp_start = bwp_start;
francescomani's avatar
francescomani committed
2038 2039 2040 2041 2042 2043
    csiim_config_pdu->subcarrier_spacing = mu;
    csiim_config_pdu->start_rb = imcsi->freqBand->startingRB;
    csiim_config_pdu->nr_of_rbs = imcsi->freqBand->nrofRBs;
    // As specified in 5.2.2.4 of 38.214
    switch (imcsi->csi_IM_ResourceElementPattern->present) {
      case NR_CSI_IM_Resource__csi_IM_ResourceElementPattern_PR_pattern0:
2044 2045 2046 2047
        for (int i = 0; i < 4; i++) {
          csiim_config_pdu->k_csiim[i] =
              (imcsi->csi_IM_ResourceElementPattern->choice.pattern0->subcarrierLocation_p0 << 1) + (i >> 1);
          csiim_config_pdu->l_csiim[i] = imcsi->csi_IM_ResourceElementPattern->choice.pattern0->symbolLocation_p0 + (i % 2);
francescomani's avatar
francescomani committed
2048
        }
francescomani's avatar
francescomani committed
2049 2050
        break;
      case NR_CSI_IM_Resource__csi_IM_ResourceElementPattern_PR_pattern1:
2051 2052
        for (int i = 0; i < 4; i++) {
          csiim_config_pdu->k_csiim[i] = (imcsi->csi_IM_ResourceElementPattern->choice.pattern1->subcarrierLocation_p1 << 2) + i;
francescomani's avatar
francescomani committed
2053 2054 2055 2056
          csiim_config_pdu->l_csiim[i] = imcsi->csi_IM_ResourceElementPattern->choice.pattern1->symbolLocation_p1;
        }
        break;
      default:
2057
        AssertFatal(1 == 0, "Invalid CSI-IM pattern\n");
francescomani's avatar
francescomani committed
2058
    }
francescomani's avatar
francescomani committed
2059
    dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_CSI_IM;
2060
    dl_config->number_pdus += 1;
francescomani's avatar
francescomani committed
2061
  }
2062 2063
}

2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084
NR_CSI_ResourceConfigId_t find_CSI_resourceconfig(NR_CSI_MeasConfig_t *csi_measconfig,
                                                  NR_BWP_Id_t dl_bwp_id,
                                                  NR_NZP_CSI_RS_ResourceId_t csi_id)
{
  bool found = false;
  for (int csi_list = 0; csi_list < csi_measconfig->csi_ResourceConfigToAddModList->list.count; csi_list++) {
    NR_CSI_ResourceConfig_t *csires = csi_measconfig->csi_ResourceConfigToAddModList->list.array[csi_list];
    if(csires->bwp_Id != dl_bwp_id)
      continue;
    struct NR_CSI_ResourceConfig__csi_RS_ResourceSetList *resset = &csires->csi_RS_ResourceSetList;
    if(resset->present != NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB)
      continue;
    if(!resset->choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList)
      continue;
    for(int i = 0; i < resset->choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList->list.count; i++) {
      NR_NZP_CSI_RS_ResourceSetId_t *res_id = resset->choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList->list.array[i];
      AssertFatal(res_id, "NR_NZP_CSI_RS_ResourceSetId shouldn't be NULL\n");
      struct NR_CSI_MeasConfig__nzp_CSI_RS_ResourceSetToAddModList *res_list = csi_measconfig->nzp_CSI_RS_ResourceSetToAddModList;
      AssertFatal(res_list, "nzp_CSI_RS_ResourceSetToAddModList shouldn't be NULL\n");
      for (int j = 0; j < res_list->list.count; j++) {
        NR_NZP_CSI_RS_ResourceSet_t *csi_res = res_list->list.array[j];
2085
        if (*res_id != csi_res->nzp_CSI_ResourceSetId)
2086 2087
          continue;
        for (int k = 0; k < csi_res->nzp_CSI_RS_Resources.list.count; k++) {
2088
          AssertFatal(csi_res->nzp_CSI_RS_Resources.list.array[k], "NZP_CSI_RS_ResourceId shoulan't be NULL\n");
2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107
          if (csi_id == *csi_res->nzp_CSI_RS_Resources.list.array[k]) {
            found = true;
            break;
          }
        }
        if (found && csi_res->trs_Info)
          // CRI-RS for Tracking (not implemented yet)
          // in this case we there is no associated CSI report
          // therefore to signal this we return a value higher than
          // maxNrofCSI-ResourceConfigurations
          return NR_maxNrofCSI_ResourceConfigurations + 1;
        else if (found)
          return csires->csi_ResourceConfigId;
      }
    }
  }
  return -1; // not found any CSI-resource in current DL BWP associated with this CSI-RS ID
}

2108
uint8_t set_csirs_measurement_bitmap(NR_CSI_MeasConfig_t *csi_measconfig, NR_CSI_ResourceConfigId_t csi_res_id)
2109 2110 2111 2112 2113 2114 2115 2116 2117 2118
{
  uint8_t meas_bitmap = 0;
  if (csi_res_id > NR_maxNrofCSI_ResourceConfigurations)
    return meas_bitmap; // CSI-RS for tracking
  for(int i = 0; i < csi_measconfig->csi_ReportConfigToAddModList->list.count; i++) {
    struct NR_CSI_ReportConfig *report_config = csi_measconfig->csi_ReportConfigToAddModList->list.array[i];
    if(report_config->resourcesForChannelMeasurement != csi_res_id)
      continue;
    // bit 0 RSRP bit 1 RI bit 2 LI bit 3 PMI bit 4 CQI bit 5 i1
    switch (report_config->reportQuantity.present) {
2119
      case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI:
2120 2121
        meas_bitmap += (1 << 1) + (1 << 3) + (1 << 4);
        break;
2122
      case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1:
2123 2124
        meas_bitmap += (1 << 1) + (1 << 5);
        break;
2125
      case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1_CQI:
2126 2127
        meas_bitmap += (1 << 1) + (1 << 4) + (1 << 5);
        break;
2128
      case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI:
2129 2130
        meas_bitmap += (1 << 1) + (1 << 4);
        break;
2131
      case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP:
2132 2133
        meas_bitmap += 1;
        break;
2134
      case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI:
2135 2136
        meas_bitmap += (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4);
        break;
2137 2138
      default:
        AssertFatal(false, "Unexpected measurement report type %d\n", report_config->reportQuantity.present);
2139 2140 2141 2142 2143 2144
    }
  }
  AssertFatal(meas_bitmap > 0, "Expected to have at least 1 measurement configured for CSI-RS\n");
  return meas_bitmap;
}

2145 2146 2147
void nr_schedule_csirs_reception(NR_UE_MAC_INST_t *mac, int frame, int slot)
{
  if (!mac->sc_info.csi_MeasConfig)
francescomani's avatar
francescomani committed
2148
    return;
2149

2150
  NR_CSI_MeasConfig_t *csi_measconfig = mac->sc_info.csi_MeasConfig;
2151

francescomani's avatar
francescomani committed
2152 2153
  if (csi_measconfig->nzp_CSI_RS_ResourceToAddModList == NULL)
    return;
2154

2155
  fapi_nr_dl_config_request_t *dl_config = get_dl_config_request(mac, slot);
2156
  NR_UE_DL_BWP_t *current_DL_BWP = mac->current_DL_BWP;
francescomani's avatar
francescomani committed
2157
  NR_BWP_Id_t dl_bwp_id = current_DL_BWP->bwp_id;
2158

francescomani's avatar
francescomani committed
2159 2160 2161
  int mu = current_DL_BWP->scs;
  uint16_t bwp_size = current_DL_BWP->BWPSize;
  uint16_t bwp_start = current_DL_BWP->BWPStart;
francescomani's avatar
francescomani committed
2162 2163

  for (int id = 0; id < csi_measconfig->nzp_CSI_RS_ResourceToAddModList->list.count; id++){
2164 2165 2166 2167
    NR_NZP_CSI_RS_Resource_t *nzpcsi = csi_measconfig->nzp_CSI_RS_ResourceToAddModList->list.array[id];
    int period, offset;
    csi_period_offset(NULL, nzpcsi->periodicityAndOffset, &period, &offset);
    if((frame * nr_slots_per_frame[mu] + slot-offset) % period != 0)
2168
      continue;
2169
    NR_CSI_ResourceConfigId_t csi_res_id = find_CSI_resourceconfig(csi_measconfig, dl_bwp_id, nzpcsi->nzp_CSI_RS_ResourceId);
2170 2171
    // do not schedule reseption of this CSI-RS if not associated with current BWP
    if(csi_res_id < 0)
francescomani's avatar
francescomani committed
2172
      continue;
2173
    LOG_D(MAC,"Scheduling reception of CSI-RS in frame %d slot %d\n", frame, slot);
francescomani's avatar
francescomani committed
2174
    fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu = &dl_config->dl_config_list[dl_config->number_pdus].csirs_config_pdu.csirs_config_rel15;
2175
    csirs_config_pdu->measurement_bitmap = set_csirs_measurement_bitmap(csi_measconfig, csi_res_id);
francescomani's avatar
francescomani committed
2176 2177
    NR_CSI_RS_ResourceMapping_t  resourceMapping = nzpcsi->resourceMapping;
    csirs_config_pdu->subcarrier_spacing = mu;
francescomani's avatar
francescomani committed
2178
    csirs_config_pdu->cyclic_prefix = current_DL_BWP->cyclicprefix ? *current_DL_BWP->cyclicprefix : 0;
2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192

    // According to last paragraph of TS 38.214 5.2.2.3.1
    if (resourceMapping.freqBand.startingRB < bwp_start) {
      csirs_config_pdu->start_rb = bwp_start;
    } else {
      csirs_config_pdu->start_rb = resourceMapping.freqBand.startingRB;
    }
    if (resourceMapping.freqBand.nrofRBs > (bwp_start + bwp_size - csirs_config_pdu->start_rb)) {
      csirs_config_pdu->nr_of_rbs = bwp_start + bwp_size - csirs_config_pdu->start_rb;
    } else {
      csirs_config_pdu->nr_of_rbs = resourceMapping.freqBand.nrofRBs;
    }
    AssertFatal(csirs_config_pdu->nr_of_rbs >= 24, "CSI-RS has %d RBs, but the minimum is 24\n", csirs_config_pdu->nr_of_rbs);

francescomani's avatar
francescomani committed
2193 2194 2195 2196 2197 2198 2199 2200 2201 2202
    csirs_config_pdu->csi_type = 1; // NZP-CSI-RS
    csirs_config_pdu->symb_l0 = resourceMapping.firstOFDMSymbolInTimeDomain;
    if (resourceMapping.firstOFDMSymbolInTimeDomain2)
      csirs_config_pdu->symb_l1 = *resourceMapping.firstOFDMSymbolInTimeDomain2;
    csirs_config_pdu->cdm_type = resourceMapping.cdm_Type;
    csirs_config_pdu->freq_density = resourceMapping.density.present;
    if ((resourceMapping.density.present == NR_CSI_RS_ResourceMapping__density_PR_dot5)
        && (resourceMapping.density.choice.dot5 == NR_CSI_RS_ResourceMapping__density__dot5_evenPRBs))
      csirs_config_pdu->freq_density--;
    csirs_config_pdu->scramb_id = nzpcsi->scramblingID;
2203 2204 2205 2206 2207
    csirs_config_pdu->power_control_offset = nzpcsi->powerControlOffset + 8;
    if (nzpcsi->powerControlOffsetSS)
      csirs_config_pdu->power_control_offset_ss = *nzpcsi->powerControlOffsetSS;
    else
      csirs_config_pdu->power_control_offset_ss = 1; // 0 dB
francescomani's avatar
francescomani committed
2208 2209 2210
    switch(resourceMapping.frequencyDomainAllocation.present){
      case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row1:
        csirs_config_pdu->row = 1;
2211
        csirs_config_pdu->freq_domain = ((resourceMapping.frequencyDomainAllocation.choice.row1.buf[0]) >> 4) & 0x0f;
francescomani's avatar
francescomani committed
2212 2213 2214
        break;
      case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row2:
        csirs_config_pdu->row = 2;
2215 2216
        csirs_config_pdu->freq_domain = (((resourceMapping.frequencyDomainAllocation.choice.row2.buf[1] >> 4) & 0x0f)
                                         | ((resourceMapping.frequencyDomainAllocation.choice.row2.buf[0] << 4) & 0xff0));
francescomani's avatar
francescomani committed
2217 2218 2219
        break;
      case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row4:
        csirs_config_pdu->row = 4;
2220
        csirs_config_pdu->freq_domain = ((resourceMapping.frequencyDomainAllocation.choice.row4.buf[0]) >> 5) & 0x07;
francescomani's avatar
francescomani committed
2221 2222
        break;
      case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_other:
2223
        csirs_config_pdu->freq_domain = ((resourceMapping.frequencyDomainAllocation.choice.other.buf[0]) >> 2) & 0x3f;
francescomani's avatar
francescomani committed
2224
        // determining the row of table 7.4.1.5.3-1 in 38.211
2225
        switch (resourceMapping.nrofPorts) {
francescomani's avatar
francescomani committed
2226
          case NR_CSI_RS_ResourceMapping__nrofPorts_p1:
2227
            AssertFatal(1 == 0, "Resource with 1 CSI port shouldn't be within other rows\n");
2228
            break;
francescomani's avatar
francescomani committed
2229 2230
          case NR_CSI_RS_ResourceMapping__nrofPorts_p2:
            csirs_config_pdu->row = 3;
2231
            break;
francescomani's avatar
francescomani committed
2232 2233
          case NR_CSI_RS_ResourceMapping__nrofPorts_p4:
            csirs_config_pdu->row = 5;
2234
            break;
francescomani's avatar
francescomani committed
2235 2236 2237
          case NR_CSI_RS_ResourceMapping__nrofPorts_p8:
            if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2)
              csirs_config_pdu->row = 8;
2238
            else {
francescomani's avatar
francescomani committed
2239
              int num_k = 0;
2240 2241 2242
              for (int k = 0; k < 6; k++)
                num_k += (((csirs_config_pdu->freq_domain) >> k) & 0x01);
              if (num_k == 4)
francescomani's avatar
francescomani committed
2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262
                csirs_config_pdu->row = 6;
              else
                csirs_config_pdu->row = 7;
            }
            break;
          case NR_CSI_RS_ResourceMapping__nrofPorts_p12:
            if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2)
              csirs_config_pdu->row = 10;
            else
              csirs_config_pdu->row = 9;
            break;
          case NR_CSI_RS_ResourceMapping__nrofPorts_p16:
            if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2)
              csirs_config_pdu->row = 12;
            else
              csirs_config_pdu->row = 11;
            break;
          case NR_CSI_RS_ResourceMapping__nrofPorts_p24:
            if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2)
              csirs_config_pdu->row = 14;
2263
            else {
francescomani's avatar
francescomani committed
2264 2265 2266 2267
              if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm8_FD2_TD4)
                csirs_config_pdu->row = 15;
              else
                csirs_config_pdu->row = 13;
2268 2269
            }
            break;
francescomani's avatar
francescomani committed
2270 2271 2272
          case NR_CSI_RS_ResourceMapping__nrofPorts_p32:
            if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2)
              csirs_config_pdu->row = 17;
2273
            else {
francescomani's avatar
francescomani committed
2274 2275 2276 2277 2278 2279
              if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm8_FD2_TD4)
                csirs_config_pdu->row = 18;
              else
                csirs_config_pdu->row = 16;
            }
            break;
2280 2281
          default:
            AssertFatal(1 == 0, "Invalid number of ports in CSI-RS resource\n");
2282
        }
francescomani's avatar
francescomani committed
2283 2284
        break;
      default:
2285
        AssertFatal(1 == 0, "Invalid freqency domain allocation in CSI-RS resource\n");
2286
    }
francescomani's avatar
francescomani committed
2287
    dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_CSI_RS;
2288
    dl_config->number_pdus += 1;
2289 2290 2291
  }
}

2292 2293 2294 2295
// This function schedules the PRACH according to prach_ConfigurationIndex and TS 38.211, tables 6.3.3.2.x
// PRACH formats 9, 10, 11 are corresponding to dual PRACH format configurations A1/B1, A2/B2, A3/B3.
// - todo:
// - Partial configuration is actually already stored in (fapi_nr_prach_config_t) &mac->phy_config.config_req->prach_config
2296
static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, sub_frame_t slotP)
laurent's avatar
laurent committed
2297
{
2298
  RA_config_t *ra = &mac->ra;
2299
  ra->RA_offset = 2; // to compensate the rx frame offset at the gNB
2300
  if (ra->ra_state != nrRA_GENERATE_PREAMBLE)
2301 2302
    return;

2303 2304 2305
  fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
  fapi_nr_prach_config_t *prach_config = &cfg->prach_config;

2306
  NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon;
2307
  NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric;
2308
  const int bwp_id = mac->current_UL_BWP->bwp_id;
2309
  NR_TDD_UL_DL_ConfigCommon_t *tdd_config = mac->tdd_UL_DL_ConfigurationCommon;
2310

2311
  if (is_nr_UL_slot(tdd_config, slotP, mac->frame_type)) {
2312 2313 2314

    // WIP Need to get the proper selected ssb_idx
    //     Initial beam selection functionality is not available yet
2315
    uint8_t selected_gnb_ssb_idx = mac->mib_ssb;
2316 2317

    // Get any valid PRACH occasion in the current slot for the selected SSB index
2318
    prach_occasion_info_t *prach_occasion_info_p;
2319
    int is_nr_prach_slot = get_nr_prach_info_from_ssb_index(&mac->prach_assoc_pattern[bwp_id],
2320
                                                            selected_gnb_ssb_idx,
francescomani's avatar
francescomani committed
2321 2322
                                                            (int)frameP,
                                                            (int)slotP,
2323
                                                            &mac->ssb_list[bwp_id],
francescomani's avatar
francescomani committed
2324
                                                            &prach_occasion_info_p);
2325

2326
    if (is_nr_prach_slot) {
2327 2328
      AssertFatal(NULL != prach_occasion_info_p,"PRACH Occasion Info not returned in a valid NR Prach Slot\n");

2329 2330
      nr_get_RA_window(mac);

2331 2332 2333
      uint16_t format = prach_occasion_info_p->format;
      uint16_t format0 = format & 0xff;        // single PRACH format
      uint16_t format1 = (format >> 8) & 0xff; // dual PRACH format
2334

2335 2336 2337 2338 2339
      fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frameP, slotP, FAPI_NR_UL_CONFIG_TYPE_PRACH);
      if (!pdu) {
        LOG_E(NR_MAC, "Error in PRACH allocation\n");
        return;
      }
2340
      uint16_t ncs = get_NCS(rach_ConfigGeneric->zeroCorrelationZoneConfig, format0, setup->restrictedSetConfig);
2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357
      pdu->prach_config_pdu = (fapi_nr_ul_config_prach_pdu){
          .phys_cell_id = mac->physCellId,
          .num_prach_ocas = 1,
          .prach_slot = prach_occasion_info_p->slot,
          .prach_start_symbol = prach_occasion_info_p->start_symbol,
          .num_ra = prach_occasion_info_p->fdm,
          .num_cs = ncs,
          .root_seq_id = prach_config->num_prach_fd_occasions_list[prach_occasion_info_p->fdm].prach_root_sequence_index,
          .restricted_set = prach_config->restricted_set_config,
          .freq_msg1 = prach_config->num_prach_fd_occasions_list[prach_occasion_info_p->fdm].k1};

      LOG_I(NR_MAC,
            "PRACH scheduler: Selected RO Frame %u, Slot %u, Symbol %u, Fdm %u\n",
            frameP,
            pdu->prach_config_pdu.prach_slot,
            pdu->prach_config_pdu.prach_start_symbol,
            pdu->prach_config_pdu.num_ra);
2358 2359

      // Search which SSB is mapped in the RO (among all the SSBs mapped to this RO)
2360 2361 2362
      for (int ssb_nb_in_ro=0; ssb_nb_in_ro<prach_occasion_info_p->nb_mapped_ssb; ssb_nb_in_ro++) {
        if (prach_occasion_info_p->mapped_ssb_idx[ssb_nb_in_ro] == selected_gnb_ssb_idx) {
          ra->ssb_nb_in_ro = ssb_nb_in_ro;
2363
          break;
2364
        }
2365
      }
2366
      AssertFatal(ra->ssb_nb_in_ro<prach_occasion_info_p->nb_mapped_ssb, "%u not found in the mapped SSBs to the PRACH occasion", selected_gnb_ssb_idx);
2367 2368

      if (format1 != 0xff) {
2369
        switch (format0) { // dual PRACH format
2370
          case 0xa1:
2371
            pdu->prach_config_pdu.prach_format = 11;
2372 2373
            break;
          case 0xa2:
2374
            pdu->prach_config_pdu.prach_format = 12;
2375 2376
            break;
          case 0xa3:
2377
            pdu->prach_config_pdu.prach_format = 13;
2378
            break;
2379 2380
          default:
            AssertFatal(1 == 0, "Only formats A1/B1 A2/B2 A3/B3 are valid for dual format");
2381 2382
        }
      } else {
2383
        switch (format0) { // single PRACH format
2384
          case 0:
2385
            pdu->prach_config_pdu.prach_format = 0;
2386 2387
            break;
          case 1:
2388
            pdu->prach_config_pdu.prach_format = 1;
2389 2390
            break;
          case 2:
2391
            pdu->prach_config_pdu.prach_format = 2;
2392 2393
            break;
          case 3:
2394
            pdu->prach_config_pdu.prach_format = 3;
2395 2396
            break;
          case 0xa1:
2397
            pdu->prach_config_pdu.prach_format = 4;
2398 2399
            break;
          case 0xa2:
2400
            pdu->prach_config_pdu.prach_format = 5;
2401 2402
            break;
          case 0xa3:
2403
            pdu->prach_config_pdu.prach_format = 6;
2404 2405
            break;
          case 0xb1:
2406
            pdu->prach_config_pdu.prach_format = 7;
2407 2408
            break;
          case 0xb4:
2409
            pdu->prach_config_pdu.prach_format = 8;
2410 2411
            break;
          case 0xc0:
2412
            pdu->prach_config_pdu.prach_format = 9;
2413 2414
            break;
          case 0xc2:
2415
            pdu->prach_config_pdu.prach_format = 10;
2416 2417 2418 2419 2420
            break;
          default:
            AssertFatal(1 == 0, "Invalid PRACH format");
        }
      } // if format1
2421

2422
      nr_get_prach_resources(mac, 0, 0, &ra->prach_resources, ra->rach_ConfigDedicated);
2423
      pdu->prach_config_pdu.ra_PreambleIndex = ra->ra_PreambleIndex;
2424
      pdu->prach_config_pdu.prach_tx_power = get_prach_tx_power(mac);
2425 2426 2427 2428
      mac->ra.ra_rnti = nr_get_ra_rnti(pdu->prach_config_pdu.prach_start_symbol,
                                       pdu->prach_config_pdu.prach_slot,
                                       pdu->prach_config_pdu.num_ra,
                                       0);
2429 2430
      release_ul_config(pdu, false);
      nr_scheduled_response_t scheduled_response = {.ul_config = mac->ul_config_request + slotP,
2431
                                                    .mac = mac,
2432
                                                    .module_id = mac->ue_id,
2433
                                                    .CC_id = 0 /*TBR fix*/};
cig's avatar
cig committed
2434 2435
      if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL)
        mac->if_module->scheduled_response(&scheduled_response);
2436

2437
      nr_Msg1_transmitted(mac);
2438 2439 2440 2441
    } // is_nr_prach_slot
  } // if is_nr_UL_slot
}

2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456
typedef struct {
  uint8_t bsr_len;
  uint8_t bsr_ce_len;
  uint8_t bsr_header_len;
  uint8_t phr_len;
  uint8_t phr_ce_len;
  uint8_t phr_header_len;
  uint16_t sdu_length_total;
  NR_BSR_SHORT *bsr_s;
  NR_BSR_LONG *bsr_l;
  NR_BSR_SHORT *bsr_t;
  //NR_POWER_HEADROOM_CMD *phr_pr;
  int tot_mac_ce_len;
  uint8_t total_mac_pdu_header_len;
} NR_UE_MAC_CE_INFO;
cig's avatar
cig committed
2457

2458
/*
2459 2460 2461 2462 2463 2464 2465 2466 2467
  nr_ue_get_sdu_mac_ce_pre finds length in various mac_ce field
  Need nothing from mac_ce_p:
  Update the following in mac_ce_p:
  bsr_len;
  bsr_ce_len;
  bsr_header_len;
  phr_len; TBD
  phr_ce_len; TBD
  phr_header_len; TBD
2468
*/
2469 2470 2471 2472 2473 2474 2475 2476
static int nr_ue_get_sdu_mac_ce_pre(NR_UE_MAC_INST_t *mac,
                                    int CC_id,
                                    frame_t frameP,
                                    sub_frame_t subframe,
                                    uint8_t gNB_index,
                                    uint8_t *ulsch_buffer,
                                    uint16_t buflen,
                                    NR_UE_MAC_CE_INFO *mac_ce_p)
2477
{
2478
  int num_lcg_id_with_data = 0;
cig's avatar
cig committed
2479
  // Preparing the MAC CEs sub-PDUs and get the total size
2480 2481 2482
  mac_ce_p->bsr_header_len = 0;
  mac_ce_p->phr_header_len = 0;   //sizeof(SCH_SUBHEADER_FIXED);
  int lcg_id = 0;
2483
  while (lcg_id != NR_INVALID_LCGID) {
2484
    if (mac->scheduling_info.lcg_sched_info[lcg_id].BSR_bytes) {
mjoang's avatar
mjoang committed
2485 2486 2487 2488 2489
      num_lcg_id_with_data++;
    }
    lcg_id++;
  }

2490 2491 2492 2493 2494
  // Compute BSR Length if Regular or Periodic BSR is triggered
  // WARNING: if BSR long is computed, it may be changed to BSR short during or after multiplexing
  // if there remains less than 1 LCGROUP with data after Tx
  if (mac->scheduling_info.BSR_reporting_active) {
    AssertFatal((mac->scheduling_info.BSR_reporting_active & NR_BSR_TRIGGER_PADDING) == 0,
mjoang's avatar
mjoang committed
2495
                "Inconsistent BSR Trigger=%d !\n",
2496
                mac->scheduling_info.BSR_reporting_active);
mjoang's avatar
mjoang committed
2497

2498 2499
    // A Regular or Periodic BSR can only be sent if TBS is sufficient
    // as transmitting only a BSR is not allowed if UE has data to transmit
mjoang's avatar
mjoang committed
2500
    if (num_lcg_id_with_data <= 1) {
2501
      if (buflen >= (sizeof(NR_BSR_SHORT) + sizeof(NR_MAC_SUBHEADER_FIXED) + 1)) {
2502 2503
        mac_ce_p->bsr_ce_len = sizeof(NR_BSR_SHORT); // 1 byte
        mac_ce_p->bsr_header_len = sizeof(NR_MAC_SUBHEADER_FIXED); // 1 byte
mjoang's avatar
mjoang committed
2504 2505
      }
    } else {
2506
      if (buflen >= (num_lcg_id_with_data + 1 + sizeof(NR_MAC_SUBHEADER_SHORT) + 1)) {
2507 2508
        mac_ce_p->bsr_ce_len = num_lcg_id_with_data + 1; // variable size
        mac_ce_p->bsr_header_len = sizeof(NR_MAC_SUBHEADER_SHORT); // 2 bytes
2509 2510 2511 2512 2513 2514 2515 2516 2517
      }
    }
  }

  mac_ce_p->bsr_len = mac_ce_p->bsr_ce_len + mac_ce_p->bsr_header_len;
  return (mac_ce_p->bsr_len + mac_ce_p->phr_len);
}

/*
2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532
  nr_ue_get_sdu_mac_ce_post recalculates length and prepares the mac_ce field
  Need the following from mac_ce_p:
  bsr_ce_len
  bsr_len
  sdu_length_total
  total_mac_pdu_header_len
  Update the following in mac_ce_p:
  bsr_ce_len
  bsr_header_len
  bsr_len
  tot_mac_ce_len
  total_mac_pdu_header_len
  bsr_s
  bsr_l
  bsr_t
2533
*/
2534 2535
static void nr_ue_get_sdu_mac_ce_post(NR_UE_MAC_INST_t *mac,
                                      int CC_id,
2536 2537
                                      frame_t frame,
                                      slot_t slot,
2538 2539 2540 2541
                                      uint8_t gNB_index,
                                      uint8_t *ulsch_buffer,
                                      uint16_t buflen,
                                      NR_UE_MAC_CE_INFO *mac_ce_p)
2542
{
2543 2544 2545 2546
  // Compute BSR Values and update Nb LCGID with data after multiplexing
  unsigned short padding_len = 0;
  int num_lcg_id_with_data = 0;
  int lcg_id_bsr_trunc = 0;
2547 2548
  NR_UE_SCHEDULING_INFO *sched_info = &mac->scheduling_info;
  for (int lcg_id = 0; lcg_id < NR_MAX_NUM_LCGID; lcg_id++) {
2549
    if (mac_ce_p->bsr_ce_len == sizeof(NR_BSR_SHORT)) {
2550
      sched_info->lcg_sched_info[lcg_id].BSR =
2551 2552
          nr_locate_BsrIndexByBufferSize(NR_SHORT_BSR_TABLE,
                                         NR_SHORT_BSR_TABLE_SIZE,
2553
                                         sched_info->lcg_sched_info[lcg_id].BSR_bytes);
2554
    } else {
2555
      sched_info->lcg_sched_info[lcg_id].BSR =
2556 2557
          nr_locate_BsrIndexByBufferSize(NR_LONG_BSR_TABLE,
                                         NR_LONG_BSR_TABLE_SIZE,
2558
                                         sched_info->lcg_sched_info[lcg_id].BSR_bytes);
2559
    }
2560
    if (sched_info->lcg_sched_info[lcg_id].BSR_bytes) {
2561 2562 2563 2564 2565 2566 2567 2568 2569
      num_lcg_id_with_data++;
      lcg_id_bsr_trunc = lcg_id;
    }
  }

  // TS 38.321 Section 5.4.5
  // Check BSR padding: it is done after PHR according to Logical Channel Prioritization order
  // Check for max padding size, ie MAC Hdr for last RLC PDU = 1
  /* For Padding BSR:
2570 2571 2572 2573
     -  if the number of padding bits is equal to or larger than the size of the Short BSR plus its subheader but smaller than the
     size of the Long BSR plus its subheader:
     -  if more than one LCG has data available for transmission in the TTI where the BSR is transmitted: report Truncated BSR of
     the LCG with the highest priority logical channel with data available for transmission;
2574 2575
     -  else report Short BSR.
     -  else if the number of padding bits is equal to or larger than the size of the Long BSR plus its subheader, report Long BSR.
2576
  */
2577 2578 2579 2580 2581 2582
  if (mac_ce_p->sdu_length_total) {
    padding_len = buflen - (mac_ce_p->total_mac_pdu_header_len + mac_ce_p->sdu_length_total);
  }

  if ((padding_len) && (mac_ce_p->bsr_len == 0)) {
    /* if the number of padding bits is equal to or larger than the size of the Long BSR plus its subheader, report Long BSR */
2583
    if (padding_len >= (num_lcg_id_with_data + 1 + sizeof(NR_MAC_SUBHEADER_SHORT))) {
2584 2585 2586
      mac_ce_p->bsr_ce_len = num_lcg_id_with_data + 1; //variable size
      mac_ce_p->bsr_header_len = sizeof(NR_MAC_SUBHEADER_SHORT); //2 bytes
      // Trigger BSR Padding
2587
      sched_info->BSR_reporting_active |= NR_BSR_TRIGGER_PADDING;
2588 2589 2590 2591 2592 2593
    } else if (padding_len >= (sizeof(NR_BSR_SHORT)+sizeof(NR_MAC_SUBHEADER_FIXED))) {
      mac_ce_p->bsr_ce_len = sizeof(NR_BSR_SHORT); //1 byte
      mac_ce_p->bsr_header_len = sizeof(NR_MAC_SUBHEADER_FIXED); //1 byte

      if (num_lcg_id_with_data > 1) {
        // REPORT SHORT TRUNCATED BSR
2594
        // Get LCGID of highest priority LCID with data (todo)
2595
        for (int lcid = 1; lcid <= NR_MAX_NUM_LCID; lcid++) {
2596
          NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid);
2597 2598
          if ((sched_info->LCGID != NR_INVALID_LCGID) && (mac->scheduling_info.lcg_sched_info[sched_info->LCGID].BSR_bytes)) {
            lcg_id_bsr_trunc = sched_info->LCGID;
2599 2600 2601
          }
        }
      } else {
2602
        // Report SHORT BSR, clear bsr_t
2603
        mac_ce_p->bsr_t = NULL;
mjoang's avatar
mjoang committed
2604
      }
2605 2606

      // Trigger BSR Padding
2607
      sched_info->BSR_reporting_active |= NR_BSR_TRIGGER_PADDING;
mjoang's avatar
mjoang committed
2608
    }
2609 2610 2611 2612

    mac_ce_p->bsr_len = mac_ce_p->bsr_header_len + mac_ce_p->bsr_ce_len;
    mac_ce_p->tot_mac_ce_len += mac_ce_p->bsr_len;
    mac_ce_p->total_mac_pdu_header_len += mac_ce_p->bsr_len;
mjoang's avatar
mjoang committed
2613 2614
  }

2615 2616 2617 2618 2619 2620 2621 2622
  //Fill BSR Infos
  if (mac_ce_p->bsr_ce_len == 0) {
    mac_ce_p->bsr_s = NULL;
    mac_ce_p->bsr_l = NULL;
    mac_ce_p->bsr_t = NULL;
  } else if (mac_ce_p->bsr_header_len == sizeof(NR_MAC_SUBHEADER_SHORT)) {
    mac_ce_p->bsr_s = NULL;
    mac_ce_p->bsr_t = NULL;
2623 2624 2625 2626 2627 2628 2629 2630
    mac_ce_p->bsr_l->Buffer_size0 = sched_info->lcg_sched_info[0].BSR;
    mac_ce_p->bsr_l->Buffer_size1 = sched_info->lcg_sched_info[1].BSR;
    mac_ce_p->bsr_l->Buffer_size2 = sched_info->lcg_sched_info[2].BSR;
    mac_ce_p->bsr_l->Buffer_size3 = sched_info->lcg_sched_info[3].BSR;
    mac_ce_p->bsr_l->Buffer_size4 = sched_info->lcg_sched_info[4].BSR;
    mac_ce_p->bsr_l->Buffer_size5 = sched_info->lcg_sched_info[5].BSR;
    mac_ce_p->bsr_l->Buffer_size6 = sched_info->lcg_sched_info[6].BSR;
    mac_ce_p->bsr_l->Buffer_size7 = sched_info->lcg_sched_info[7].BSR;
2631 2632 2633
    LOG_D(NR_MAC,
          "[UE %d] Frame %d subframe %d BSR Trig=%d report LONG BSR (level LCGID0 %d,level LCGID1 %d,level LCGID2 %d,level LCGID3 "
          "%d level LCGID4 %d,level LCGID5 %d,level LCGID6 %d,level LCGID7 %d)\n",
2634
          mac->ue_id,
2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645
          frame,
          slot,
          sched_info->BSR_reporting_active,
          sched_info->lcg_sched_info[0].BSR,
          sched_info->lcg_sched_info[1].BSR,
          sched_info->lcg_sched_info[2].BSR,
          sched_info->lcg_sched_info[3].BSR,
          sched_info->lcg_sched_info[4].BSR,
          sched_info->lcg_sched_info[5].BSR,
          sched_info->lcg_sched_info[6].BSR,
          sched_info->lcg_sched_info[7].BSR);
2646 2647 2648
  } else if (mac_ce_p->bsr_header_len == sizeof(NR_MAC_SUBHEADER_FIXED)) {
    mac_ce_p->bsr_l = NULL;

2649
    if ((mac_ce_p->bsr_t != NULL) && (sched_info->BSR_reporting_active & NR_BSR_TRIGGER_PADDING)) {
2650 2651 2652
      //Truncated BSR
      mac_ce_p->bsr_s = NULL;
      mac_ce_p->bsr_t->LcgID = lcg_id_bsr_trunc;
2653
      mac_ce_p->bsr_t->Buffer_size = sched_info->lcg_sched_info[lcg_id_bsr_trunc].BSR;
2654 2655
      LOG_D(NR_MAC,
            "[UE %d] Frame %d subframe %d BSR Trig=%d report TRUNCATED BSR with level %d for LCGID %d\n",
2656
            mac->ue_id,
2657 2658 2659 2660
            frame,
            slot,
            sched_info->BSR_reporting_active,
            sched_info->lcg_sched_info[lcg_id_bsr_trunc].BSR,
2661
            lcg_id_bsr_trunc);
2662 2663 2664
    } else {
      mac_ce_p->bsr_t = NULL;
      mac_ce_p->bsr_s->LcgID = lcg_id_bsr_trunc;
2665
      mac_ce_p->bsr_s->Buffer_size = sched_info->lcg_sched_info[lcg_id_bsr_trunc].BSR;
2666 2667
      LOG_D(NR_MAC,
            "[UE %d] Frame %d subframe %d BSR Trig=%d report SHORT BSR with level %d for LCGID %d\n",
2668
            mac->ue_id,
2669 2670 2671 2672
            frame,
            slot,
            sched_info->BSR_reporting_active,
            sched_info->lcg_sched_info[lcg_id_bsr_trunc].BSR,
2673
            lcg_id_bsr_trunc);
2674 2675 2676
    }
  }

2677
  LOG_D(NR_MAC, "[UE %d][SR] Gave SDU to PHY, clearing any scheduling request\n", mac->ue_id);
2678 2679
  sched_info->SR_pending = 0;
  sched_info->SR_COUNTER = 0;
2680 2681 2682

  /* Actions when a BSR is sent */
  if (mac_ce_p->bsr_ce_len) {
2683 2684
    LOG_D(NR_MAC,
          "[UE %d] MAC BSR Sent !! bsr (ce%d,hdr%d) buff_len %d\n",
2685
          mac->ue_id,
2686 2687 2688
          mac_ce_p->bsr_ce_len,
          mac_ce_p->bsr_header_len,
          buflen);
2689
    // Reset ReTx BSR Timer
2690
    nr_timer_start(&sched_info->retxBSR_Timer);
2691
    // Reset Periodic Timer except when BSR is truncated
2692
    if (mac_ce_p->bsr_t == NULL) {
2693
      nr_timer_start(&sched_info->periodicBSR_Timer);
2694
      LOG_D(NR_MAC, "[UE %d] MAC Periodic BSR Timer Reset\n", mac->ue_id);
2695 2696 2697
    }

    // Reset BSR Trigger flags
2698
    sched_info->BSR_reporting_active = NR_BSR_TRIGGER_NONE;
2699 2700
  }
}
cig's avatar
cig committed
2701

2702
uint32_t get_count_lcids_same_priority(uint8_t start, uint8_t total_active_lcids, nr_lcordered_info_t *lcid_ordered_array)
2703 2704 2705
{
  // count number of logical channels with same priority as curr_lcid
  uint8_t same_priority_count = 0;
2706
  uint8_t curr_lcid = lcid_ordered_array[start].lcid;
2707
  for (uint8_t index = start; index < total_active_lcids; index++) {
2708
    if (lcid_ordered_array[start].priority == lcid_ordered_array[index].priority) {
2709 2710 2711
      same_priority_count++;
    }
  }
Sriharsha Korada's avatar
Sriharsha Korada committed
2712
  LOG_D(NR_MAC, "Number of lcids with same priority as that of lcid %d is %d\n", curr_lcid, same_priority_count);
2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725
  return same_priority_count;
}

long get_num_bytes_to_reqlc(NR_UE_MAC_INST_t *mac,
                            uint8_t same_priority_count,
                            uint8_t lc_num,
                            uint16_t buflen_remain_ep,
                            int16_t buflen_remain,
                            uint8_t round_id,
                            uint32_t *bytes_read_fromlc,
                            long *target)
{
  /* Calculates the number of bytes the logical channel should request from the correcponding RLC buffer*/
2726 2727
  nr_lcordered_info_t *lc_info = get_lc_info_from_lcid(mac, lc_num);
  AssertFatal(lc_info, "Couldn't find logical channel with LCID %d\n", lc_num);
2728
  uint32_t pbr = lc_info->pbr;
2729 2730
  NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lc_num);
  int32_t lcid_remain_buffer = sched_info->LCID_buffer_remain;
2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749
  *target = (same_priority_count > 1) ? min(buflen_remain_ep, pbr) : pbr;

  long num_remaining_bytes = 0;
  long num_bytes_requested = 0;
  if (round_id == 0) { // initial round
    uint16_t pdu_remain = (same_priority_count > 1) ? buflen_remain_ep : buflen_remain;
    num_bytes_requested = (pdu_remain < pbr) ? min(pdu_remain, lcid_remain_buffer) : min(pbr, lcid_remain_buffer);
    num_remaining_bytes = *target - bytes_read_fromlc[lc_num - 1];
    num_bytes_requested = min(num_bytes_requested, num_remaining_bytes);
  } else { // from first round
    if (same_priority_count > 1) {
      num_bytes_requested = min(buflen_remain_ep, lcid_remain_buffer);
      num_remaining_bytes = buflen_remain_ep - bytes_read_fromlc[lc_num - 1];
      num_bytes_requested = min(num_bytes_requested, num_remaining_bytes);
    } else {
      num_bytes_requested = min(buflen_remain, lcid_remain_buffer);
    }
  }
  AssertFatal(num_remaining_bytes >= 0, "the total number of bytes allocated until target length is greater than expected\n");
Sriharsha Korada's avatar
Sriharsha Korada committed
2750
  LOG_D(NR_MAC, "number of bytes requested for lcid %d is %li\n", lc_num, num_bytes_requested);
2751 2752 2753 2754

  return num_bytes_requested;
}

2755
bool get_dataavailability_buffers(uint8_t total_active_lcids, nr_lcordered_info_t *lcid_ordered_array, bool *data_status_lcbuffers)
2756 2757 2758
{
  // check whether there is any data in the rlc buffer corresponding to active lcs
  for (uint8_t id = 0; id < total_active_lcids; id++) {
2759
    int lcid = lcid_ordered_array[id].lcid;
2760
    if (data_status_lcbuffers[lcid_buffer_index(lcid)]) {
2761 2762 2763 2764 2765 2766
      return true;
    }
  }
  return false;
}

2767
static void select_logical_channels(NR_UE_MAC_INST_t *mac, int *num_active_lcids, nr_lcordered_info_t *active_lcids)
2768 2769 2770 2771 2772
{
  // (TODO: selection of logical channels for logical channel prioritization procedure as per 5.4.3.1.2 Selection of logical
  // channels, TS38.321)

  // selection of logical channels with Bj > 0
2773 2774
  for (int i = 0; i < mac->lc_ordered_list.count; i++) {
    int lcid = mac->lc_ordered_list.array[i]->lcid;
2775 2776
    NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid);
    if (sched_info->Bj > 0) {
2777
      active_lcids[*num_active_lcids] = *mac->lc_ordered_list.array[i];
2778
      (*num_active_lcids)++;
Sriharsha Korada's avatar
Sriharsha Korada committed
2779
      LOG_D(NR_MAC, "The available lcid is %d with total active channels count = %d\n", lcid, *num_active_lcids);
2780 2781 2782 2783
    }
  }
}

2784
static bool fill_mac_sdu(NR_UE_MAC_INST_t *mac,
2785 2786
                         frame_t frame,
                         slot_t slot,
Sriharsha Korada's avatar
Sriharsha Korada committed
2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803
                         uint8_t gNB_index,
                         uint16_t buflen,
                         int16_t *buflen_remain,
                         int lcid,
                         uint8_t **pdu,
                         uint32_t *counter,
                         uint8_t count_same_priority_lcids,
                         uint16_t buflen_ep,
                         uint32_t *lcids_bytes_tot,
                         uint16_t *num_sdus,
                         NR_UE_MAC_CE_INFO *mac_ce_p,
                         bool *lcids_data_status,
                         uint8_t *num_lcids_same_priority)
{
  const uint8_t sh_size = sizeof(NR_MAC_SUBHEADER_LONG);

  /* prepare the MAC sdu */
2804 2805
  NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid);
  int32_t lcid_remain_buffer = sched_info->LCID_buffer_remain;
Sriharsha Korada's avatar
Sriharsha Korada committed
2806
  LOG_D(NR_MAC,
2807 2808
        "[UE %d] [%d.%d] lcp round = %d, remaining mac pdu length = %d, lcid buffer remaining = %d, lcid = %d \n",
        mac->ue_id,
2809 2810
        frame,
        slot,
Sriharsha Korada's avatar
Sriharsha Korada committed
2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825
        *counter,
        *buflen_remain,
        lcid_remain_buffer,
        lcid);

  // Pointer used to build the MAC sub-PDU headers in the ULSCH buffer for each SDU
  NR_MAC_SUBHEADER_LONG *header = (NR_MAC_SUBHEADER_LONG *)(*pdu);

  *pdu += sh_size;

  // number of bytes requested from RLC for each LCID
  long target = 0;
  long bytes_requested =
      get_num_bytes_to_reqlc(mac, count_same_priority_lcids, lcid, buflen_ep, *buflen_remain, *counter, lcids_bytes_tot, &target);

2826
  uint16_t sdu_length = mac_rlc_data_req(mac->ue_id,
2827
                                         mac->ue_id,
Sriharsha Korada's avatar
Sriharsha Korada committed
2828
                                         gNB_index,
2829
                                         frame,
Sriharsha Korada's avatar
Sriharsha Korada committed
2830 2831 2832 2833 2834 2835 2836 2837 2838
                                         ENB_FLAG_NO,
                                         MBMS_FLAG_NO,
                                         lcid,
                                         bytes_requested,
                                         (char *)(*pdu),
                                         0,
                                         0);

  AssertFatal(bytes_requested >= sdu_length,
2839
              "LCID = 0x%02x RLC has segmented %d bytes but MAC has max %li remaining bytes\n",
Sriharsha Korada's avatar
Sriharsha Korada committed
2840 2841 2842 2843 2844 2845 2846 2847
              lcid,
              sdu_length,
              bytes_requested);

  // Decrement Bj by the total size of MAC SDUs(RLC PDU) served to logical channel
  // currently the Bj is drecremented by size of MAC SDus everytime it is served to logical channel, so by this approach there
  // will be more chance for lower priority logical channels to be served in the next TTI
  // second approach can also be followed where Bj is decremented only in the first round but not in the subsequent rounds
2848
  sched_info->Bj -= sdu_length; // TODO avoid Bj to go below 0
Sriharsha Korada's avatar
Sriharsha Korada committed
2849 2850 2851 2852 2853
  LOG_D(NR_MAC,
        "decrement Bj of the lcid %d by size of sdu length = %d and new Bj for lcid %d is %d\n",
        lcid,
        sdu_length,
        lcid,
2854
        sched_info->Bj);
Sriharsha Korada's avatar
Sriharsha Korada committed
2855

2856
  int lc_idx = lcid_buffer_index(lcid);
Sriharsha Korada's avatar
Sriharsha Korada committed
2857 2858
  if (sdu_length > 0) {
    LOG_D(NR_MAC,
2859
          "[UE %d] [%d.%d] UL-DXCH -> ULSCH, Generating UL MAC sub-PDU for SDU %d, length %d bytes, RB with LCID "
Sriharsha Korada's avatar
Sriharsha Korada committed
2860
          "0x%02x (buflen (TBS) %d bytes)\n",
2861
          mac->ue_id,
2862 2863
          frame,
          slot,
Sriharsha Korada's avatar
Sriharsha Korada committed
2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874
          (*num_sdus) + 1,
          sdu_length,
          lcid,
          buflen);

    header->R = 0;
    header->F = 1;
    header->LCID = lcid;
    header->L = htons(sdu_length);

#ifdef ENABLE_MAC_PAYLOAD_DEBUG
2875
    LOG_I(NR_MAC, "dumping MAC sub-header with length %d: \n", sh_size);
Sriharsha Korada's avatar
Sriharsha Korada committed
2876
    log_dump(NR_MAC, header, sh_size, LOG_DUMP_CHAR, "\n");
2877
    LOG_I(NR_MAC, "dumping MAC SDU with length %d \n", sdu_length);
Sriharsha Korada's avatar
Sriharsha Korada committed
2878 2879 2880 2881 2882 2883 2884 2885 2886 2887
    log_dump(NR_MAC, *pdu, sdu_length, LOG_DUMP_CHAR, "\n");
#endif

    *pdu += sdu_length;
    mac_ce_p->sdu_length_total += sdu_length;
    mac_ce_p->total_mac_pdu_header_len += sh_size;

    (*num_sdus)++;
  } else {
    *pdu -= sh_size;
2888
    lcids_data_status[lc_idx] = false;
Sriharsha Korada's avatar
Sriharsha Korada committed
2889
    (*num_lcids_same_priority)--;
2890
    LOG_D(NR_MAC, "No data to transmit for RB with LCID 0x%02x\n and hence set to false", lcid);
Sriharsha Korada's avatar
Sriharsha Korada committed
2891 2892 2893 2894 2895 2896
    return 0;
  }

  *buflen_remain = buflen - (mac_ce_p->total_mac_pdu_header_len + mac_ce_p->sdu_length_total + sh_size);

  // Update Buffer remain and BSR bytes after transmission
2897 2898 2899
  NR_LCG_SCHEDULING_INFO *lcg_info = &mac->scheduling_info.lcg_sched_info[0];
  sched_info->LCID_buffer_remain -= sdu_length;
  (lcg_info + sched_info->LCGID)->BSR_bytes -= sdu_length;
Sriharsha Korada's avatar
Sriharsha Korada committed
2900
  LOG_D(NR_MAC,
2901
        "[UE %d] Update BSR [%d.%d] BSR_bytes for LCG%ld = %d\n",
2902
        mac->ue_id,
2903 2904
        frame,
        slot,
2905 2906 2907 2908
        sched_info->LCGID,
        (lcg_info + sched_info->LCGID)->BSR_bytes);
  if ((lcg_info + sched_info->LCGID)->BSR_bytes < 0)
    (lcg_info + sched_info->LCGID)->BSR_bytes = 0;
Sriharsha Korada's avatar
Sriharsha Korada committed
2909 2910

  // update number of bytes served from the current lcid
2911
  lcids_bytes_tot[lc_idx] += (sdu_length + (count_same_priority_lcids > 1 ? 1 : 0) * sh_size);
Sriharsha Korada's avatar
Sriharsha Korada committed
2912

2913
  if ((*counter == 0 && lcids_bytes_tot[lc_idx] >= target)
Sriharsha Korada's avatar
Sriharsha Korada committed
2914
      || (count_same_priority_lcids > 1
2915
          && lcids_bytes_tot[lc_idx] >= buflen_ep)) { // only prioritized bit rate should be taken from logical channel in
2916
    // the first lcp run except when infinity
Sriharsha Korada's avatar
Sriharsha Korada committed
2917
    LOG_D(NR_MAC,
2918
          "Total number bytes read from rlc buffer for lcid %d are %d\n",
Sriharsha Korada's avatar
Sriharsha Korada committed
2919
          lcid,
2920
          lcids_bytes_tot[lc_idx]);
Sriharsha Korada's avatar
Sriharsha Korada committed
2921 2922 2923 2924 2925 2926
    (*num_lcids_same_priority)--;
    return 0;
  }
  return 1;
}

cig's avatar
cig committed
2927 2928
/**
 * Function:      to fetch data to be transmitted from RLC, place it in the ULSCH PDU buffer
2929 2930
 to generate the complete MAC PDU with sub-headers and MAC CEs according to ULSCH MAC PDU generation (6.1.2 TS 38.321)
 the selected sub-header for the payload sub-PDUs is NR_MAC_SUBHEADER_LONG
cig's avatar
cig committed
2931
 * @module_idP    Module ID
2932
 * @CC_id         Component Carrier index
2933 2934
 * @frame         current UL frame
 * @slot          current UL slot
cig's avatar
cig committed
2935 2936 2937 2938
 * @gNB_index     gNB index
 * @ulsch_buffer  Pointer to ULSCH PDU
 * @buflen        TBS
 */
2939
uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac,
2940
                      int CC_id,
2941 2942
                      frame_t frame,
                      slot_t slot,
cig's avatar
cig committed
2943 2944
                      uint8_t gNB_index,
                      uint8_t *ulsch_buffer,
2945 2946
                      uint16_t buflen)
{
2947 2948
  NR_UE_MAC_CE_INFO mac_ce_info;
  NR_UE_MAC_CE_INFO *mac_ce_p=&mac_ce_info;
2949
  int16_t buflen_remain = 0;
2950 2951 2952 2953 2954 2955 2956
  mac_ce_p->bsr_len = 0;
  mac_ce_p->bsr_ce_len = 0;
  mac_ce_p->bsr_header_len = 0;
  mac_ce_p->phr_len = 0;
  //mac_ce_p->phr_ce_len = 0;
  //mac_ce_p->phr_header_len = 0;

cig's avatar
cig committed
2957
  uint16_t num_sdus = 0;
2958 2959 2960 2961 2962 2963 2964 2965
  mac_ce_p->sdu_length_total = 0;
  NR_BSR_SHORT bsr_short, bsr_truncated;
  NR_BSR_LONG bsr_long;
  mac_ce_p->bsr_s = &bsr_short;
  mac_ce_p->bsr_l = &bsr_long;
  mac_ce_p->bsr_t = &bsr_truncated;
  //NR_POWER_HEADROOM_CMD phr;
  //mac_ce_p->phr_p = &phr;
2966

2967
  //int highest_priority = 16;
cig's avatar
cig committed
2968
  const uint8_t sh_size = sizeof(NR_MAC_SUBHEADER_LONG);
cig's avatar
cig committed
2969 2970 2971 2972

  // Pointer used to build the MAC PDU by placing the RLC SDUs in the ULSCH buffer
  uint8_t *pdu = ulsch_buffer;

2973 2974 2975
  // variable used to store the lcid data status during lcp
  bool lcids_data_status[NR_MAX_NUM_LCID] = {0};
  memset(lcids_data_status, 1, NR_MAX_NUM_LCID);
2976

2977 2978
  // in the first run all the lc are allocated as per bj and prioritized bit rate but in subsequent runs, no need to consider
  uint32_t lcp_allocation_counter = 0;
2979
  // bj and prioritized bit rate but just consider priority
2980
  uint16_t buflen_ep = 0; // this variable holds the length in bytes in mac pdu when multiple equal priority channels are present
2981
  // because as per standard(TS38.321), all equal priority channels should be served equally
cig's avatar
cig committed
2982

2983
  // nr_ue_get_sdu_mac_ce_pre updates all mac_ce related header field related to length
2984
  mac_ce_p->tot_mac_ce_len = nr_ue_get_sdu_mac_ce_pre(mac, CC_id, frame, slot, gNB_index, ulsch_buffer, buflen, mac_ce_p);
2985
  mac_ce_p->total_mac_pdu_header_len = mac_ce_p->tot_mac_ce_len;
cig's avatar
cig committed
2986

2987
  LOG_D(NR_MAC, "[UE %d] [%d.%d] process UL transport block at with size TBS = %d bytes \n", mac->ue_id, frame, slot, buflen);
cig's avatar
cig committed
2988

2989
  // selection of logical channels
2990 2991 2992
  int avail_lcids_count = 0;
  // variable used to build the lcids with positive Bj
  nr_lcordered_info_t lcids_bj_pos[mac->lc_ordered_list.count];
2993 2994 2995 2996 2997
  select_logical_channels(mac, &avail_lcids_count, lcids_bj_pos);

  // multiplex in the order of highest priority
  do {
    /*
2998
      go until there is space availabile in the MAC PDU and there is data available in RLC buffers of active logical channels
2999 3000 3001 3002 3003 3004 3005 3006 3007
    */
    uint8_t num_lcids_same_priority = 0;
    uint8_t count_same_priority_lcids = 0;

    // variable used to store the total bytes read from rlc for each lcid
    uint32_t lcids_bytes_tot[NR_MAX_NUM_LCID] = {0};

    for (uint8_t id = 0; id < avail_lcids_count; id++) {
      /*
3008 3009 3010 3011
  loop over all logical channels in the order of priority. As stated in TS138.321 Section 5.4.3.1, in the first run, only
  prioritized number of bytes are taken out from the corresponding RLC buffers of all active logical channels and if there is
  still space availble in the MAC PDU, then from the next run all the remaining data from the higher priority logical channel
  is placed in the MAC PDU before going on to next high priority logical channel
3012
      */
3013
      int lcid = lcids_bj_pos[id].lcid;
3014 3015
      NR_LC_SCHEDULING_INFO *lc_sched_info = get_scheduling_info_from_lcid(mac, lcid);
      int idx = lcid_buffer_index(lcid);
3016 3017
      // skip the logical channel if no data in the buffer initially or the data in the buffer was zero because it was written in to
      // MAC PDU
3018 3019
      if (!lc_sched_info->LCID_buffer_with_data || !lcids_data_status[idx]) {
        lcids_data_status[idx] = false;
3020 3021
        continue;
      }
cig's avatar
cig committed
3022

3023 3024 3025
      // count number of lc with same priority as lcid
      if (!num_lcids_same_priority) {
        num_lcids_same_priority = count_same_priority_lcids =
3026
            get_count_lcids_same_priority(id, avail_lcids_count, lcids_bj_pos);
3027
      }
cig's avatar
cig committed
3028

3029
      buflen_remain = buflen - (mac_ce_p->total_mac_pdu_header_len + mac_ce_p->sdu_length_total + sh_size);
cig's avatar
cig committed
3030

francescomani's avatar
francescomani committed
3031
      LOG_D(NR_MAC,
3032
            "[UE %d] [%d.%d] UL-DXCH -> ULSCH, RLC with LCID 0x%02x (TBS %d bytes, sdu_length_total %d bytes, MAC header "
3033 3034
            "len %d bytes,"
            "buflen_remain %d bytes)\n",
3035
            mac->ue_id,
3036 3037
            frame,
            slot,
3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049
            lcid,
            buflen,
            mac_ce_p->sdu_length_total,
            mac_ce_p->tot_mac_ce_len,
            buflen_remain);

      if (num_lcids_same_priority == count_same_priority_lcids) {
        buflen_ep = (buflen_remain - (count_same_priority_lcids * sh_size)) / count_same_priority_lcids;
      }

      while (buflen_remain > 0) {
        /*
3050 3051 3052 3053 3054
          loops until the requested number of bytes from MAC to RLC are placed in the MAC PDU. The number of requested bytes
          depends on whether it is the first run or otherwise because in the first run only prioritited number of bytes of all
          active logical channels in the order of priority are placed in the MAC PDU. The 'get_num_bytes_to_reqlc' calculates
          the target number of bytes to request from RLC via 'mac_rlc_data_req'
        */
3055
        if (!fill_mac_sdu(mac,
3056 3057
                          frame,
                          slot,
Sriharsha Korada's avatar
Sriharsha Korada committed
3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070
                          gNB_index,
                          buflen,
                          &buflen_remain,
                          lcid,
                          &pdu,
                          &lcp_allocation_counter,
                          count_same_priority_lcids,
                          buflen_ep,
                          lcids_bytes_tot,
                          &num_sdus,
                          mac_ce_p,
                          lcids_data_status,
                          &num_lcids_same_priority)) {
3071 3072 3073
          break;
        }
      }
3074
    }
3075 3076 3077

    lcp_allocation_counter++;
  } while (buflen_remain > 0 && get_dataavailability_buffers(avail_lcids_count, lcids_bj_pos, lcids_data_status));
3078

3079 3080
  //nr_ue_get_sdu_mac_ce_post recalculates all mac_ce related header fields since buffer has been changed after mac_rlc_data_req.
  //Also, BSR padding is handled here after knowing mac_ce_p->sdu_length_total.
3081
  nr_ue_get_sdu_mac_ce_post(mac, CC_id, frame, slot, gNB_index, ulsch_buffer, buflen, mac_ce_p);
mjoang's avatar
mjoang committed
3082

3083
  if (mac_ce_p->tot_mac_ce_len > 0) {
cig's avatar
cig committed
3084

3085 3086 3087
    LOG_D(NR_MAC, "In %s copying %d bytes of MAC CEs to the UL PDU \n", __FUNCTION__, mac_ce_p->tot_mac_ce_len);
    nr_write_ce_ulsch_pdu(pdu, mac, 0, NULL, mac_ce_p->bsr_t, mac_ce_p->bsr_s, mac_ce_p->bsr_l);
    pdu += (unsigned char) mac_ce_p->tot_mac_ce_len;
cig's avatar
cig committed
3088

3089
#ifdef ENABLE_MAC_PAYLOAD_DEBUG
3090 3091
    LOG_I(NR_MAC, "In %s: dumping MAC CE with length tot_mac_ce_len %d: \n", __FUNCTION__, mac_ce_p->tot_mac_ce_len);
    log_dump(NR_MAC, mac_header_control_elements, mac_ce_p->tot_mac_ce_len, LOG_DUMP_CHAR, "\n");
3092
#endif
3093 3094
  }

3095
  buflen_remain = buflen - (mac_ce_p->total_mac_pdu_header_len + mac_ce_p->sdu_length_total);
3096

3097 3098
  // Compute final offset for padding and fill remainder of ULSCH with 0
  if (buflen_remain > 0) {
cig's avatar
cig committed
3099

3100
    LOG_D(NR_MAC, "In %s filling remainder %d bytes to the UL PDU \n", __FUNCTION__, buflen_remain);
3101 3102
    ((NR_MAC_SUBHEADER_FIXED *) pdu)->R = 0;
    ((NR_MAC_SUBHEADER_FIXED *) pdu)->LCID = UL_SCH_LCID_PADDING;
cig's avatar
cig committed
3103

3104
#ifdef ENABLE_MAC_PAYLOAD_DEBUG
3105 3106
    LOG_I(NR_MAC, "In %s: padding MAC sub-header with length %ld bytes \n", __FUNCTION__, sizeof(NR_MAC_SUBHEADER_FIXED));
    log_dump(NR_MAC, pdu, sizeof(NR_MAC_SUBHEADER_FIXED), LOG_DUMP_CHAR, "\n");
3107
#endif
cig's avatar
cig committed
3108

3109 3110
    pdu++;
    buflen_remain--;
cig's avatar
cig committed
3111

3112
    if (IS_SOFTMODEM_RFSIM) {
cig's avatar
cig committed
3113
      for (int j = 0; j < buflen_remain; j++) {
3114
        pdu[j] = (unsigned char)rand();
cig's avatar
cig committed
3115
      }
3116 3117
    } else {
      memset(pdu, 0, buflen_remain);
cig's avatar
cig committed
3118 3119
    }

3120
#ifdef ENABLE_MAC_PAYLOAD_DEBUG
3121 3122
    LOG_I(NR_MAC, "In %s: MAC padding sub-PDU with length %d bytes \n", __FUNCTION__, buflen_remain);
    log_dump(NR_MAC, pdu, buflen_remain, LOG_DUMP_CHAR, "\n");
3123
#endif
3124 3125
  }

3126
#ifdef ENABLE_MAC_PAYLOAD_DEBUG
3127 3128
  LOG_I(NR_MAC, "In %s: dumping MAC PDU with length %d: \n", __FUNCTION__, buflen);
  log_dump(NR_MAC, ulsch_buffer, buflen, LOG_DUMP_CHAR, "\n");
3129
#endif
3130

cig's avatar
cig committed
3131
  return num_sdus > 0 ? 1 : 0;
3132
}
cig's avatar
cig committed
3133

3134
static void schedule_ta_command(fapi_nr_dl_config_request_t *dl_config, NR_UL_TIME_ALIGNMENT_t *ul_time_alignment)
3135 3136 3137 3138
{
  fapi_nr_ta_command_pdu *ta = &dl_config->dl_config_list[dl_config->number_pdus].ta_command_pdu;
  ta->ta_frame = ul_time_alignment->frame;
  ta->ta_slot = ul_time_alignment->slot;
3139
  ta->is_rar = ul_time_alignment->ta_apply == rar_ta;
3140 3141 3142
  ta->ta_command = ul_time_alignment->ta_command;
  dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_CONFIG_TA_COMMAND;
  dl_config->number_pdus += 1;
3143
  ul_time_alignment->ta_apply = no_ta;
3144
}