nr_ue_scheduler.c 160 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 38 39

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

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

/* utils */
#include "assertions.h"
46
#include "oai_asn1.h"
47
#include "SIMULATION/TOOLS/sim.h" // for taus
48
#include "utils.h"
49

50 51
#include <executables/softmodem-common.h>

52
#include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h"
53
#include "LAYER2/RLC/rlc.h"
54
#include "RRC/NR_UE/L2_interface_ue.h"
mjoang's avatar
mjoang committed
55

56
//#define SRS_DEBUG
57 58 59 60 61
#define verifyMutex(a)                                                \
  {                                                                   \
    int ret = a;                                                      \
    AssertFatal(ret == 0, "Failure in mutex management ret=%d\n", a); \
  }
62

63
static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, sub_frame_t slotP);
64
static void schedule_ta_command(fapi_nr_dl_config_request_t *dl_config, NR_UL_TIME_ALIGNMENT_t *ul_time_alignment);
65 66 67 68 69 70
static void nr_ue_fill_phr(NR_UE_MAC_INST_t *mac,
                           NR_SINGLE_ENTRY_PHR_MAC_CE *phr,
                           float P_CMAX,
                           float tx_power,
                           frame_t frameP,
                           sub_frame_t subframe);
71

72 73 74 75 76
void clear_ul_config_request(NR_UE_MAC_INST_t *mac, int scs)
{
  int slots = nr_slots_per_frame[scs];
  for (int i = 0; i < slots ; i++) {
    fapi_nr_ul_config_request_t *ul_config = mac->ul_config_request + i;
77
    verifyMutex(pthread_mutex_lock(&ul_config->mutex_ul_config));
78
    ul_config->number_pdus = 0;
79
    verifyMutex(pthread_mutex_unlock(&ul_config->mutex_ul_config));
80 81 82
  }
}

83
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)
84
{
85 86 87
  NR_TDD_UL_DL_ConfigCommon_t *tdd_config = mac->tdd_UL_DL_ConfigurationCommon;

  // Check if requested on the right slot
88 89 90 91
  if (!is_nr_UL_slot(tdd_config, slot_tx, mac->frame_type)) {
    LOG_E(NR_MAC, "Lock of UL config for PDU type %d called for slot %d which is not UL\n", pdu_type, slot_tx);
    return NULL;
  }
92 93 94 95

  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;

96
  verifyMutex(pthread_mutex_lock(&ul_config->mutex_ul_config));
97 98
  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);
99 100
    ul_config->number_pdus = 0;
  }
101
  ul_config->frame = frame_tx;
102 103 104
  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);
105
    verifyMutex(pthread_mutex_unlock(&ul_config->mutex_ul_config));
106 107 108 109 110 111 112 113 114
    return NULL;
  }
  fapi_nr_ul_config_request_pdu_t *pdu = ul_config->ul_config_list + ul_config->number_pdus++;
  pdu->pdu_type = pdu_type;
  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;
}
115

116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
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;
}

134
NR_LC_SCHEDULING_INFO *get_scheduling_info_from_lcid(NR_UE_MAC_INST_t *mac, NR_LogicalChannelIdentity_t lcid)
135 136 137 138 139
{
  int idx = lcid_buffer_index(lcid);
  return &mac->scheduling_info.lc_sched_info[idx];
}

140
static void trigger_regular_bsr(NR_UE_MAC_INST_t *mac, NR_LogicalChannelIdentity_t lcid, bool sr_DelayTimerApplied)
141 142
{
  // Regular BSR trigger
143 144 145
  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);
146 147 148 149 150 151 152 153 154
  // 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);
}

155 156
void update_mac_timers(NR_UE_MAC_INST_t *mac)
{
157 158 159 160 161
  if (mac->data_inactivity_timer) {
    bool inactivity_timer_expired = nr_timer_tick(mac->data_inactivity_timer);
    if (inactivity_timer_expired)
      nr_mac_rrc_inactivity_timer_ind(mac->ue_id);
  }
162
  nr_timer_tick(&mac->ra.contention_resolution_timer);
163 164
  for (int j = 0; j < NR_MAX_SR_ID; j++)
    nr_timer_tick(&mac->scheduling_info.sr_info[j].prohibitTimer);
165
  nr_timer_tick(&mac->scheduling_info.sr_DelayTimer);
166 167 168 169 170 171 172 173
  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);
174
      if (lc_sched_info->LCGID != NR_INVALID_LCGID && lc_sched_info->LCID_buffer_remain > 0) {
175
        LOG_D(NR_MAC, "Triggering regular BSR after retxBSR timer expired\n");
176 177
        trigger_regular_bsr(mac, lcid, lc_info->sr_DelayTimerApplied);
        break;
178 179 180
      }
    }
  }
181 182 183
  bool periodicBSR_expired = nr_timer_tick(&mac->scheduling_info.periodicBSR_Timer);
  if (periodicBSR_expired) {
    // periodicBSR-Timer expires, trigger BSR
184
    mac->scheduling_info.BSR_reporting_active |= NR_BSR_TRIGGER_PERIODIC;
185 186
    LOG_D(NR_MAC, "[UE %d] MAC BSR Triggered PeriodicBSR Timer expiry\n", mac->ue_id);
  }
187 188 189 190
  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);
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205

  nr_phr_info_t *phr_info = &mac->scheduling_info.phr_info;
  if (phr_info->is_configured) {
    bool prohibit_expired = nr_timer_tick(&phr_info->prohibitPHR_Timer);
    if (prohibit_expired) {
      int16_t pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm);
      if (abs(pathloss - phr_info->PathlossLastValue) > phr_info->PathlossChange_db) {
        phr_info->phr_reporting |= (1 << phr_cause_prohibit_timer);
      }
    }
    bool periodic_expired = nr_timer_tick(&phr_info->periodicPHR_Timer);
    if (periodic_expired) {
      phr_info->phr_reporting |= (1 << phr_cause_periodic_timer);
    }
  }
206 207
}

208 209 210
void remove_ul_config_last_item(fapi_nr_ul_config_request_pdu_t *pdu)
{
  pdu->privateNBpdus--;
211 212
}

213
void release_ul_config(fapi_nr_ul_config_request_pdu_t *configPerSlot, bool clearIt)
214
{
215 216
  if (clearIt)
    *configPerSlot->privateNBpdus = 0;
217
  verifyMutex(pthread_mutex_unlock(configPerSlot->lock));
218
}
francescomani's avatar
francescomani committed
219

220 221
fapi_nr_ul_config_request_pdu_t *fapiLockIterator(fapi_nr_ul_config_request_t *ul_config, frame_t frame_tx, int slot_tx)
{
222
  verifyMutex(pthread_mutex_lock(&ul_config->mutex_ul_config));
223 224
  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);
225
    verifyMutex(pthread_mutex_unlock(&ul_config->mutex_ul_config));
226 227 228 229 230
    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;
231
    verifyMutex(pthread_mutex_unlock(&ul_config->mutex_ul_config));
232 233 234 235
    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);
236
    verifyMutex(pthread_mutex_unlock(&ul_config->mutex_ul_config));
237 238 239 240 241 242 243 244
    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;
}
245

246 247 248
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;
249
  //Check if requested on the right slot
250 251 252 253
  if (!is_nr_UL_slot(tdd_config, slot_tx, mac->frame_type)) {
    LOG_E(NR_MAC, "UL lock iterator called for slot %d which is not UL\n", slot_tx);
    return NULL;
  }
francescomani's avatar
francescomani committed
254
  AssertFatal(mac->ul_config_request != NULL, "mac->ul_config_request not initialized, logic bug\n");
255
  return fapiLockIterator(mac->ul_config_request + slot_tx, frame_tx, slot_tx);
256 257 258 259 260 261 262 263
}

/*
 * 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
264 265
  AssertFatal(mac->dl_config_request != NULL, "mac->dl_config_request not initialized, logic bug\n");
  return &mac->dl_config_request[slot];
266 267
}

268
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)
269
{
270
  NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
271
  NR_SRS_Config_t *srs_config = current_UL_BWP->srs_Config;
272
  NR_PUSCH_Config_t *pusch_Config = current_UL_BWP->pusch_Config;
273

274
  long transformPrecoder = pusch_config_pdu->transform_precoding;
275

276 277 278
  /* PRECOD_NBR_LAYERS */
  // 0 bits if the higher layer parameter txConfig = nonCodeBook

279
  if (*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook){
280

281 282 283 284
    // 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);
285

286
    // 1 antenna port and the higher layer parameter txConfig = codebook 0 bits
287

francescomani's avatar
francescomani committed
288
    if (n_antenna_port == 4) { // 4 antenna port and the higher layer parameter txConfig = codebook
289 290

      // Table 7.3.1.1.2-2: transformPrecoder=disabled and maxRank = 2 or 3 or 4
291
      if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled)
292
          && ((*pusch_Config->maxRank == 2) || (*pusch_Config->maxRank == 3) || (*pusch_Config->maxRank == 4))) {
293
        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) {
294
          pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][0];
295
          pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][1];
296 297
        }

298
        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent){
299
          pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][2];
300
          pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][3];
301 302
        }

303
        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent){
304
          pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][4];
305
          pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][5];
306 307 308 309
        }
      }

      // Table 7.3.1.1.2-3: transformPrecoder= enabled, or transformPrecoder=disabled and maxRank = 1
310
      if (((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled)
311 312
           || (transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled))
          && (*pusch_Config->maxRank == 1)) {
313
        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) {
314
          pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][6];
315
          pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][7];
316 317
        }

318
        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent){
319
          pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][8];
320
          pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][9];
321 322
        }

323
        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent){
324
          pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][10];
325
          pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][11];
326 327 328 329
        }
      }
    }

francescomani's avatar
francescomani committed
330 331
    if (n_antenna_port == 2) {
      // 2 antenna port and the higher layer parameter txConfig = codebook
332
      // Table 7.3.1.1.2-4: transformPrecoder=disabled and maxRank = 2
francescomani's avatar
francescomani committed
333
      if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (*pusch_Config->maxRank == 2)) {
334
        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) {
335
          pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][12];
336
          pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][13];
337 338
        }

339
        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent){
340
          pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][14];
341
          pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][15];
342 343 344 345 346
        }

      }

      // Table 7.3.1.1.2-5: transformPrecoder= enabled, or transformPrecoder= disabled and maxRank = 1
347
      if (((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled)
348 349
           || (transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled))
          && (*pusch_Config->maxRank == 1)) {
350
        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) {
351
          pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][16];
352
          pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][17];
353 354
        }

355
        if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent){
356
          pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][18];
357
          pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][19];
358 359 360 361 362 363 364
        }
      }
    }
  }
}

// todo: this function shall be reviewed completely because of the many comments left by the author
365 366
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)
{
367
  uint8_t rank = pusch_config_pdu->nrOfLayers;
368

369
  NR_PUSCH_Config_t *pusch_Config = mac->current_UL_BWP->pusch_Config;
370
  AssertFatal(pusch_Config!=NULL,"pusch_Config shouldn't be null\n");
371

372 373 374
  long transformPrecoder = pusch_config_pdu->transform_precoding;
  LOG_D(NR_MAC,"transformPrecoder %s\n", transformPrecoder==NR_PUSCH_Config__transformPrecoder_disabled ? "disabled" : "enabled");

375 376 377 378 379 380 381 382 383 384 385
  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
386 387
  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);
388

389
  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) &&
390
      (dmrs_type == NULL) && (max_length == NULL)) { // tables 7.3.1.1.2-6
391 392
    pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2;
    pusch_config_pdu->dmrs_ports = 1 << dci->antenna_ports.val;
393 394
  }

395
  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) &&
396
      (dmrs_type == NULL) && (max_length != NULL)) { // tables 7.3.1.1.2-7
397 398

    pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; //TBC
399 400
    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;
401 402
  }

403 404
  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (dmrs_type == NULL)
      && (max_length == NULL)) { // tables 7.3.1.1.2-8/9/10/11
405 406

    if (rank == 1) {
407 408
      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));
409 410 411
    }

    if (rank == 2){
412 413
      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;
414 415 416
    }

    if (rank == 3){
417
      pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2;
418
      pusch_config_pdu->dmrs_ports = 0x7;  // ports 0-2
419 420 421
    }

    if (rank == 4){
422
      pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2;
423
      pusch_config_pdu->dmrs_ports = 0xf;  // ports 0-3
424 425 426
    }
  }

427 428
  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (dmrs_type == NULL)
      && (max_length != NULL)) { // tables 7.3.1.1.2-12/13/14/15
429 430 431

    if (rank == 1){
      pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 1)?2:1; //TBC
432 433
      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;
434 435 436 437 438 439 440
    }

    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];
441
      //n_front_load_symb = (dci->antenna_ports.val > 3)?2:1; // FIXME
442 443 444 445 446 447 448 449
    }

    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];
450
      //n_front_load_symb = (dci->antenna_ports.val > 1)?2:1; //FIXME
451 452 453 454 455 456 457 458 459
    }

    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];
460
      //n_front_load_symb = (dci->antenna_ports.val > 1)?2:1; //FIXME
461 462 463
    }
  }

464 465
  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (dmrs_type != NULL)
      && (max_length == NULL)) { // tables 7.3.1.1.2-16/17/18/19
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496

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

497 498
  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (dmrs_type != NULL)
      && (max_length != NULL)) { // tables 7.3.1.1.2-20/21/22/23
499 500 501 502

    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
503
      //n_front_load_symb = table_7_3_1_1_2_20[dci->antenna_ports.val][2]; //FIXME
504 505 506 507 508 509 510
    }

    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];
511
      //n_front_load_symb = table_7_3_1_1_2_21[dci->antenna_ports.val][3]; //FIXME
512
    }
513 514 515 516 517 518 519

    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];
520
      //n_front_load_symb = table_7_3_1_1_2_22[dci->antenna_ports.val][4]; //FIXME
521 522 523 524 525 526 527 528 529
    }

    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];
530
      //n_front_load_symb = table_7_3_1_1_2_23[dci->antenna_ports.val][5]; //FIXME
531 532
    }
  }
533
  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);
534 535 536 537 538 539 540 541 542 543
}

// 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
544 545 546 547
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,
548
                        csi_payload_t *csi_report,
549 550
                        RAR_grant_t *rar_grant,
                        uint16_t rnti,
551
                        int ss_type,
552
                        const nr_dci_format_t dci_format)
553
{
554 555
  uint16_t l_prime_mask = 0;
  int N_PRB_oh  = 0;
556 557

  int rnti_type = get_rnti_type(mac, rnti);
558
  NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
559
  NR_UE_ServingCell_Info_t *sc_info = &mac->sc_info;
560 561 562

  // Common configuration
  pusch_config_pdu->dmrs_config_type = pusch_dmrs_type1;
563 564 565 566
  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;
567

568
  pusch_dmrs_AdditionalPosition_t add_pos = pusch_dmrs_pos2;
569
  int dmrslength = 1;
570
  NR_PUSCH_Config_t *pusch_Config = current_UL_BWP->pusch_Config;
571

572 573 574
  if (rar_grant) {

    // Note: for Msg3 or MsgA PUSCH transmission the N_PRB_oh is always set to 0
575 576
    int ibwp_start = sc_info->initial_ul_BWPStart;
    int ibwp_size = sc_info->initial_ul_BWPSize;
577 578 579
    int abwp_start = current_UL_BWP->BWPStart;
    int abwp_size = current_UL_BWP->BWPSize;
    int scs = current_UL_BWP->scs;
580

581
    // BWP start selection according to 8.3 of TS 38.213
582
    if ((ibwp_start < abwp_start) || (ibwp_size > abwp_size)) {
583
      pusch_config_pdu->bwp_start = abwp_start;
584 585
      pusch_config_pdu->bwp_size = abwp_size;
    } else {
586
      pusch_config_pdu->bwp_start = ibwp_start;
587 588
      pusch_config_pdu->bwp_size = ibwp_size;
    }
589 590 591

    //// Resource assignment from RAR
    // Frequency domain allocation according to 8.3 of TS 38.213
592
    int mask;
593 594 595 596
    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;
597

598 599 600 601 602 603 604 605
    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,
606
                                                       f_alloc) < 0) {
607
      LOG_E(NR_MAC, "can't nr_ue_process_dci_freq_dom_resource_assignment()\n");
608
      return -1;
609
    }
610 611

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

    // Time domain allocation
615 616
    pusch_config_pdu->start_symbol_index = tda_info->startSymbolIndex;
    pusch_config_pdu->nr_of_symbols = tda_info->nrOfSymbols;
617

618 619 620 621 622 623
    l_prime_mask = get_l_prime(tda_info->nrOfSymbols,
                               tda_info->mapping_type,
                               add_pos,
                               dmrslength,
                               tda_info->startSymbolIndex,
                               mac->dmrs_TypeA_Position);
624
    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);
625

626
#ifdef DEBUG_MSG3
627
    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);
628
#endif
629 630 631 632 633 634 635 636 637 638 639 640 641 642 643

    // 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
644
    pusch_config_pdu->transform_precoding = get_transformPrecoding(current_UL_BWP, NR_UL_DCI_FORMAT_0_0, 0); // as if it was DCI 0_0
645 646

    // Resource allocation in frequency domain according to 6.1.2.2 in TS 38.214
647
    pusch_config_pdu->resource_alloc = 1;
648 649 650 651

    //// Completing PUSCH PDU
    pusch_config_pdu->mcs_table = 0;
    pusch_config_pdu->cyclic_prefix = 0;
652 653 654
    pusch_config_pdu->data_scrambling_id = mac->physCellId;
    pusch_config_pdu->ul_dmrs_scrambling_id = mac->physCellId;
    pusch_config_pdu->subcarrier_spacing = scs;
655 656 657 658 659
    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;
660
    pusch_config_pdu->pusch_data.new_data_indicator = true; // new data
661
    pusch_config_pdu->pusch_data.num_cb = 0;
662
    pusch_config_pdu->tbslbrm = 0;
663 664

  } else if (dci) {
francescomani's avatar
francescomani committed
665
    pusch_config_pdu->ulsch_indicator = dci->ulsch_indicator;
666 667 668 669 670 671
    if (dci->csi_request.nbits > 0 && dci->csi_request.val > 0) {
      AssertFatal(csi_report, "CSI report needs to be present in case of CSI request\n");
      pusch_config_pdu->pusch_uci.csi_part1_bit_length = csi_report->p1_bits;
      pusch_config_pdu->pusch_uci.csi_part1_payload = csi_report->part1_payload;
      pusch_config_pdu->pusch_uci.csi_part2_bit_length = csi_report->p2_bits;
      pusch_config_pdu->pusch_uci.csi_part2_payload = csi_report->part2_payload;
672 673 674 675 676
      AssertFatal(pusch_Config && pusch_Config->uci_OnPUSCH, "UCI on PUSCH need to be configured\n");
      NR_UCI_OnPUSCH_t *onPusch = pusch_Config->uci_OnPUSCH->choice.setup;
      AssertFatal(onPusch &&
                  onPusch->betaOffsets &&
                  onPusch->betaOffsets->present == NR_UCI_OnPUSCH__betaOffsets_PR_semiStatic,
677
                  "Only semistatic beta offset is supported\n");
678 679
      NR_BetaOffsets_t *beta_offsets = onPusch->betaOffsets->choice.semiStatic;

680 681 682 683 684 685
      pusch_config_pdu->pusch_uci.beta_offset_csi1 = pusch_config_pdu->pusch_uci.csi_part1_bit_length < 12 ?
                                                     *beta_offsets->betaOffsetCSI_Part1_Index1 :
                                                     *beta_offsets->betaOffsetCSI_Part1_Index2;
      pusch_config_pdu->pusch_uci.beta_offset_csi2 = pusch_config_pdu->pusch_uci.csi_part2_bit_length < 12 ?
                                                     *beta_offsets->betaOffsetCSI_Part2_Index1 :
                                                     *beta_offsets->betaOffsetCSI_Part2_Index2;
686
      pusch_config_pdu->pusch_uci.alpha_scaling = onPusch->scaling;
687 688 689 690 691 692 693 694
    }
    else {
      pusch_config_pdu->pusch_uci.csi_part1_bit_length = 0;
      pusch_config_pdu->pusch_uci.csi_part2_bit_length = 0;
    }

    pusch_config_pdu->pusch_uci.harq_ack_bit_length = 0;

695 696 697 698 699 700 701
    if (dci_format == NR_UL_DCI_FORMAT_0_0 && ss_type == NR_SearchSpace__searchSpaceType_PR_common) {
      pusch_config_pdu->bwp_start = sc_info->initial_ul_BWPStart;
      pusch_config_pdu->bwp_size = sc_info->initial_ul_BWPSize;
    } else {
      pusch_config_pdu->bwp_start = current_UL_BWP->BWPStart;
      pusch_config_pdu->bwp_size = current_UL_BWP->BWPSize;
    }
702

703 704 705
    pusch_config_pdu->start_symbol_index = tda_info->startSymbolIndex;
    pusch_config_pdu->nr_of_symbols = tda_info->nrOfSymbols;

706
    /* Transform precoding */
707
    pusch_config_pdu->transform_precoding = get_transformPrecoding(current_UL_BWP, dci_format, 0);
708
    bool tp_enabled = pusch_config_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled;
709 710

    /*DCI format-related configuration*/
711
    if (dci_format == NR_UL_DCI_FORMAT_0_0) {
712
      if (!tp_enabled && pusch_config_pdu->nr_of_symbols < 3)
713 714 715
        pusch_config_pdu->num_dmrs_cdm_grps_no_data = 1;
      else
        pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2;
716 717 718
    } 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);
719
    } else {
720 721 722 723 724 725
      LOG_E(NR_MAC, "UL grant from DCI format %d is not handled...\n", dci_format);
      return -1;
    }

    if (pusch_config_pdu->nrOfLayers < 1) {
      LOG_E(NR_MAC, "Invalid UL number of layers %d from DCI\n", pusch_config_pdu->nrOfLayers);
726 727 728
      return -1;
    }

729
    int mappingtype = tda_info->mapping_type;
730 731

    NR_DMRS_UplinkConfig_t *NR_DMRS_ulconfig = NULL;
732 733
    if(pusch_Config) {
      NR_DMRS_ulconfig = (mappingtype == NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeA)
734 735
                             ? pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup
                             : pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup;
736
    }
737

738
    pusch_config_pdu->scid = 0;
739
    pusch_config_pdu->data_scrambling_id = mac->physCellId;
740 741
    if (pusch_Config
        && pusch_Config->dataScramblingIdentityPUSCH
742 743 744 745
        && 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;

746
    pusch_config_pdu->ul_dmrs_scrambling_id = mac->physCellId;
747
    if (dci_format == NR_UL_DCI_FORMAT_0_1)
748 749
      pusch_config_pdu->scid = dci->dmrs_sequence_initialization.val;

750
    /* TRANSFORM PRECODING ------------------------------------------------------------------------------------------*/
751
    if (tp_enabled) {
752 753

      uint32_t n_RS_Id = 0;
rmagueta's avatar
rmagueta committed
754 755
      if (NR_DMRS_ulconfig->transformPrecodingEnabled &&
          NR_DMRS_ulconfig->transformPrecodingEnabled->nPUSCH_Identity != NULL)
756 757
        n_RS_Id = *NR_DMRS_ulconfig->transformPrecodingEnabled->nPUSCH_Identity;
      else
758
        n_RS_Id = mac->physCellId;
759 760 761 762 763

      // 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
764 765 766
      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;
767 768 769
      else
        AssertFatal(1==0,"SequenceGroupHopping or sequenceHopping are NOT Supported\n");

770 771 772 773
      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);
774
    }
775
    else {
Laurent THOMAS's avatar
Laurent THOMAS committed
776
      if (pusch_config_pdu->scid == 0 && NR_DMRS_ulconfig && NR_DMRS_ulconfig->transformPrecodingDisabled &&
777 778
          NR_DMRS_ulconfig->transformPrecodingDisabled->scramblingID0)
        pusch_config_pdu->ul_dmrs_scrambling_id = *NR_DMRS_ulconfig->transformPrecodingDisabled->scramblingID0;
779
      if (pusch_config_pdu->scid == 1 && NR_DMRS_ulconfig &&
780 781 782
          NR_DMRS_ulconfig->transformPrecodingDisabled->scramblingID1)
        pusch_config_pdu->ul_dmrs_scrambling_id = *NR_DMRS_ulconfig->transformPrecodingDisabled->scramblingID1;
    }
783 784 785

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

786 787
    /* IDENTIFIER_DCI_FORMATS */
    /* FREQ_DOM_RESOURCE_ASSIGNMENT_UL */
788 789 790
    if (nr_ue_process_dci_freq_dom_resource_assignment(pusch_config_pdu,
                                                       NULL,
                                                       NULL,
791
                                                       pusch_config_pdu->bwp_size,
792 793 794
                                                       0,
                                                       0,
                                                       dci->frequency_domain_assignment) < 0) {
795
      LOG_E(NR_MAC, "can't nr_ue_process_dci_freq_dom_resource_assignment()\n");
796 797
      return -1;
    }
798

799
    /* FREQ_HOPPING_FLAG */
800 801
    if (pusch_Config
        && pusch_Config->frequencyHopping
802
        && (pusch_Config->resourceAllocation != NR_PUSCH_Config__resourceAllocation_resourceAllocationType0)) {
803 804 805 806 807 808 809
      pusch_config_pdu->frequency_hopping = dci->frequency_hopping_flag.val;
    }

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

    /* MCS TABLE */
810
    long *mcs_table_config = pusch_Config ? (tp_enabled ? pusch_Config->mcs_TableTransformPrecoder : pusch_Config->mcs_Table) : NULL;
811
    pusch_config_pdu->mcs_table = get_pusch_mcs_table(mcs_table_config, tp_enabled, dci_format, rnti_type, ss_type, false);
812 813

    /* NDI */
814
    NR_UL_HARQ_INFO_t *harq = &mac->ul_harq_info[dci->harq_pid.val];
815 816 817
    pusch_config_pdu->pusch_data.new_data_indicator = false;
    if (dci->ndi != harq->last_ndi) {
      pusch_config_pdu->pusch_data.new_data_indicator = true;
818
      // if new data reset harq structure
819
      memset(harq, 0, sizeof(*harq));
820
    }
821
    harq->last_ndi = dci->ndi;
822 823 824
    /* RV */
    pusch_config_pdu->pusch_data.rv_index = dci->rv;
    /* HARQ_PROCESS_NUMBER */
825
    pusch_config_pdu->pusch_data.harq_process_id = dci->harq_pid.val;
826

827
    if (NR_DMRS_ulconfig != NULL)
828 829
      add_pos = (NR_DMRS_ulconfig->dmrs_AdditionalPosition == NULL) ? 2 : *NR_DMRS_ulconfig->dmrs_AdditionalPosition;

830
    /* DMRS */
831 832 833
    l_prime_mask = get_l_prime(pusch_config_pdu->nr_of_symbols,
                               mappingtype, add_pos, dmrslength,
                               pusch_config_pdu->start_symbol_index,
834
                               mac->dmrs_TypeA_Position);
835

836 837
    if (sc_info->xOverhead_PUSCH)
      N_PRB_oh = 6 * (1 + *sc_info->xOverhead_PUSCH);
838 839 840
    else
      N_PRB_oh = 0;

841
    if (sc_info->rateMatching_PUSCH) {
842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857
      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);
858
    } else
859 860
      pusch_config_pdu->tbslbrm = 0;

861
    /* PTRS */
862 863
    if (pusch_Config && pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB &&
        pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS) {
864
      if (!tp_enabled) {
865 866
        nfapi_nr_ue_ptrs_ports_t ptrs_ports_list;
        pusch_config_pdu->pusch_ptrs.ptrs_ports_list = &ptrs_ports_list;
867 868 869 870 871 872 873 874 875 876 877
        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) {
878 879
          pusch_config_pdu->pdu_bit_map |= PUSCH_PDU_BITMAP_PUSCH_PTRS;
        }
880 881
        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);
882
      }
883 884 885
    }
  }

886 887
  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",
888 889 890 891
        pusch_config_pdu->rb_start,
        pusch_config_pdu->rb_size,
        pusch_config_pdu->start_symbol_index,
        pusch_config_pdu->nr_of_symbols,
892
        rnti_types(rnti_type));
893

894
  pusch_config_pdu->ul_dmrs_symb_pos = l_prime_mask;
895
  pusch_config_pdu->qam_mod_order = nr_get_Qm_ul(pusch_config_pdu->mcs_index, pusch_config_pdu->mcs_table);
896 897
  if (pusch_config_pdu->qam_mod_order == 0) {
    LOG_W(NR_MAC, "Invalid Mod order, likely due to unexpected UL DCI. Ignoring DCI! \n");
898 899 900
    return -1;
  }

francescomani's avatar
francescomani committed
901 902
  int start_symbol = pusch_config_pdu->start_symbol_index;
  int number_of_symbols = pusch_config_pdu->nr_of_symbols;
903
  int number_dmrs_symbols = 0;
francescomani's avatar
francescomani committed
904 905 906 907 908
  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;
  }

909
  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;
910 911

  // Compute TBS
912 913 914 915
  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;
916 917 918 919
    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,
920
                                                          nb_dmrs_re_per_rb * number_dmrs_symbols,
921 922
                                                          N_PRB_oh,
                                                          0, // TBR to verify tb scaling
923 924 925 926 927 928 929 930
                                                          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;
  }
931

932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947
  /* TPC_PUSCH */
  int delta_pusch = 0;
  if (dci) {
    bool stateless_pusch_power_control = mac->current_UL_BWP->pusch_Config != NULL
                                        && mac->current_UL_BWP->pusch_Config->pusch_PowerControl != NULL
                                        && mac->current_UL_BWP->pusch_Config->pusch_PowerControl->tpc_Accumulation != NULL;
    int table_38_213_7_1_1_1[2][4] = {{-1, 0, 1, 3}, {-4, -1, 1, 4}};
    if (stateless_pusch_power_control) {
      delta_pusch = table_38_213_7_1_1_1[1][dci->tpc];
    } else {
      // TODO: This is not entirely correct. In case there is a prevously scheduled PUSCH for a future slot
      // we should apply its TPC now.
      delta_pusch = table_38_213_7_1_1_1[0][dci->tpc];
    }
  }

948 949 950 951 952 953 954 955 956 957 958 959
  bool is_rar_tx_retx = rnti_type == TYPE_TC_RNTI_;

  pusch_config_pdu->tx_power = get_pusch_tx_power_ue(mac,
                                                     pusch_config_pdu->rb_size,
                                                     pusch_config_pdu->rb_start,
                                                     pusch_config_pdu->nr_of_symbols,
                                                     nb_dmrs_re_per_rb * number_dmrs_symbols,
                                                     0, //TODO: count PTRS per RB
                                                     pusch_config_pdu->qam_mod_order,
                                                     pusch_config_pdu->target_code_rate,
                                                     pusch_config_pdu->pusch_uci.beta_offset_csi1,
                                                     pusch_config_pdu->pusch_data.tb_size << 3,
960
                                                     delta_pusch,
961 962 963
                                                     is_rar_tx_retx,
                                                     pusch_config_pdu->transform_precoding);

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

966 967 968 969
  //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);

970 971 972 973 974
  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;
  }

975 976 977 978 979 980 981 982 983 984
  // 38.321 5.4.6
  //  if it is the first UL resource allocated for a new transmission since the last MAC reset:
  //  2> start phr-PeriodicTimer;
  if (mac->scheduling_info.phr_info.is_configured) {
    if (mac->scheduling_info.phr_info.was_mac_reset && pusch_config_pdu->pusch_data.new_data_indicator) {
      mac->scheduling_info.phr_info.was_mac_reset = false;
      nr_timer_start(&mac->scheduling_info.phr_info.periodicPHR_Timer);
    }
  }

985 986 987
  return 0;
}

988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028
csi_payload_t nr_ue_aperiodic_csi_reporting(NR_UE_MAC_INST_t *mac, dci_field_t csi_request, int tda, long *k2)
{
  NR_CSI_AperiodicTriggerStateList_t *aperiodicTriggerStateList = mac->sc_info.aperiodicTriggerStateList;
  AssertFatal(aperiodicTriggerStateList, "Received CSI request via DCI but aperiodicTriggerStateList is not present\n");
  int n_states = aperiodicTriggerStateList->list.count;
  int n_ts = csi_request.nbits;
  csi_payload_t csi = {0};
  AssertFatal(n_states <= ((1 << n_ts) - 1), "Case of subselection indication of trigger states not supported yet\n");
  int num_trig = 0;
  for (int i = 0; i < n_ts; i++) {
    // A non-zero codepoint of the CSI request field in the DCI is mapped to a CSI triggering state
    // according to the order of the associated positions of the up to (2^n_ts -1) trigger states
    // in CSI-AperiodicTriggerStateList with codepoint 1 mapped to the triggering state in the first position
    if (csi_request.val & (1 << i)) {
      AssertFatal(num_trig == 0, "Multiplexing more than 1 CSI report is not supported\n");
      NR_CSI_AperiodicTriggerState_t *trigger_state = aperiodicTriggerStateList->list.array[i];
      AssertFatal(trigger_state->associatedReportConfigInfoList.list.count == 1,
                  "Cannot handle more than 1 report configuration per state\n");
      NR_CSI_AssociatedReportConfigInfo_t *reportconfig = trigger_state->associatedReportConfigInfoList.list.array[0];
      NR_CSI_ReportConfigId_t id = reportconfig->reportConfigId;
      NR_CSI_MeasConfig_t *csi_measconfig = mac->sc_info.csi_MeasConfig;
      int found = -1;
      for (int c = 0; c < csi_measconfig->csi_ReportConfigToAddModList->list.count; c++) {
        NR_CSI_ReportConfig_t *report_config = csi_measconfig->csi_ReportConfigToAddModList->list.array[c];
        if (report_config->reportConfigId == id) {
          struct NR_CSI_ReportConfig__reportConfigType__aperiodic__reportSlotOffsetList *offset_list = &report_config->reportConfigType.choice.aperiodic->reportSlotOffsetList;
          AssertFatal(tda < offset_list->list.count, "TDA index from DCI %d exceeds slot offset list %d\n", tda, offset_list->list.count);
          if (k2 == NULL || *k2 < *offset_list->list.array[tda])
            k2 = offset_list->list.array[tda];
          found = c;
          break;
        }
      }
      AssertFatal(found >= 0, "Couldn't find csi-ReportConfig with ID %ld\n", id);
      num_trig++;
      csi = nr_get_csi_payload(mac, found, ON_PUSCH, csi_measconfig);
    }
  }
  return csi;
}

1029 1030 1031 1032 1033
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)
1034
{
1035
  NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100

  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
1101
  return 0;
1102 1103 1104 1105 1106
}

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

1147 1148 1149
  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",
              slot_offset, DURATION_RX_TO_TX);
1150 1151
  int n_slots_frame = nr_slots_per_frame[current_UL_BWP->scs];
  int sched_slot = (slot + slot_offset) % n_slots_frame;
1152
  NR_TDD_UL_DL_ConfigCommon_t *tdd_config = mac->tdd_UL_DL_ConfigurationCommon;
1153 1154 1155 1156
  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;
  }
1157
  int sched_frame = frame + (slot + slot_offset / n_slots_frame) % MAX_FRAME_NUMBER;
1158 1159 1160 1161 1162 1163 1164
  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);
1165 1166 1167
}


1168
// Periodic SRS scheduling
1169
static bool nr_ue_periodic_srs_scheduling(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot)
francescomani's avatar
francescomani committed
1170
{
1171
  bool srs_scheduled = false;
1172
  NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
1173

1174
  NR_SRS_Config_t *srs_config = current_UL_BWP ? current_UL_BWP->srs_Config : NULL;
1175 1176

  if (!srs_config) {
1177
    return false;
1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204
  }

  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];
1205
    uint16_t offset = get_nr_srs_offset(srs_resource->resourceType.choice.periodic->periodicityAndOffset_p);
1206

francescomani's avatar
francescomani committed
1207
    int n_slots_frame = nr_slots_per_frame[current_UL_BWP->scs];
1208 1209 1210

    // Check if UE should transmit the SRS
    if((frame*n_slots_frame+slot-offset)%period == 0) {
1211 1212 1213 1214 1215 1216 1217 1218 1219
      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);
1220 1221
    }
  }
1222
  return srs_scheduled;
1223 1224
}

1225 1226 1227
// Performs :
// 1. TODO: Call RRC for link status return to PHY
// 2. TODO: Perform SR/BSR procedures for scheduling feedback
1228
void nr_ue_dl_scheduler(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info)
francescomani's avatar
francescomani committed
1229
{
1230 1231
  frame_t rx_frame = dl_info->frame;
  slot_t rx_slot = dl_info->slot;
1232

1233 1234 1235
  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;
1236
  dl_config->number_pdus = 0;
1237

1238
  if (mac->state == UE_NOT_SYNC || mac->state == UE_DETACHING)
1239
    return;
francescomani's avatar
francescomani committed
1240

1241 1242 1243
  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
1244
  }
1245

1246 1247 1248 1249 1250
  ue_dci_configuration(mac, dl_config, rx_frame, rx_slot);

  if (mac->ul_time_alignment.ta_apply != no_ta)
    schedule_ta_command(dl_config, &mac->ul_time_alignment);

1251
  nr_scheduled_response_t scheduled_response = {.dl_config = dl_config,
1252
                                                .module_id = mac->ue_id,
1253 1254 1255 1256 1257
                                                .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
1258
  else
1259
    LOG_E(NR_MAC, "Internal error, no scheduled_response function\n");
francescomani's avatar
francescomani committed
1260
}
1261

1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274
static bool check_pucchres_for_pending_SR(NR_PUCCH_Config_t *pucch_Config, int target_sr_id)
{
  for (int id = 0; id < pucch_Config->schedulingRequestResourceToAddModList->list.count; id++) {
    NR_SchedulingRequestResourceConfig_t *sr_Config = pucch_Config->schedulingRequestResourceToAddModList->list.array[id];
    if (sr_Config->schedulingRequestID == target_sr_id)  {
      if (sr_Config->resource) {
        return true;
      }
    }
  }
  return false;
}

1275
static void nr_update_sr(NR_UE_MAC_INST_t *mac)
1276 1277
{
  NR_UE_SCHEDULING_INFO *sched_info = &mac->scheduling_info;
1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299

  // if no pending data available for transmission
  // All pending SR(s) shall be cancelled and each respective sr-ProhibitTimer shall be stopped
  bool data_avail = false;
  for (int i = 0; i < NR_MAX_NUM_LCID; i++) {
    if (sched_info->lc_sched_info[i].LCID_buffer_remain > 0) {
      data_avail = true;
      break;
    }
  }
  if (!data_avail) {
    for (int i = 0; i < NR_MAX_SR_ID; i++) {
      nr_sr_info_t *sr = &sched_info->sr_info[i];
      if (sr->active_SR_ID) {
        LOG_D(NR_MAC, "No pending data available -> Canceling pending SRs\n");
        sr->pending = false;
        sr->counter = 0;
        nr_timer_stop(&sr->prohibitTimer);
      }
    }
  }

1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316
  // 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

1317 1318 1319 1320 1321
  if (lc_info->sr_id < 0 || lc_info->sr_id >= NR_MAX_SR_ID)
    LOG_E(NR_MAC, "No SR corresponding to this LCID\n"); // TODO not sure what to do here
  else {
    nr_sr_info_t *sr = &sched_info->sr_info[lc_info->sr_id];
    if (!sr->pending) {
1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337
      NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
      NR_PUCCH_Config_t *pucch_Config = current_UL_BWP ? current_UL_BWP->pucch_Config : NULL;
      if (check_pucchres_for_pending_SR(pucch_Config, lc_info->sr_id)) {
        // trigger SR
        LOG_D(NR_MAC, "Triggering SR for ID %d\n", lc_info->sr_id);
        sr->pending = true;
        sr->counter = 0;
      }
      else {
        // initiate a Random Access procedure on the SpCell and cancel the pending SR
        // if the MAC entity has no valid PUCCH resource configured for the pending SR
        sr->pending = false;
        sr->counter = 0;
        nr_timer_stop(&sr->prohibitTimer);
        schedule_RA_after_SR_failure(mac);
      }
1338 1339
    }
  }
1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408
}

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

1409
void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info)
francescomani's avatar
francescomani committed
1410
{
1411
  int cc_id = ul_info->cc_id;
1412 1413
  frame_t frame_tx = ul_info->frame;
  slot_t slot_tx = ul_info->slot;
1414
  uint32_t gNB_index = ul_info->gNB_index;
1415

1416
  RA_config_t *ra = &mac->ra;
1417
  if(mac->state > UE_NOT_SYNC && mac->state < UE_CONNECTED) {
1418 1419
    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
1420 1421 1422 1423
  }

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

1426 1427 1428 1429 1430
  // 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
1431 1432
  // 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)
1433 1434
  uint8_t ulsch_input_buffer_array[NFAPI_MAX_NUM_UL_PDU][MAX_ULSCH_PAYLOAD_BYTES];
  int number_of_pdus = 0;
1435

1436 1437 1438 1439 1440 1441 1442 1443
  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) {
1444
      uint32_t TBS_bytes = ulcfg_pdu->pusch_config_pdu.pusch_data.tb_size;
1445 1446 1447 1448 1449 1450
      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);
1451
      ulcfg_pdu->pusch_config_pdu.tx_request_body.fapiTxPdu = NULL;
1452
      if (ra->ra_state == nrRA_WAIT_RAR && !ra->cfra) {
1453
        nr_get_msg3_payload(mac, ulsch_input_buffer, TBS_bytes);
1454 1455 1456
        for (int k = 0; k < TBS_bytes; k++) {
          LOG_D(NR_MAC, "(%i): 0x%x\n", k, ulsch_input_buffer[k]);
        }
1457 1458 1459
        ulcfg_pdu->pusch_config_pdu.tx_request_body.fapiTxPdu = ulsch_input_buffer;
        ulcfg_pdu->pusch_config_pdu.tx_request_body.pdu_length = TBS_bytes;
        number_of_pdus++;
1460 1461
      } else {
        if (ulcfg_pdu->pusch_config_pdu.pusch_data.new_data_indicator
1462
            && (mac->state == UE_CONNECTED || (ra->ra_state == nrRA_WAIT_RAR && ra->cfra))) {
1463
          // Getting IP traffic to be transmitted
1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481
          int tx_power = ulcfg_pdu->pusch_config_pdu.tx_power;
          int P_CMAX = nr_get_Pcmax(mac->p_Max,
                                    mac->nr_band,
                                    mac->frame_type,
                                    mac->frequency_range,
                                    mac->current_UL_BWP->channel_bandwidth,
                                    ulcfg_pdu->pusch_config_pdu.qam_mod_order,
                                    false,
                                    mac->current_UL_BWP->scs,
                                    mac->current_UL_BWP->BWPSize,
                                    ulcfg_pdu->pusch_config_pdu.transform_precoding,
                                    ulcfg_pdu->pusch_config_pdu.rb_size,
                                    ulcfg_pdu->pusch_config_pdu.rb_start);

          nr_ue_get_sdu(mac, cc_id, frame_tx, slot_tx, gNB_index, ulsch_input_buffer, TBS_bytes, tx_power, P_CMAX);
          ulcfg_pdu->pusch_config_pdu.tx_request_body.fapiTxPdu = ulsch_input_buffer;
          ulcfg_pdu->pusch_config_pdu.tx_request_body.pdu_length = TBS_bytes;
          number_of_pdus++;
1482 1483 1484 1485
          // start or restart dataInactivityTimer  if any MAC entity transmits a MAC SDU for DTCH logical channel,
          // or DCCH logical channel
          if (mac->data_inactivity_timer)
            nr_timer_start(mac->data_inactivity_timer);
1486 1487
        }
      }
1488

1489
      if (ra->ra_state == nrRA_WAIT_CONTENTION_RESOLUTION && !ra->cfra) {
1490 1491 1492
        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
1493
        nr_Msg3_transmitted(mac, cc_id, frame_tx, slot_tx, gNB_index);
1494
      }
1495
      if (ra->ra_state == nrRA_WAIT_RAR && !ra->cfra) {
1496
        LOG_A(NR_MAC, "[RAPROC][%d.%d] RA-Msg3 transmitted\n", frame_tx, slot_tx);
1497
        nr_Msg3_transmitted(mac, cc_id, frame_tx, slot_tx, gNB_index);
francescomani's avatar
francescomani committed
1498
      }
1499
    }
1500 1501 1502
    ulcfg_pdu++;
  }
  release_ul_config(ulcfg_pdu, false);
francescomani's avatar
francescomani committed
1503 1504 1505 1506

  if(mac->state >= UE_PERFORMING_RA && mac->state < UE_DETACHING)
    nr_ue_pucch_scheduler(mac, frame_tx, slot_tx);

1507 1508 1509 1510
  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,
1511 1512
                                                  .module_id = mac->ue_id,
                                                  .CC_id = cc_id,
1513 1514
                                                  .phy_data = ul_info->phy_data};
    mac->if_module->scheduled_response(&scheduled_response);
1515 1516
  }

1517
  if(mac->state == UE_CONNECTED)
1518
    nr_update_sr(mac);
1519

1520
  // update Bj for all active lcids before LCP procedure
1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542
  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);
1543
    }
1544
  }
1545 1546
}

1547
static uint8_t nr_locate_BsrIndexByBufferSize(const uint32_t *table, int size, int value)
1548
{
mjoang's avatar
mjoang committed
1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570
  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
    }

1571
    LOG_T(NR_MAC, "[UE] searching BSR index %d for (BSR TABLE %d < value %d)\n",
mjoang's avatar
mjoang committed
1572 1573 1574 1575 1576 1577 1578 1579 1580 1581
          jm, table[jm], value);
  }

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

1582 1583 1584 1585 1586 1587 1588
// 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
1589 1590 1591 1592 1593 1594 1595
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)
1596
{
1597
  int delta = 0;
1598
  const NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
1599

1600
  // Get the numerology to calculate the Tx frame and slot
francescomani's avatar
francescomani committed
1601
  int mu = current_UL_BWP->scs;
1602

1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620
  // 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;
1621 1622
      default:
        AssertFatal(1 == 0, "Invalid numerology %i\n", mu);
1623 1624
    }

1625 1626 1627 1628 1629 1630 1631
    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",
                k2,
                DURATION_RX_TO_TX,
                DURATION_RX_TO_TX,
                DURATION_RX_TO_TX);

1632
    *slot_tx = (current_slot + k2 + delta) % nr_slots_per_frame[mu];
1633
    *frame_tx = (current_frame + (current_slot + k2 + delta) / nr_slots_per_frame[mu]) % MAX_FRAME_NUMBER;
1634 1635

  } else {
1636 1637 1638 1639 1640 1641 1642 1643

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

1644
    if (k2 < 0) { // This can happen when a false DCI is received
1645
      LOG_W(PHY, "%d.%d. Received k2 %ld\n", current_frame, current_slot, k2);
1646 1647 1648 1649 1650
      return -1;
    }

    // Calculate TX slot and frame
    *slot_tx = (current_slot + k2) % nr_slots_per_frame[mu];
1651
    *frame_tx = (current_frame + (current_slot + k2) / nr_slots_per_frame[mu]) % MAX_FRAME_NUMBER;
1652 1653 1654

  }

1655
  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);
1656 1657 1658 1659 1660

  return 0;
}

// Build the list of all the valid RACH occasions in the maximum association pattern period according to the PRACH config
1661 1662
static void build_ro_list(NR_UE_MAC_INST_t *mac)
{
1663 1664 1665 1666
  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;
1667
  bool even_slot_invalid;
1668 1669 1670 1671 1672 1673 1674 1675
  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)
  uint16_t format = 0xffff;
  uint8_t format2 = 0xff;
  int nb_fdm;

1676
  uint8_t config_index;
1677 1678 1679 1680
  int msg1_FDM;

  uint8_t nb_of_frames_per_prach_conf_period;

1681
  NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon;
1682 1683 1684 1685
  NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric;

  config_index = rach_ConfigGeneric->prach_ConfigurationIndex;

1686 1687
  int mu;
  if (setup->msg1_SubcarrierSpacing)
1688
    mu = *setup->msg1_SubcarrierSpacing;
1689
  else
1690
    mu = mac->current_UL_BWP->scs;
1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707

  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

1708
  int unpaired = mac->phy_config.config_req.cell_config.frame_duplex_type;
1709

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

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

1715
  if (mac->frequency_range == FR2) { //FR2
1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745

    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];
1746
    LOG_D(NR_MAC,"N_t_slot %d, N_dur %d\n",N_t_slot,N_dur);
1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758
    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

1759 1760
  const int bwp_id = mac->current_UL_BWP->bwp_id;
  prach_association_pattern_t *prach_assoc_pattern = &mac->prach_assoc_pattern[bwp_id];
1761
  prach_assoc_pattern->nb_of_prach_conf_period_in_max_period = MAX_NB_PRACH_CONF_PERIOD_IN_ASSOCIATION_PATTERN_PERIOD / x;
1762 1763
  nb_of_frames_per_prach_conf_period = x;

1764
  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);
1765 1766 1767 1768 1769 1770

  // 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
  // -------------------------------------
1771 1772 1773 1774 1775
  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];
1776

1777
    LOG_D(NR_MAC,"PRACH Conf Period Idx %d\n", period_idx);
1778 1779 1780

    // For every frames in a PRACH configuration period
    // ------------------------------------------------
1781
    for (int frame_idx = 0; frame_idx < nb_of_frames_per_prach_conf_period; frame_idx++) {
1782
      int frame_rach = (period_idx * nb_of_frames_per_prach_conf_period) + frame_idx;
1783

1784
      LOG_D(NR_MAC,"PRACH Conf Period Frame Idx %d - Frame %d\n", frame_idx, frame_rach);
1785
      // Is it a valid frame for this PRACH configuration index? (n_sfn mod x = y)
1786
      if ((frame_rach % x) == y || (frame_rach % x) == y2) {
1787 1788 1789

        // For every slot in a frame
        // -------------------------
1790
        for (int slot = 0; slot < nr_slots_per_frame[mu]; slot++) {
1791 1792
          // Is it a valid slot?
          map_shift = slot >> slot_shift_for_map; // in PRACH configuration index table slots are numbered wrt 60kHz
1793
          if ((s_map>>map_shift) & 0x01) {
1794 1795 1796
            // Valid slot

            // Additionally, for 30kHz/120kHz, we must check for the n_RA_Slot param also
1797 1798
            if (even_slot_invalid && (slot%2 == 0))
              continue; // no prach in even slots @ 30kHz/120kHz for 1 prach per 60khz slot/subframe
1799 1800 1801 1802

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

1803 1804 1805
            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;
1806 1807
            slot_map->prach_occasion = malloc(N_t_slot * nb_fdm * sizeof(*slot_map->prach_occasion));
            AssertFatal(slot_map->prach_occasion, "no memory available\n");
1808
            for (int n_prach_occ_in_time = 0; n_prach_occ_in_time < N_t_slot; n_prach_occ_in_time++) {
1809
              uint8_t start_symbol = prach_conf_start_symbol + n_prach_occ_in_time * N_dur;
1810
              LOG_D(NR_MAC,"PRACH Occ in time %d\n", n_prach_occ_in_time);
1811

1812
              for (int n_prach_occ_in_freq = 0; n_prach_occ_in_freq < nb_fdm; n_prach_occ_in_freq++) {
1813 1814 1815
                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,
1816
                                            .frame = frame_idx,
1817 1818
                                            .slot = slot,
                                            .format = format};
1819
                prach_assoc_pattern->prach_conf_period_list[period_idx].nb_of_prach_occasion++;
1820

1821 1822 1823 1824 1825 1826 1827 1828
                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",
                      frame_rach,
                      slot,
                      start_symbol,
                      n_prach_occ_in_time,
                      n_prach_occ_in_freq,
                      prach_conf_period_list->nb_of_prach_occasion,
1829 1830
                      slot_map->nb_of_prach_occasion_in_time,
                      slot_map->nb_of_prach_occasion_in_freq);
1831 1832 1833 1834 1835 1836 1837 1838 1839 1840
              } // 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
1841 1842
static void build_ssb_list(NR_UE_MAC_INST_t *mac)
{
1843
  // Create the list of transmitted SSBs
1844 1845
  const int bwp_id = mac->current_UL_BWP->bwp_id;
  ssb_list_info_t *ssb_list = &mac->ssb_list[bwp_id];
1846 1847 1848
  fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
  ssb_list->nb_tx_ssb = 0;

1849
  for (int ssb_index = 0; ssb_index < MAX_NB_SSB; ssb_index++) {
1850 1851 1852
    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) {
1853
      ssb_list->nb_ssb_per_index[ssb_index] = ssb_list->nb_tx_ssb;
1854
      ssb_list->nb_tx_ssb++;
1855
    }
1856 1857
    else
      ssb_list->nb_ssb_per_index[ssb_index] = -1;
1858
  }
1859
  ssb_list->tx_ssb = calloc(ssb_list->nb_tx_ssb, sizeof(*ssb_list->tx_ssb));
1860 1861
}

1862 1863 1864 1865 1866 1867 1868 1869 1870 1871
static int get_ssb_idx_from_list(ssb_list_info_t *ssb_list, int idx)
{
  for (int ssb_index = 0; ssb_index < MAX_NB_SSB; ssb_index++) {
    if (ssb_list->nb_ssb_per_index[ssb_index] == idx)
      return ssb_index;
  }
  AssertFatal(false, "Couldn't find SSB index in SSB list\n");
  return 0;
}

1872
// Map the transmitted SSBs to the ROs and create the association pattern according to the config
1873 1874
static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac)
{
1875 1876
  // Map SSBs to PRACH occasions
  // WIP: Assumption: No PRACH occasion is rejected because of a conflict with SSBs or TDD_UL_DL_ConfigurationCommon schedule
1877
  NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon;
1878 1879
  NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR ssb_perRACH_config = setup->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present;

1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890
  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;
1891

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

1894 1895 1896
  const int bwp_id = mac->current_UL_BWP->bwp_id;
  ssb_list_info_t *ssb_list = &mac->ssb_list[bwp_id];

1897
  // Evaluate the number of PRACH configuration periods required to map all the SSBs and set the association period
1898 1899
  // WIP: Assumption for now is that all the PRACH configuration periods within a maximum association pattern period have the same
  // number of PRACH occasions
1900 1901
  //      (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
1902
  LOG_D(NR_MAC,"Evaluate the number of PRACH configuration periods required to map all the SSBs and set the association period\n");
1903 1904
  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;
1905

1906
  prach_association_pattern_t *prach_assoc_pattern = &mac->prach_assoc_pattern[bwp_id];
1907 1908 1909 1910 1911 1912 1913 1914
  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;
1915 1916

  if (required_nb_of_prach_conf_period == 1) {
1917
    prach_association_period->nb_of_prach_conf_period = 1;
1918 1919
  }
  else if (required_nb_of_prach_conf_period == 2) {
1920
    prach_association_period->nb_of_prach_conf_period = 2;
1921 1922
  }
  else if (required_nb_of_prach_conf_period <= 4) {
1923
    prach_association_period->nb_of_prach_conf_period = 4;
1924 1925
  }
  else if (required_nb_of_prach_conf_period <= 8) {
1926
    prach_association_period->nb_of_prach_conf_period = 8;
1927 1928
  }
  else if (required_nb_of_prach_conf_period <= 16) {
1929
    prach_association_period->nb_of_prach_conf_period = 16;
1930 1931 1932 1933 1934
  }
  else {
    AssertFatal(1 == 0, "Invalid number of PRACH config periods within an association period %d\n", required_nb_of_prach_conf_period);
  }

1935
  prach_assoc_pattern->nb_of_assoc_period = 1; // WIP: only one possible association period
1936 1937
  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;
1938

1939 1940 1941 1942
  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);
1943

1944 1945 1946
  // 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
1947 1948

  // Map all the association periods within the association pattern period
1949
  LOG_D(NR_MAC,"Proceed to the SSB to RO mapping\n");
1950
  // Check if we need to map multiple SSBs per RO or multiple ROs per SSB
1951

1952 1953 1954 1955 1956 1957 1958
  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
1959 1960
      // 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
1961
      int idx = 0;
1962 1963 1964 1965
      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];
1966 1967
        // Build the association period with its association PRACH Configuration indexes
        // Go through all the ROs within the PRACH config period
1968 1969 1970 1971 1972 1973 1974
        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;
1975 1976 1977
                // 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
1978 1979
                for (; idx < ssb_list->nb_tx_ssb; idx++) {
                  ssb_info_t *tx_ssb = ssb_list->tx_ssb + idx;
1980
                  // Map only the transmitted ssb_idx
1981
                  int ssb_idx = get_ssb_idx_from_list(ssb_list, idx);
1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001
                  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) {
2002
                      idx++;
2003 2004
                      break;
                    }
2005
                }
2006
                done = MAX_NB_SSB == idx;
2007 2008 2009 2010 2011 2012 2013
              }
            }
          }
        }
      }
    }
  } else {
2014 2015 2016 2017
    int frame = 0;
    int slot = 0;
    int ro_in_time = 0;
    int ro_in_freq = 0;
2018 2019 2020
    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++) {
2021
      // Go through the list of transmitted SSBs
2022 2023
      for (int idx = 0; idx < ssb_list->nb_tx_ssb; idx++) {
        ssb_info_t *tx_ssb = ssb_list->tx_ssb + idx;
2024
        uint8_t nb_mapped_ro_in_association_period = 0; // Reset the nb of mapped ROs for the new SSB index
2025 2026 2027 2028 2029 2030 2031
        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];
2032 2033
          for (; frame < prach_conf->nb_of_frame; frame++) {
            for (; slot < prach_conf->nb_of_slot; slot++) {
2034
              prach_occasion_slot_t *slot_map = &prach_conf->prach_occasion_slot_map[frame][slot];
2035 2036
              for (; ro_in_time < slot_map->nb_of_prach_occasion_in_time; ro_in_time++) {
                for (; ro_in_freq < slot_map->nb_of_prach_occasion_in_freq; ro_in_freq++) {
2037 2038
                  prach_occasion_info_t *ro_p =
                      slot_map->prach_occasion + ro_in_time * slot_map->nb_of_prach_occasion_in_freq + ro_in_freq;
2039
                  int ssb_idx = get_ssb_idx_from_list(ssb_list, idx);
2040 2041 2042 2043 2044 2045 2046 2047 2048 2049
                  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++;

                  LOG_D(NR_MAC,
2050
                        "Mapped ssb_idx %u to RO slot-symbol %u-%u-%u, %u-%u-%u-%u/%u\n"
2051 2052
                        "Nb mapped ROs for this ssb idx: in the association period only %u / total %u\n",
                        ssb_idx,
2053
                        ro_p->frame,
2054 2055
                        ro_p->slot,
                        ro_p->start_symbol,
2056
                        frame,
2057 2058 2059 2060 2061 2062
                        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);
2063 2064

                  // Exit the loop if this SSB has been mapped to all the required ROs
2065 2066 2067
                  // 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
2068 2069 2070 2071
                  if (nb_mapped_ro_in_association_period == ssb_rach_ratio) {
                    ro_in_freq++;
                    break;
                  }
2072
                }
2073 2074 2075 2076
                if (nb_mapped_ro_in_association_period == ssb_rach_ratio)
                  break;
                else
                  ro_in_freq = 0;
2077
              }
2078 2079 2080 2081
              if (nb_mapped_ro_in_association_period == ssb_rach_ratio)
                break;
              else
                ro_in_time = 0;
2082
            }
2083 2084 2085 2086
            if (nb_mapped_ro_in_association_period == ssb_rach_ratio)
              break;
            else
              slot = 0;
2087
          }
2088 2089 2090 2091
          if (nb_mapped_ro_in_association_period == ssb_rach_ratio)
            break;
          else
            frame = 0;
2092 2093 2094 2095
        }
      }
    }
  }
2096 2097 2098
}

// Returns a RACH occasion if any matches the SSB idx, the frame and the slot
2099
static int get_nr_prach_info_from_ssb_index(prach_association_pattern_t *prach_assoc_pattern,
2100
                                            int ssb_idx,
2101 2102
                                            int frame,
                                            int slot,
francescomani's avatar
francescomani committed
2103 2104 2105
                                            ssb_list_info_t *ssb_list,
                                            prach_occasion_info_t **prach_occasion_info_pp)
{
2106 2107 2108 2109 2110 2111 2112 2113 2114
  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
2115 2116
  int idx_list = ssb_list->nb_ssb_per_index[ssb_idx];
  ssb_info_t *ssb_info_p = &ssb_list->tx_ssb[idx_list];
2117
  LOG_D(NR_MAC, "checking for prach : ssb_info_p->nb_mapped_ro %d\n", ssb_info_p->nb_mapped_ro);
2118 2119 2120 2121 2122 2123 2124 2125 2126
  for (int n_mapped_ro = 0; n_mapped_ro < ssb_info_p->nb_mapped_ro; n_mapped_ro++) {
    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);
2127
    if ((slot == ssb_info_p->mapped_ro[n_mapped_ro]->slot) &&
2128 2129 2130 2131
        (ssb_info_p->mapped_ro[n_mapped_ro]->frame == (frame % prach_assoc_pattern->nb_of_frame))) {
      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];
2132 2133 2134 2135
    }
  }

  // If there is a matching RO slot in the SSB_to_RO map
2136
  if (NULL != prach_occasion_slot_p) {
2137 2138 2139 2140 2141
    // 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;

2142 2143
    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++) {
2144 2145 2146 2147
        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) {
2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162
            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++) {
2163 2164 2165 2166
        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) {
2167
            if (nb_mapped_ssb == random_ssb_nb) {
2168
              *prach_occasion_info_pp = ro_p;
2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183
              return 1;
            }
            else {
              nb_mapped_ssb++;
            }
          }
        }
      }
    }
  }

  return 0;
}

// Build the SSB to RO mapping upon RRC configuration update
2184 2185
void build_ssb_to_ro_map(NR_UE_MAC_INST_t *mac)
{
2186
  // Clear all the lists and maps
2187
  const int bwp_id = mac->current_UL_BWP->bwp_id;
2188
  free_rach_structures(mac, bwp_id);
2189 2190
  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));
2191 2192

  // Build the list of all the valid RACH occasions in the maximum association pattern period according to the PRACH config
2193 2194
  LOG_D(NR_MAC,"Build RO list\n");
  build_ro_list(mac);
2195 2196

  // Build the list of all the valid/transmitted SSBs according to the config
2197 2198
  LOG_D(NR_MAC,"Build SSB list\n");
  build_ssb_list(mac);
2199 2200

  // Map the transmitted SSBs to the ROs and create the association pattern according to the config
2201 2202 2203
  LOG_D(NR_MAC,"Map SSB to RO\n");
  map_ssb_to_ro(mac);
  LOG_D(NR_MAC,"Map SSB to RO done\n");
2204 2205
}

francescomani's avatar
francescomani committed
2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275
static bool schedule_uci_on_pusch(NR_UE_MAC_INST_t *mac, frame_t frame_tx, int slot_tx, const PUCCH_sched_t *pucch)
{
  fapi_nr_ul_config_request_pdu_t *ulcfg_pdu = lockGet_ul_iterator(mac, frame_tx, slot_tx);
  if (!ulcfg_pdu)
    return NULL;

  nfapi_nr_ue_pusch_pdu_t *pusch_pdu = NULL;
  while (ulcfg_pdu->pdu_type != FAPI_NR_END) {
    if (ulcfg_pdu->pdu_type == FAPI_NR_UL_CONFIG_TYPE_PUSCH) {
      int start_pusch = ulcfg_pdu->pusch_config_pdu.start_symbol_index;
      int nsymb_pusch = ulcfg_pdu->pusch_config_pdu.nr_of_symbols;
      int end_pusch = start_pusch + nsymb_pusch;
      NR_PUCCH_Resource_t *pucchres = pucch->pucch_resource;
      int nr_of_symbols = 0;
      int start_symbol_index = 0;
      switch(pucchres->format.present) {
        case NR_PUCCH_Resource__format_PR_format0 :
          nr_of_symbols = pucchres->format.choice.format0->nrofSymbols;
          start_symbol_index = pucchres->format.choice.format0->startingSymbolIndex;
          break;
        case NR_PUCCH_Resource__format_PR_format1 :
          nr_of_symbols = pucchres->format.choice.format1->nrofSymbols;
          start_symbol_index = pucchres->format.choice.format1->startingSymbolIndex;
          break;
        case NR_PUCCH_Resource__format_PR_format2 :
          nr_of_symbols = pucchres->format.choice.format2->nrofSymbols;
          start_symbol_index = pucchres->format.choice.format2->startingSymbolIndex;
          break;
        case NR_PUCCH_Resource__format_PR_format3 :
          nr_of_symbols = pucchres->format.choice.format3->nrofSymbols;
          start_symbol_index = pucchres->format.choice.format3->startingSymbolIndex;
          break;
        case NR_PUCCH_Resource__format_PR_format4 :
          nr_of_symbols = pucchres->format.choice.format4->nrofSymbols;
          start_symbol_index = pucchres->format.choice.format4->startingSymbolIndex;
          break;
        default :
          AssertFatal(false, "Undefined PUCCH format \n");
      }
      int final_symbol = nr_of_symbols + start_symbol_index;
      // PUCCH overlapping in time with PUSCH
      if (start_symbol_index < end_pusch && final_symbol > start_pusch) {
        pusch_pdu = &ulcfg_pdu->pusch_config_pdu;
        break;
      }
    }
    ulcfg_pdu++;
  }

  if (!pusch_pdu) {
    release_ul_config(ulcfg_pdu, false);
    return false;
  }

  // If a UE would transmit on a serving cell a PUSCH without UL-SCH that overlaps with a PUCCH transmission
  // on a serving cell that includes positive SR information, the UE does not transmit the PUSCH.
  if (pusch_pdu && pusch_pdu->ulsch_indicator == 0 && pucch->sr_payload == 1) {
    release_ul_config(ulcfg_pdu, false);
    return false;
  }

  // - UE multiplexes only HARQ-ACK information, if any, from the UCI in the PUSCH transmission
  // and does not transmit the PUCCH if the UE multiplexes aperiodic or semi-persistent CSI reports in the PUSCH

  // - UE multiplexes only HARQ-ACK information and CSI reports, if any, from the UCI in the PUSCH transmission
  // and does not transmit the PUCCH if the UE does not multiplex aperiodic or semi-persistent CSI reports in the PUSCH
  bool mux_done = false;
  if (pucch->n_harq > 0) {
    pusch_pdu->pusch_uci.harq_ack_bit_length = pucch->n_harq;
    pusch_pdu->pusch_uci.harq_payload = pucch->ack_payload;
2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288
    NR_PUSCH_Config_t *pusch_Config = mac->current_UL_BWP->pusch_Config;
    AssertFatal(pusch_Config && pusch_Config->uci_OnPUSCH, "UCI on PUSCH need to be configured\n");
    NR_UCI_OnPUSCH_t *onPusch = pusch_Config->uci_OnPUSCH->choice.setup;
    AssertFatal(onPusch &&
                onPusch->betaOffsets &&
                onPusch->betaOffsets->present == NR_UCI_OnPUSCH__betaOffsets_PR_semiStatic,
                "Only semistatic beta offset is supported\n");
    NR_BetaOffsets_t *beta_offsets = onPusch->betaOffsets->choice.semiStatic;
    pusch_pdu->pusch_uci.beta_offset_harq_ack = pucch->n_harq > 2 ?
                                                       (pucch->n_harq < 12 ? *beta_offsets->betaOffsetACK_Index2 :
                                                       *beta_offsets->betaOffsetACK_Index3) :
                                                       *beta_offsets->betaOffsetACK_Index1;
    pusch_pdu->pusch_uci.alpha_scaling = onPusch->scaling;
francescomani's avatar
francescomani committed
2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301
    mux_done = true;
  }
  if (pusch_pdu->pusch_uci.csi_part1_bit_length == 0 && pusch_pdu->pusch_uci.csi_part2_bit_length == 0) {
    // To support this we would need to shift some bits into CSI part2 -> need to change the logic
    AssertFatal(pucch->n_csi == 0, "Multiplexing periodic CSI on PUSCH not supported\n");
  }

  release_ul_config(ulcfg_pdu, false);
  // only use PUSCH if any mux is done otherwise send PUCCH
  return mux_done;
}

void nr_ue_pucch_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, int slotP)
2302 2303 2304 2305 2306 2307 2308
{
  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;
2309 2310

  // SR
2311 2312
  if (mac->state == UE_CONNECTED && trigger_periodic_scheduling_request(mac, &pucch[0], frameP, slotP)) {
    num_res++;
2313
    // TODO check if the PUCCH resource for the SR transmission occasion overlap with a UL-SCH resource
2314
  }
2315 2316

  // CSI
2317
  int csi_res = 0;
francescomani's avatar
francescomani committed
2318
  if (mac->state == UE_CONNECTED)
2319 2320 2321
    csi_res = nr_get_csi_measurements(mac, frameP, slotP, &pucch[num_res]);
  if (csi_res > 0) {
    num_res += csi_res;
2322 2323
  }

2324 2325 2326 2327
  // ACKNACK
  bool any_harq = get_downlink_ack(mac, frameP, slotP, &pucch[num_res]);
  if (any_harq)
    num_res++;
2328

2329 2330
  if (num_res == 0)
    return;
2331
  // do no transmit pucch if only SR scheduled and it is negative
2332
  if (num_res == 1 && pucch[0].n_sr > 0 && pucch[0].sr_payload == 0)
2333 2334
    return;

2335 2336
  if (num_res > 1)
    multiplex_pucch_resource(mac, pucch, num_res);
francescomani's avatar
francescomani committed
2337

2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349
  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;
francescomani's avatar
francescomani committed
2350 2351 2352 2353 2354

      // checking if we need to schedule pucch[j] on PUSCH
      if (schedule_uci_on_pusch(mac, frameP, slotP, &pucch[j]))
        continue;

2355 2356 2357 2358 2359
      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;
      }
2360
      mac->nr_ue_emul_l1.active_uci_sfn_slot = NFAPI_SFNSLOT2HEX(frameP, slotP);
2361 2362
      int ret = nr_ue_configure_pucch(mac,
                                      slotP,
2363
                                      frameP,
2364 2365 2366 2367 2368 2369 2370
                                      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);
    }
2371 2372 2373
  }
}

2374 2375 2376
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
2377
    return;
francescomani's avatar
francescomani committed
2378

2379
  NR_CSI_MeasConfig_t *csi_measconfig = mac->sc_info.csi_MeasConfig;
2380

francescomani's avatar
francescomani committed
2381 2382
  if (csi_measconfig->csi_IM_ResourceToAddModList == NULL)
    return;
francescomani's avatar
francescomani committed
2383

2384
  fapi_nr_dl_config_request_t *dl_config = get_dl_config_request(mac, slot);
francescomani's avatar
francescomani committed
2385 2386
  NR_CSI_IM_Resource_t *imcsi;
  int period, offset;
2387

2388
  NR_UE_DL_BWP_t *current_DL_BWP = mac->current_DL_BWP;
francescomani's avatar
francescomani committed
2389 2390 2391
  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
2392 2393 2394 2395 2396 2397 2398

  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;
2399 2400
    csiim_config_pdu->bwp_size = bwp_size;
    csiim_config_pdu->bwp_start = bwp_start;
francescomani's avatar
francescomani committed
2401 2402 2403 2404 2405 2406
    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:
2407 2408 2409 2410
        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
2411
        }
francescomani's avatar
francescomani committed
2412 2413
        break;
      case NR_CSI_IM_Resource__csi_IM_ResourceElementPattern_PR_pattern1:
2414 2415
        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
2416 2417 2418 2419
          csiim_config_pdu->l_csiim[i] = imcsi->csi_IM_ResourceElementPattern->choice.pattern1->symbolLocation_p1;
        }
        break;
      default:
2420
        AssertFatal(1 == 0, "Invalid CSI-IM pattern\n");
francescomani's avatar
francescomani committed
2421
    }
francescomani's avatar
francescomani committed
2422
    dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_CSI_IM;
2423
    dl_config->number_pdus += 1;
francescomani's avatar
francescomani committed
2424
  }
2425 2426
}

2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447
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];
2448
        if (*res_id != csi_res->nzp_CSI_ResourceSetId)
2449 2450
          continue;
        for (int k = 0; k < csi_res->nzp_CSI_RS_Resources.list.count; k++) {
2451
          AssertFatal(csi_res->nzp_CSI_RS_Resources.list.array[k], "NZP_CSI_RS_ResourceId shoulan't be NULL\n");
2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470
          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
}

2471
uint8_t set_csirs_measurement_bitmap(NR_CSI_MeasConfig_t *csi_measconfig, NR_CSI_ResourceConfigId_t csi_res_id)
2472 2473 2474 2475 2476
{
  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++) {
2477
    NR_CSI_ReportConfig_t *report_config = csi_measconfig->csi_ReportConfigToAddModList->list.array[i];
2478 2479 2480 2481
    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) {
2482
      case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI:
2483 2484
        meas_bitmap += (1 << 1) + (1 << 3) + (1 << 4);
        break;
2485
      case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1:
2486 2487
        meas_bitmap += (1 << 1) + (1 << 5);
        break;
2488
      case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1_CQI:
2489 2490
        meas_bitmap += (1 << 1) + (1 << 4) + (1 << 5);
        break;
2491
      case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI:
2492 2493
        meas_bitmap += (1 << 1) + (1 << 4);
        break;
2494
      case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP:
2495 2496
        meas_bitmap += 1;
        break;
2497
      case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI:
2498 2499
        meas_bitmap += (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4);
        break;
2500 2501
      default:
        AssertFatal(false, "Unexpected measurement report type %d\n", report_config->reportQuantity.present);
2502 2503 2504 2505 2506 2507
    }
  }
  AssertFatal(meas_bitmap > 0, "Expected to have at least 1 measurement configured for CSI-RS\n");
  return meas_bitmap;
}

2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614
void configure_csi_resource_mapping(fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu,
                                    NR_CSI_RS_ResourceMapping_t  *resourceMapping,
                                    uint32_t bwp_size,
                                    uint32_t bwp_start)
{
  // 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);

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

  switch(resourceMapping->frequencyDomainAllocation.present){
    case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row1:
      csirs_config_pdu->row = 1;
      csirs_config_pdu->freq_domain = ((resourceMapping->frequencyDomainAllocation.choice.row1.buf[0]) >> 4) & 0x0f;
      break;
    case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row2:
      csirs_config_pdu->row = 2;
      csirs_config_pdu->freq_domain = (((resourceMapping->frequencyDomainAllocation.choice.row2.buf[1] >> 4) & 0x0f)
                                       | ((resourceMapping->frequencyDomainAllocation.choice.row2.buf[0] << 4) & 0xff0));
      break;
    case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row4:
      csirs_config_pdu->row = 4;
      csirs_config_pdu->freq_domain = ((resourceMapping->frequencyDomainAllocation.choice.row4.buf[0]) >> 5) & 0x07;
      break;
    case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_other:
      csirs_config_pdu->freq_domain = ((resourceMapping->frequencyDomainAllocation.choice.other.buf[0]) >> 2) & 0x3f;
      // determining the row of table 7.4.1.5.3-1 in 38.211
      switch (resourceMapping->nrofPorts) {
        case NR_CSI_RS_ResourceMapping__nrofPorts_p1:
          AssertFatal(1 == 0, "Resource with 1 CSI port shouldn't be within other rows\n");
          break;
        case NR_CSI_RS_ResourceMapping__nrofPorts_p2:
          csirs_config_pdu->row = 3;
          break;
        case NR_CSI_RS_ResourceMapping__nrofPorts_p4:
          csirs_config_pdu->row = 5;
          break;
        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;
          else {
            int num_k = 0;
            for (int k = 0; k < 6; k++)
              num_k += (((csirs_config_pdu->freq_domain) >> k) & 0x01);
            if (num_k == 4)
              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;
          else {
            if (resourceMapping->cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm8_FD2_TD4)
              csirs_config_pdu->row = 15;
            else
              csirs_config_pdu->row = 13;
          }
          break;
        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;
          else {
            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;
        default:
          AssertFatal(false, "Invalid number of ports in CSI-RS resource\n");
      }
      break;
    default:
      AssertFatal(false, "Invalid freqency domain allocation in CSI-RS resource\n");
  }
}

2615 2616 2617
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
2618
    return;
2619

2620
  NR_CSI_MeasConfig_t *csi_measconfig = mac->sc_info.csi_MeasConfig;
2621

francescomani's avatar
francescomani committed
2622 2623
  if (csi_measconfig->nzp_CSI_RS_ResourceToAddModList == NULL)
    return;
2624

2625
  fapi_nr_dl_config_request_t *dl_config = get_dl_config_request(mac, slot);
2626
  NR_UE_DL_BWP_t *current_DL_BWP = mac->current_DL_BWP;
francescomani's avatar
francescomani committed
2627
  NR_BWP_Id_t dl_bwp_id = current_DL_BWP->bwp_id;
2628

francescomani's avatar
francescomani committed
2629 2630 2631
  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
2632 2633

  for (int id = 0; id < csi_measconfig->nzp_CSI_RS_ResourceToAddModList->list.count; id++){
2634 2635 2636 2637
    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)
2638
      continue;
2639
    NR_CSI_ResourceConfigId_t csi_res_id = find_CSI_resourceconfig(csi_measconfig, dl_bwp_id, nzpcsi->nzp_CSI_RS_ResourceId);
2640 2641
    // do not schedule reseption of this CSI-RS if not associated with current BWP
    if(csi_res_id < 0)
francescomani's avatar
francescomani committed
2642
      continue;
2643
    LOG_D(MAC,"Scheduling reception of CSI-RS in frame %d slot %d\n", frame, slot);
francescomani's avatar
francescomani committed
2644
    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;
2645
    csirs_config_pdu->measurement_bitmap = set_csirs_measurement_bitmap(csi_measconfig, csi_res_id);
francescomani's avatar
francescomani committed
2646
    csirs_config_pdu->subcarrier_spacing = mu;
francescomani's avatar
francescomani committed
2647
    csirs_config_pdu->cyclic_prefix = current_DL_BWP->cyclicprefix ? *current_DL_BWP->cyclicprefix : 0;
2648

francescomani's avatar
francescomani committed
2649
    csirs_config_pdu->csi_type = 1; // NZP-CSI-RS
2650

francescomani's avatar
francescomani committed
2651
    csirs_config_pdu->scramb_id = nzpcsi->scramblingID;
2652 2653 2654 2655 2656
    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
2657 2658 2659

    configure_csi_resource_mapping(csirs_config_pdu, &nzpcsi->resourceMapping, bwp_size, bwp_start);

francescomani's avatar
francescomani committed
2660
    dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_CSI_RS;
2661
    dl_config->number_pdus += 1;
2662 2663 2664
  }
}

2665 2666 2667 2668
// 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
2669
static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, sub_frame_t slotP)
laurent's avatar
laurent committed
2670
{
2671
  RA_config_t *ra = &mac->ra;
2672
  ra->RA_offset = 2; // to compensate the rx frame offset at the gNB
2673
  if (ra->ra_state != nrRA_GENERATE_PREAMBLE)
2674 2675
    return;

2676 2677 2678
  fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
  fapi_nr_prach_config_t *prach_config = &cfg->prach_config;

2679
  NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon;
2680
  NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric;
2681
  const int bwp_id = mac->current_UL_BWP->bwp_id;
2682
  NR_TDD_UL_DL_ConfigCommon_t *tdd_config = mac->tdd_UL_DL_ConfigurationCommon;
2683

2684
  if (is_nr_UL_slot(tdd_config, slotP, mac->frame_type)) {
2685 2686 2687

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

    // Get any valid PRACH occasion in the current slot for the selected SSB index
2691
    prach_occasion_info_t *prach_occasion_info_p;
2692
    int is_nr_prach_slot = get_nr_prach_info_from_ssb_index(&mac->prach_assoc_pattern[bwp_id],
2693
                                                            selected_gnb_ssb_idx,
francescomani's avatar
francescomani committed
2694 2695
                                                            (int)frameP,
                                                            (int)slotP,
2696
                                                            &mac->ssb_list[bwp_id],
francescomani's avatar
francescomani committed
2697
                                                            &prach_occasion_info_p);
2698

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

2702 2703
      nr_get_RA_window(mac);

2704 2705 2706
      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
2707

2708 2709 2710 2711 2712
      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;
      }
2713
      uint16_t ncs = get_NCS(rach_ConfigGeneric->zeroCorrelationZoneConfig, format0, setup->restrictedSetConfig);
2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730
      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);
2731 2732

      // Search which SSB is mapped in the RO (among all the SSBs mapped to this RO)
2733 2734 2735
      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;
2736
          break;
2737
        }
2738
      }
2739
      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);
2740 2741

      if (format1 != 0xff) {
2742
        switch (format0) { // dual PRACH format
2743
          case 0xa1:
2744
            pdu->prach_config_pdu.prach_format = 11;
2745 2746
            break;
          case 0xa2:
2747
            pdu->prach_config_pdu.prach_format = 12;
2748 2749
            break;
          case 0xa3:
2750
            pdu->prach_config_pdu.prach_format = 13;
2751
            break;
2752 2753
          default:
            AssertFatal(1 == 0, "Only formats A1/B1 A2/B2 A3/B3 are valid for dual format");
2754 2755
        }
      } else {
2756
        switch (format0) { // single PRACH format
2757
          case 0:
2758
            pdu->prach_config_pdu.prach_format = 0;
2759 2760
            break;
          case 1:
2761
            pdu->prach_config_pdu.prach_format = 1;
2762 2763
            break;
          case 2:
2764
            pdu->prach_config_pdu.prach_format = 2;
2765 2766
            break;
          case 3:
2767
            pdu->prach_config_pdu.prach_format = 3;
2768 2769
            break;
          case 0xa1:
2770
            pdu->prach_config_pdu.prach_format = 4;
2771 2772
            break;
          case 0xa2:
2773
            pdu->prach_config_pdu.prach_format = 5;
2774 2775
            break;
          case 0xa3:
2776
            pdu->prach_config_pdu.prach_format = 6;
2777 2778
            break;
          case 0xb1:
2779
            pdu->prach_config_pdu.prach_format = 7;
2780 2781
            break;
          case 0xb4:
2782
            pdu->prach_config_pdu.prach_format = 8;
2783 2784
            break;
          case 0xc0:
2785
            pdu->prach_config_pdu.prach_format = 9;
2786 2787
            break;
          case 0xc2:
2788
            pdu->prach_config_pdu.prach_format = 10;
2789 2790 2791 2792 2793
            break;
          default:
            AssertFatal(1 == 0, "Invalid PRACH format");
        }
      } // if format1
2794

2795
      nr_get_prach_resources(mac, 0, 0, &ra->prach_resources, ra->rach_ConfigDedicated);
2796
      pdu->prach_config_pdu.ra_PreambleIndex = ra->ra_PreambleIndex;
2797
      pdu->prach_config_pdu.prach_tx_power = get_prach_tx_power(mac);
2798 2799 2800 2801
      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);
2802 2803
      release_ul_config(pdu, false);
      nr_scheduled_response_t scheduled_response = {.ul_config = mac->ul_config_request + slotP,
2804
                                                    .mac = mac,
2805
                                                    .module_id = mac->ue_id,
2806
                                                    .CC_id = 0 /*TBR fix*/};
cig's avatar
cig committed
2807 2808
      if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL)
        mac->if_module->scheduled_response(&scheduled_response);
2809

2810
      nr_Msg1_transmitted(mac);
2811 2812 2813 2814
    } // is_nr_prach_slot
  } // if is_nr_UL_slot
}

2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825
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;
2826
  NR_SINGLE_ENTRY_PHR_MAC_CE* phr;
2827 2828 2829 2830
  //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
2831

2832
/*
2833 2834 2835 2836 2837 2838 2839 2840 2841
  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
2842
*/
2843 2844 2845 2846 2847 2848
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,
2849
                                    uint32_t buflen,
2850 2851
                                    int16_t tx_power,
                                    int16_t P_CMAX,
2852
                                    NR_UE_MAC_CE_INFO *mac_ce_p)
2853
{
2854
  int num_lcg_id_with_data = 0;
cig's avatar
cig committed
2855
  // Preparing the MAC CEs sub-PDUs and get the total size
2856 2857
  mac_ce_p->bsr_header_len = 0;
  int lcg_id = 0;
2858
  while (lcg_id != NR_INVALID_LCGID) {
2859
    if (mac->scheduling_info.lcg_sched_info[lcg_id].BSR_bytes) {
mjoang's avatar
mjoang committed
2860 2861 2862 2863 2864
      num_lcg_id_with_data++;
    }
    lcg_id++;
  }

2865 2866 2867 2868 2869
  // 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
2870
                "Inconsistent BSR Trigger=%d !\n",
2871
                mac->scheduling_info.BSR_reporting_active);
mjoang's avatar
mjoang committed
2872

2873 2874
    // 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
2875
    if (num_lcg_id_with_data <= 1) {
2876
      if (buflen >= (sizeof(NR_BSR_SHORT) + sizeof(NR_MAC_SUBHEADER_FIXED) + 1)) {
2877 2878
        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
2879 2880
      }
    } else {
2881
      if (buflen >= (num_lcg_id_with_data + 1 + sizeof(NR_MAC_SUBHEADER_SHORT) + 1)) {
2882 2883
        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
2884 2885 2886 2887
      }
    }
  }
  mac_ce_p->bsr_len = mac_ce_p->bsr_ce_len + mac_ce_p->bsr_header_len;
2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903


  nr_phr_info_t *phr_info = &mac->scheduling_info.phr_info;
  mac_ce_p->phr_header_len = 0;
  mac_ce_p->phr_ce_len = 0;
  if (phr_info->is_configured && phr_info->phr_reporting > 0) {
    if (buflen >= (mac_ce_p->bsr_len +  sizeof(NR_MAC_SUBHEADER_FIXED) + sizeof(NR_SINGLE_ENTRY_PHR_MAC_CE))) {
      if (mac->scheduling_info.phr_info.phr_reporting) {
        mac_ce_p->phr_header_len = sizeof(NR_MAC_SUBHEADER_FIXED);
        mac_ce_p->phr_ce_len = sizeof(NR_SINGLE_ENTRY_PHR_MAC_CE);
        nr_ue_fill_phr(mac, mac_ce_p->phr, P_CMAX, tx_power, frameP, subframe);
      }
    }
  }
  mac_ce_p->phr_len = mac_ce_p->phr_header_len + mac_ce_p->phr_ce_len;

2904 2905 2906 2907
  return (mac_ce_p->bsr_len + mac_ce_p->phr_len);
}

/*
2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922
  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
2923
*/
2924
static void nr_ue_get_sdu_mac_ce_post(NR_UE_MAC_INST_t *mac,
2925 2926
                                      frame_t frame,
                                      slot_t slot,
2927
                                      uint8_t *ulsch_buffer,
2928
                                      uint32_t buflen,
2929
                                      NR_UE_MAC_CE_INFO *mac_ce_p)
2930
{
2931
  // Compute BSR Values and update Nb LCGID with data after multiplexing
2932
  uint32_t padding_len = 0;
2933 2934
  int num_lcg_id_with_data = 0;
  int lcg_id_bsr_trunc = 0;
2935 2936
  NR_UE_SCHEDULING_INFO *sched_info = &mac->scheduling_info;
  for (int lcg_id = 0; lcg_id < NR_MAX_NUM_LCGID; lcg_id++) {
2937
    if (mac_ce_p->bsr_ce_len == sizeof(NR_BSR_SHORT)) {
2938
      sched_info->lcg_sched_info[lcg_id].BSR =
2939 2940
          nr_locate_BsrIndexByBufferSize(NR_SHORT_BSR_TABLE,
                                         NR_SHORT_BSR_TABLE_SIZE,
2941
                                         sched_info->lcg_sched_info[lcg_id].BSR_bytes);
2942
    } else {
2943
      sched_info->lcg_sched_info[lcg_id].BSR =
2944 2945
          nr_locate_BsrIndexByBufferSize(NR_LONG_BSR_TABLE,
                                         NR_LONG_BSR_TABLE_SIZE,
2946
                                         sched_info->lcg_sched_info[lcg_id].BSR_bytes);
2947
    }
2948
    if (sched_info->lcg_sched_info[lcg_id].BSR_bytes) {
2949 2950 2951 2952 2953 2954 2955 2956 2957
      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:
2958 2959 2960 2961
     -  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;
2962 2963
     -  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.
2964
  */
2965 2966 2967 2968 2969 2970
  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 */
2971
    if (padding_len >= (num_lcg_id_with_data + 1 + sizeof(NR_MAC_SUBHEADER_SHORT))) {
2972 2973 2974
      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
2975
      sched_info->BSR_reporting_active |= NR_BSR_TRIGGER_PADDING;
2976 2977 2978 2979 2980 2981
    } 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
2982
        // Get LCGID of highest priority LCID with data (todo)
2983
        for (int lcid = 1; lcid <= NR_MAX_NUM_LCID; lcid++) {
2984
          NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid);
2985 2986
          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;
2987 2988 2989
          }
        }
      } else {
2990
        // Report SHORT BSR, clear bsr_t
2991
        mac_ce_p->bsr_t = NULL;
mjoang's avatar
mjoang committed
2992
      }
2993 2994

      // Trigger BSR Padding
2995
      sched_info->BSR_reporting_active |= NR_BSR_TRIGGER_PADDING;
mjoang's avatar
mjoang committed
2996
    }
2997 2998 2999 3000

    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
3001 3002
  }

3003 3004 3005 3006 3007 3008 3009 3010
  //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;
3011 3012 3013 3014 3015 3016 3017 3018
    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;
3019 3020 3021
    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",
3022
          mac->ue_id,
3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033
          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);
3034 3035 3036
  } else if (mac_ce_p->bsr_header_len == sizeof(NR_MAC_SUBHEADER_FIXED)) {
    mac_ce_p->bsr_l = NULL;

3037
    if ((mac_ce_p->bsr_t != NULL) && (sched_info->BSR_reporting_active & NR_BSR_TRIGGER_PADDING)) {
3038 3039 3040
      //Truncated BSR
      mac_ce_p->bsr_s = NULL;
      mac_ce_p->bsr_t->LcgID = lcg_id_bsr_trunc;
3041
      mac_ce_p->bsr_t->Buffer_size = sched_info->lcg_sched_info[lcg_id_bsr_trunc].BSR;
3042 3043
      LOG_D(NR_MAC,
            "[UE %d] Frame %d subframe %d BSR Trig=%d report TRUNCATED BSR with level %d for LCGID %d\n",
3044
            mac->ue_id,
3045 3046 3047 3048
            frame,
            slot,
            sched_info->BSR_reporting_active,
            sched_info->lcg_sched_info[lcg_id_bsr_trunc].BSR,
3049
            lcg_id_bsr_trunc);
3050 3051 3052
    } else {
      mac_ce_p->bsr_t = NULL;
      mac_ce_p->bsr_s->LcgID = lcg_id_bsr_trunc;
3053
      mac_ce_p->bsr_s->Buffer_size = sched_info->lcg_sched_info[lcg_id_bsr_trunc].BSR;
3054 3055
      LOG_D(NR_MAC,
            "[UE %d] Frame %d subframe %d BSR Trig=%d report SHORT BSR with level %d for LCGID %d\n",
3056
            mac->ue_id,
3057 3058 3059 3060
            frame,
            slot,
            sched_info->BSR_reporting_active,
            sched_info->lcg_sched_info[lcg_id_bsr_trunc].BSR,
3061
            lcg_id_bsr_trunc);
3062 3063 3064 3065 3066
    }
  }

  /* Actions when a BSR is sent */
  if (mac_ce_p->bsr_ce_len) {
3067
    LOG_D(NR_MAC,
3068
          "[UE %d] MAC BSR Sent! ce %d, hdr %d buff_len %d triggering LCID %ld\n",
3069
          mac->ue_id,
3070 3071
          mac_ce_p->bsr_ce_len,
          mac_ce_p->bsr_header_len,
3072 3073
          buflen,
          sched_info->regularBSR_trigger_lcid);
3074
    // Reset ReTx BSR Timer
3075
    nr_timer_start(&sched_info->retxBSR_Timer);
3076
    // Reset Periodic Timer except when BSR is truncated
3077
    if (mac_ce_p->bsr_t == NULL) {
3078
      nr_timer_start(&sched_info->periodicBSR_Timer);
3079
      LOG_D(NR_MAC, "[UE %d] MAC Periodic BSR Timer Reset\n", mac->ue_id);
3080 3081
    }

3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092
    if (sched_info->regularBSR_trigger_lcid > 0) {
      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 (lc_info->sr_id >= 0 && lc_info->sr_id < NR_MAX_SR_ID) {
        LOG_D(NR_MAC, "[UE %d][SR] Gave SDU to PHY, clearing scheduling request with ID %d\n", mac->ue_id, lc_info->sr_id);
        nr_sr_info_t *sr = &sched_info->sr_info[lc_info->sr_id];
        sr->pending = false;
        sr->counter = 0;
        nr_timer_stop(&sr->prohibitTimer);
      }
    }
3093
    // Reset BSR Trigger flags
3094
    sched_info->BSR_reporting_active = NR_BSR_TRIGGER_NONE;
3095
    sched_info->regularBSR_trigger_lcid = 0;
3096 3097
  }
}
cig's avatar
cig committed
3098

3099
uint32_t get_count_lcids_same_priority(uint8_t start, uint8_t total_active_lcids, nr_lcordered_info_t *lcid_ordered_array)
3100 3101 3102
{
  // count number of logical channels with same priority as curr_lcid
  uint8_t same_priority_count = 0;
3103
  uint8_t curr_lcid = lcid_ordered_array[start].lcid;
3104
  for (uint8_t index = start; index < total_active_lcids; index++) {
3105
    if (lcid_ordered_array[start].priority == lcid_ordered_array[index].priority) {
3106 3107 3108
      same_priority_count++;
    }
  }
Sriharsha Korada's avatar
Sriharsha Korada committed
3109
  LOG_D(NR_MAC, "Number of lcids with same priority as that of lcid %d is %d\n", curr_lcid, same_priority_count);
3110 3111 3112 3113 3114 3115
  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,
3116 3117
                            uint32_t buflen_remain_ep,
                            int32_t buflen_remain,
3118 3119 3120 3121 3122
                            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*/
3123 3124
  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);
3125
  uint32_t pbr = lc_info->pbr;
3126 3127
  NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lc_num);
  int32_t lcid_remain_buffer = sched_info->LCID_buffer_remain;
3128 3129 3130 3131 3132
  *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
3133
    uint32_t pdu_remain = (same_priority_count > 1) ? buflen_remain_ep : buflen_remain;
3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146
    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
3147
  LOG_D(NR_MAC, "number of bytes requested for lcid %d is %li\n", lc_num, num_bytes_requested);
3148 3149 3150 3151

  return num_bytes_requested;
}

3152
bool get_dataavailability_buffers(uint8_t total_active_lcids, nr_lcordered_info_t *lcid_ordered_array, bool *data_status_lcbuffers)
3153 3154 3155
{
  // check whether there is any data in the rlc buffer corresponding to active lcs
  for (uint8_t id = 0; id < total_active_lcids; id++) {
3156
    int lcid = lcid_ordered_array[id].lcid;
3157
    if (data_status_lcbuffers[lcid_buffer_index(lcid)]) {
3158 3159 3160 3161 3162 3163
      return true;
    }
  }
  return false;
}

3164
static void select_logical_channels(NR_UE_MAC_INST_t *mac, int *num_active_lcids, nr_lcordered_info_t *active_lcids)
3165 3166 3167 3168 3169
{
  // (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
3170 3171
  for (int i = 0; i < mac->lc_ordered_list.count; i++) {
    int lcid = mac->lc_ordered_list.array[i]->lcid;
3172 3173
    NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid);
    if (sched_info->Bj > 0) {
3174
      active_lcids[*num_active_lcids] = *mac->lc_ordered_list.array[i];
3175
      (*num_active_lcids)++;
Sriharsha Korada's avatar
Sriharsha Korada committed
3176
      LOG_D(NR_MAC, "The available lcid is %d with total active channels count = %d\n", lcid, *num_active_lcids);
3177 3178 3179 3180
    }
  }
}

3181
static bool fill_mac_sdu(NR_UE_MAC_INST_t *mac,
3182 3183
                         frame_t frame,
                         slot_t slot,
Sriharsha Korada's avatar
Sriharsha Korada committed
3184
                         uint8_t gNB_index,
3185 3186
                         uint32_t buflen,
                         int32_t *buflen_remain,
Sriharsha Korada's avatar
Sriharsha Korada committed
3187 3188 3189 3190
                         int lcid,
                         uint8_t **pdu,
                         uint32_t *counter,
                         uint8_t count_same_priority_lcids,
3191
                         uint32_t buflen_ep,
Sriharsha Korada's avatar
Sriharsha Korada committed
3192 3193 3194 3195 3196 3197 3198 3199 3200
                         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 */
3201 3202
  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
3203
  LOG_D(NR_MAC,
3204 3205
        "[UE %d] [%d.%d] lcp round = %d, remaining mac pdu length = %d, lcid buffer remaining = %d, lcid = %d \n",
        mac->ue_id,
3206 3207
        frame,
        slot,
Sriharsha Korada's avatar
Sriharsha Korada committed
3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222
        *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);

3223
  uint16_t sdu_length = mac_rlc_data_req(mac->ue_id,
3224
                                         mac->ue_id,
Sriharsha Korada's avatar
Sriharsha Korada committed
3225
                                         gNB_index,
3226
                                         frame,
Sriharsha Korada's avatar
Sriharsha Korada committed
3227 3228 3229 3230 3231 3232 3233 3234 3235
                                         ENB_FLAG_NO,
                                         MBMS_FLAG_NO,
                                         lcid,
                                         bytes_requested,
                                         (char *)(*pdu),
                                         0,
                                         0);

  AssertFatal(bytes_requested >= sdu_length,
3236
              "LCID = 0x%02x RLC has segmented %d bytes but MAC has max %li remaining bytes\n",
Sriharsha Korada's avatar
Sriharsha Korada committed
3237 3238 3239 3240 3241 3242 3243 3244
              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
3245
  sched_info->Bj -= sdu_length; // TODO avoid Bj to go below 0
Sriharsha Korada's avatar
Sriharsha Korada committed
3246 3247 3248 3249 3250
  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,
3251
        sched_info->Bj);
Sriharsha Korada's avatar
Sriharsha Korada committed
3252

3253
  int lc_idx = lcid_buffer_index(lcid);
Sriharsha Korada's avatar
Sriharsha Korada committed
3254 3255
  if (sdu_length > 0) {
    LOG_D(NR_MAC,
3256
          "[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
3257
          "0x%02x (buflen (TBS) %d bytes)\n",
3258
          mac->ue_id,
3259 3260
          frame,
          slot,
Sriharsha Korada's avatar
Sriharsha Korada committed
3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271
          (*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
3272
    LOG_I(NR_MAC, "dumping MAC sub-header with length %d: \n", sh_size);
Sriharsha Korada's avatar
Sriharsha Korada committed
3273
    log_dump(NR_MAC, header, sh_size, LOG_DUMP_CHAR, "\n");
3274
    LOG_I(NR_MAC, "dumping MAC SDU with length %d \n", sdu_length);
Sriharsha Korada's avatar
Sriharsha Korada committed
3275 3276 3277 3278 3279 3280 3281 3282 3283 3284
    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;
3285
    lcids_data_status[lc_idx] = false;
Sriharsha Korada's avatar
Sriharsha Korada committed
3286
    (*num_lcids_same_priority)--;
3287
    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
3288 3289 3290 3291 3292 3293
    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
3294 3295 3296
  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
3297
  LOG_D(NR_MAC,
3298
        "[UE %d] Update BSR [%d.%d] BSR_bytes for LCG%ld = %d\n",
3299
        mac->ue_id,
3300 3301
        frame,
        slot,
3302 3303 3304 3305
        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
3306 3307

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

3310
  if ((*counter == 0 && lcids_bytes_tot[lc_idx] >= target)
Sriharsha Korada's avatar
Sriharsha Korada committed
3311
      || (count_same_priority_lcids > 1
3312
          && lcids_bytes_tot[lc_idx] >= buflen_ep)) { // only prioritized bit rate should be taken from logical channel in
3313
    // the first lcp run except when infinity
Sriharsha Korada's avatar
Sriharsha Korada committed
3314
    LOG_D(NR_MAC,
3315
          "Total number bytes read from rlc buffer for lcid %d are %d\n",
Sriharsha Korada's avatar
Sriharsha Korada committed
3316
          lcid,
3317
          lcids_bytes_tot[lc_idx]);
Sriharsha Korada's avatar
Sriharsha Korada committed
3318 3319 3320 3321 3322 3323
    (*num_lcids_same_priority)--;
    return 0;
  }
  return 1;
}

cig's avatar
cig committed
3324 3325
/**
 * Function:      to fetch data to be transmitted from RLC, place it in the ULSCH PDU buffer
3326 3327
 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
3328
 * @module_idP    Module ID
3329
 * @CC_id         Component Carrier index
3330 3331
 * @frame         current UL frame
 * @slot          current UL slot
cig's avatar
cig committed
3332 3333 3334 3335
 * @gNB_index     gNB index
 * @ulsch_buffer  Pointer to ULSCH PDU
 * @buflen        TBS
 */
3336
uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac,
3337
                      int CC_id,
3338 3339
                      frame_t frame,
                      slot_t slot,
cig's avatar
cig committed
3340 3341
                      uint8_t gNB_index,
                      uint8_t *ulsch_buffer,
3342 3343 3344
                      uint32_t buflen,
                      int16_t tx_power,
                      int16_t P_CMAX)
3345
{
3346 3347
  NR_UE_MAC_CE_INFO mac_ce_info;
  NR_UE_MAC_CE_INFO *mac_ce_p=&mac_ce_info;
3348
  int32_t buflen_remain = 0;
3349 3350 3351 3352 3353 3354 3355
  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
3356
  uint16_t num_sdus = 0;
3357 3358 3359 3360 3361 3362
  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;
3363 3364 3365

  NR_SINGLE_ENTRY_PHR_MAC_CE phr;
  mac_ce_p->phr = &phr;
3366

3367
  //int highest_priority = 16;
cig's avatar
cig committed
3368
  const uint8_t sh_size = sizeof(NR_MAC_SUBHEADER_LONG);
cig's avatar
cig committed
3369 3370 3371 3372

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

3373 3374 3375
  // 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);
3376

3377 3378
  // 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;
3379
  // bj and prioritized bit rate but just consider priority
3380
  uint32_t buflen_ep = 0; // this variable holds the length in bytes in mac pdu when multiple equal priority channels are present
3381
  // because as per standard(TS38.321), all equal priority channels should be served equally
cig's avatar
cig committed
3382

3383
  // nr_ue_get_sdu_mac_ce_pre updates all mac_ce related header field related to length
3384
  mac_ce_p->tot_mac_ce_len = nr_ue_get_sdu_mac_ce_pre(mac, CC_id, frame, slot, gNB_index, ulsch_buffer, buflen, tx_power, P_CMAX, mac_ce_p);
3385
  mac_ce_p->total_mac_pdu_header_len = mac_ce_p->tot_mac_ce_len;
cig's avatar
cig committed
3386

3387
  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
3388

3389
  // selection of logical channels
3390 3391 3392
  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];
3393 3394 3395 3396 3397
  select_logical_channels(mac, &avail_lcids_count, lcids_bj_pos);

  // multiplex in the order of highest priority
  do {
    /*
3398
      go until there is space availabile in the MAC PDU and there is data available in RLC buffers of active logical channels
3399 3400 3401 3402 3403 3404 3405 3406 3407
    */
    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++) {
      /*
3408 3409 3410 3411
  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
3412
      */
3413
      int lcid = lcids_bj_pos[id].lcid;
3414 3415
      NR_LC_SCHEDULING_INFO *lc_sched_info = get_scheduling_info_from_lcid(mac, lcid);
      int idx = lcid_buffer_index(lcid);
3416 3417
      // 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
3418 3419
      if (!lc_sched_info->LCID_buffer_with_data || !lcids_data_status[idx]) {
        lcids_data_status[idx] = false;
3420 3421
        continue;
      }
cig's avatar
cig committed
3422

3423 3424 3425
      // count number of lc with same priority as lcid
      if (!num_lcids_same_priority) {
        num_lcids_same_priority = count_same_priority_lcids =
3426
            get_count_lcids_same_priority(id, avail_lcids_count, lcids_bj_pos);
3427
      }
cig's avatar
cig committed
3428

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

francescomani's avatar
francescomani committed
3431
      LOG_D(NR_MAC,
3432
            "[UE %d] [%d.%d] UL-DXCH -> ULSCH, RLC with LCID 0x%02x (TBS %d bytes, sdu_length_total %d bytes, MAC header "
3433 3434
            "len %d bytes,"
            "buflen_remain %d bytes)\n",
3435
            mac->ue_id,
3436 3437
            frame,
            slot,
3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449
            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) {
        /*
3450 3451 3452 3453 3454
          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'
        */
3455
        if (!fill_mac_sdu(mac,
3456 3457
                          frame,
                          slot,
Sriharsha Korada's avatar
Sriharsha Korada committed
3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470
                          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)) {
3471 3472 3473
          break;
        }
      }
3474
    }
3475 3476 3477

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

3479 3480
  //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.
3481
  nr_ue_get_sdu_mac_ce_post(mac, frame, slot, ulsch_buffer, buflen, mac_ce_p);
mjoang's avatar
mjoang committed
3482

3483 3484
  if (mac_ce_p->tot_mac_ce_len > 0) {
    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);
3485
    int size = nr_write_ce_ulsch_pdu(pdu, mac, mac_ce_p->phr_ce_len ? mac_ce_p->phr : NULL, 0, mac_ce_p->bsr_t, mac_ce_p->bsr_s, mac_ce_p->bsr_l);
francescomani's avatar
francescomani committed
3486 3487
    if (size != mac_ce_p->tot_mac_ce_len)
      LOG_E(NR_MAC, "MAC CE size computed by nr_write_ce_ulsch_pdu is %d while the one assumed before is %d\n", size, mac_ce_p->tot_mac_ce_len);
3488
    pdu += (unsigned char) mac_ce_p->tot_mac_ce_len;
cig's avatar
cig committed
3489

3490
#ifdef ENABLE_MAC_PAYLOAD_DEBUG
3491 3492
    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");
3493
#endif
3494 3495
  }

3496
  buflen_remain = buflen - (mac_ce_p->total_mac_pdu_header_len + mac_ce_p->sdu_length_total);
3497

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

3501
    LOG_D(NR_MAC, "Filling remainder %d bytes to the UL PDU \n", buflen_remain);
3502 3503
    ((NR_MAC_SUBHEADER_FIXED *) pdu)->R = 0;
    ((NR_MAC_SUBHEADER_FIXED *) pdu)->LCID = UL_SCH_LCID_PADDING;
cig's avatar
cig committed
3504

3505
#ifdef ENABLE_MAC_PAYLOAD_DEBUG
3506
    LOG_I(NR_MAC, "Padding MAC sub-header with length %ld bytes \n", sizeof(NR_MAC_SUBHEADER_FIXED));
3507
    log_dump(NR_MAC, pdu, sizeof(NR_MAC_SUBHEADER_FIXED), LOG_DUMP_CHAR, "\n");
3508
#endif
cig's avatar
cig committed
3509

3510 3511
    pdu++;
    buflen_remain--;
cig's avatar
cig committed
3512

3513
    if (IS_SOFTMODEM_RFSIM) {
cig's avatar
cig committed
3514
      for (int j = 0; j < buflen_remain; j++) {
3515
        pdu[j] = (unsigned char)rand();
cig's avatar
cig committed
3516
      }
3517 3518
    } else {
      memset(pdu, 0, buflen_remain);
cig's avatar
cig committed
3519 3520
    }

3521
#ifdef ENABLE_MAC_PAYLOAD_DEBUG
3522
    LOG_I(NR_MAC, "MAC padding sub-PDU with length %d bytes \n", buflen_remain);
3523
    log_dump(NR_MAC, pdu, buflen_remain, LOG_DUMP_CHAR, "\n");
3524
#endif
3525 3526
  }

3527
#ifdef ENABLE_MAC_PAYLOAD_DEBUG
3528
  LOG_I(NR_MAC, "Dumping MAC PDU with length %d: \n", buflen);
3529
  log_dump(NR_MAC, ulsch_buffer, buflen, LOG_DUMP_CHAR, "\n");
3530
#endif
3531

cig's avatar
cig committed
3532
  return num_sdus > 0 ? 1 : 0;
3533
}
cig's avatar
cig committed
3534

3535
static void schedule_ta_command(fapi_nr_dl_config_request_t *dl_config, NR_UL_TIME_ALIGNMENT_t *ul_time_alignment)
3536 3537 3538 3539
{
  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;
3540
  ta->is_rar = ul_time_alignment->ta_apply == rar_ta;
3541 3542 3543
  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;
3544
  ul_time_alignment->ta_apply = no_ta;
3545
}
3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584

static void nr_ue_fill_phr(NR_UE_MAC_INST_t *mac,
                           NR_SINGLE_ENTRY_PHR_MAC_CE *phr,
                           float P_CMAX,
                           float tx_power,
                           frame_t frameP,
                           sub_frame_t subframe)
{
  nr_phr_info_t *phr_info = &mac->scheduling_info.phr_info;
  // Value mapping according to 38.133 10.1.18.1
  const int PC_MAX_00 = -29;
  phr->PCMAX = max(0, (int)P_CMAX - PC_MAX_00) & 0x3f;
  // Value mapping according to 38.133 10.1.17.1.1
  const int POWER_HEADROOM_55 = 22;
  int headroom = P_CMAX - tx_power;
  if (headroom < POWER_HEADROOM_55) {
    const int POWER_HEADROOM_0 = -32;
    phr->PH = max(0, headroom - POWER_HEADROOM_0);
  } else {
    phr->PH = min(0x3f, 55 + (headroom - POWER_HEADROOM_55) / 2);
  }

  LOG_D(NR_MAC,
        "PHR Reporting sfn.subframe %d.%d reason = %d, P_CMAX = %d (%5.2f dBm), headrom = %d (%d dB) tx_power = %5.2f dBm\n",
        frameP,
        subframe,
        phr_info->phr_reporting,
        phr->PCMAX,
        P_CMAX,
        phr->PH,
        headroom,
        tx_power);

  phr_info->PathlossLastValue = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm);
  // Restart both timers according to 38.321
  nr_timer_start(&phr_info->periodicPHR_Timer);
  nr_timer_start(&phr_info->prohibitPHR_Timer);
  phr_info->phr_reporting = 0;
}