nr_ra_procedures.c 32 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 33 34 35 36 37
/*
 * 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 ra_procedures.c
 * \brief Routines for UE MAC-layer Random Access procedures (TS 38.321, Release 15)
 * \author R. Knopp, Navid Nikaein, Guido Casati
 * \date 2019
 * \version 0.1
 * \company Eurecom
 * \email: knopp@eurecom.fr navid.nikaein@eurecom.fr, guido.casati@iis.fraunhofer.de
 * \note
 * \warning
 */

/* Tools */
#include "SIMULATION/TOOLS/sim.h"	// for taus

/* RRC */
#include "NR_RACH-ConfigCommon.h"
rmagueta's avatar
rmagueta committed
38
#include "RRC/NR_UE/rrc_proto.h"
39 40 41 42 43

/* PHY */
#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
#include "PHY/defs_common.h"
#include "PHY/defs_nr_common.h"
cig's avatar
cig committed
44
#include "PHY/NR_UE_ESTIMATION/nr_estimation.h"
45 46 47 48 49 50

/* MAC */
#include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h"
#include "NR_MAC_COMMON/nr_mac.h"
#include "LAYER2/NR_MAC_UE/mac_proto.h"

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

53 54
void nr_get_RA_window(NR_UE_MAC_INST_t *mac);

55 56 57 58
// Random Access procedure initialization as per 5.1.1 and initialization of variables specific
// to Random Access type as specified in clause 5.1.1a (3GPP TS 38.321 version 16.2.1 Release 16)
// todo:
// - check if carrier to use is explicitly signalled then do (1) RA CARRIER SELECTION (SUL, NUL) (2) set PCMAX (currently hardcoded to 0)
cig's avatar
cig committed
59 60
void init_RA(module_id_t mod_id,
             NR_PRACH_RESOURCES_t *prach_resources,
61 62 63 64
             NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon,
             NR_RACH_ConfigGeneric_t *rach_ConfigGeneric,
             NR_RACH_ConfigDedicated_t *rach_ConfigDedicated) {

65
  NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
66 67 68

  RA_config_t *ra          = &mac->ra;
  ra->RA_active            = 1;
69 70
  ra->ra_PreambleIndex     = -1;
  ra->RA_usedGroupA        = 1;
71
  ra->RA_RAPID_found       = 0;
cig's avatar
cig committed
72 73
  ra->preambleTransMax     = 0;
  ra->first_Msg3           = 1;
74
  ra->starting_preamble_nb = 0;
cig's avatar
cig committed
75
  ra->RA_backoff_cnt       = 0;
76

77
  prach_resources->RA_PREAMBLE_BACKOFF = 0;
cig's avatar
cig committed
78
  prach_resources->RA_PCMAX = nr_get_Pcmax(mod_id);
79 80 81 82 83 84 85
  prach_resources->RA_PREAMBLE_TRANSMISSION_COUNTER = 1;
  prach_resources->RA_PREAMBLE_POWER_RAMPING_COUNTER = 1;
  prach_resources->POWER_OFFSET_2STEP_RA = 0;
  prach_resources->RA_SCALING_FACTOR_BI = 1;

  if (rach_ConfigDedicated) {
    if (rach_ConfigDedicated->cfra){
86 87
      LOG_I(MAC, "Initialization of 2-step contention-free random access procedure\n");
      prach_resources->RA_TYPE = RA_2STEP;
88
      ra->cfra = 1;
Thomas Schlichter's avatar
Thomas Schlichter committed
89 90 91 92 93 94 95 96 97 98
    } else if (rach_ConfigDedicated->ext1){
      if (rach_ConfigDedicated->ext1->cfra_TwoStep_r16){
        LOG_I(MAC, "In %s: setting RA type to 2-step...\n", __FUNCTION__);
        prach_resources->RA_TYPE = RA_2STEP;
        ra->cfra = 1;
      } else {
        LOG_E(MAC, "In %s: config not handled\n", __FUNCTION__);
      }
    } else {
      LOG_E(MAC, "In %s: config not handled\n", __FUNCTION__);
99
    }
100 101 102 103
  } else if (nr_rach_ConfigCommon){
    LOG_I(MAC, "Initialization of 4-step contention-based random access procedure\n");
    prach_resources->RA_TYPE = RA_4STEP;
    ra->cfra = 0;
Thomas Schlichter's avatar
Thomas Schlichter committed
104 105
  } else {
    LOG_E(MAC, "In %s: config not handled\n", __FUNCTION__);
106 107
  }

108 109
  switch (rach_ConfigGeneric->powerRampingStep){ // in dB
    case 0:
110 111
      prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP = 0;
      break;
112
    case 1:
113 114
      prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP = 2;
      break;
115
    case 2:
116 117
      prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP = 4;
      break;
118
    case 3:
119 120
      prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP = 6;
      break;
121
  }
122

123 124
  switch (rach_ConfigGeneric->preambleTransMax) {
    case 0:
125
      ra->preambleTransMax = 3;
126
      break;
127
    case 1:
128
      ra->preambleTransMax = 4;
129
      break;
130
    case 2:
131
      ra->preambleTransMax = 5;
132
      break;
133
    case 3:
134
      ra->preambleTransMax = 6;
135
      break;
136
    case 4:
137
      ra->preambleTransMax = 7;
138
      break;
139
    case 5:
140
      ra->preambleTransMax = 8;
141
      break;
142
    case 6:
143
      ra->preambleTransMax = 10;
144
      break;
145
    case 7:
146
      ra->preambleTransMax = 20;
147
      break;
148
    case 8:
149
      ra->preambleTransMax = 50;
150
      break;
151
    case 9:
152
      ra->preambleTransMax = 100;
153
      break;
154
    case 10:
155
      ra->preambleTransMax = 200;
156 157 158
      break;
  }

159 160 161 162 163
  if (nr_rach_ConfigCommon->ext1) {
    if (nr_rach_ConfigCommon->ext1->ra_PrioritizationForAccessIdentity){
      LOG_D(MAC, "In %s:%d: Missing implementation for Access Identity initialization procedures\n", __FUNCTION__, __LINE__);
    }
  }
164 165
}

166
void ssb_rach_config(RA_config_t *ra, NR_PRACH_RESOURCES_t *prach_resources, NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon, fapi_nr_ul_config_prach_pdu *prach_pdu){
167

cig's avatar
cig committed
168 169
  // Determine the SSB to RACH mapping ratio
  // =======================================
Mario Hudon's avatar
Mario Hudon committed
170

171 172 173 174 175 176
  NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR ssb_perRACH_config = nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present;
  boolean_t multiple_ssb_per_ro; // true if more than one or exactly one SSB per RACH occasion, false if more than one RO per SSB
  uint8_t ssb_rach_ratio; // Nb of SSBs per RACH or RACHs per SSB
  int total_preambles_per_ssb;
  uint8_t ssb_nb_in_ro;
  int numberOfRA_Preambles = 64;
Mario Hudon's avatar
Mario Hudon committed
177

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
  switch (ssb_perRACH_config){
    case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_oneEighth:
      multiple_ssb_per_ro = false;
      ssb_rach_ratio = 8;
      ra->cb_preambles_per_ssb = 4 * (nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.oneEighth + 1);
      break;
    case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_oneFourth:
      multiple_ssb_per_ro = false;
      ssb_rach_ratio = 4;
      ra->cb_preambles_per_ssb = 4 * (nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.oneFourth + 1);
      break;
    case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_oneHalf:
      multiple_ssb_per_ro = false;
      ssb_rach_ratio = 2;
      ra->cb_preambles_per_ssb = 4 * (nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.oneHalf + 1);
      break;
    case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_one:
      multiple_ssb_per_ro = true;
      ssb_rach_ratio = 1;
      ra->cb_preambles_per_ssb = 4 * (nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.one + 1);
      break;
    case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_two:
      multiple_ssb_per_ro = true;
      ssb_rach_ratio = 2;
      ra->cb_preambles_per_ssb = 4 * (nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.two + 1);
      break;
    case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_four:
      multiple_ssb_per_ro = true;
      ssb_rach_ratio = 4;
      ra->cb_preambles_per_ssb = nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.four;
      break;
    case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_eight:
      multiple_ssb_per_ro = true;
      ssb_rach_ratio = 8;
      ra->cb_preambles_per_ssb = nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.eight;
      break;
    case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_sixteen:
      multiple_ssb_per_ro = true;
      ssb_rach_ratio = 16;
      ra->cb_preambles_per_ssb = nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.sixteen;
      break;
    default:
      AssertFatal(1 == 0, "Unsupported ssb_perRACH_config %d\n", ssb_perRACH_config);
  }
cig's avatar
cig committed
222

223 224
  if (nr_rach_ConfigCommon->totalNumberOfRA_Preambles)
    numberOfRA_Preambles = *(nr_rach_ConfigCommon->totalNumberOfRA_Preambles);
Mario Hudon's avatar
Mario Hudon committed
225

226 227 228 229 230 231
  // Compute the proper Preamble selection params according to the selected SSB and the ssb_perRACH_OccasionAndCB_PreamblesPerSSB configuration
  if ((true == multiple_ssb_per_ro) && (ssb_rach_ratio > 1)) {
    total_preambles_per_ssb = numberOfRA_Preambles / ssb_rach_ratio;

    ssb_nb_in_ro = prach_pdu->ssb_nb_in_ro;
    ra->starting_preamble_nb = total_preambles_per_ssb * ssb_nb_in_ro;
cig's avatar
cig committed
232
  } else {
233 234
    total_preambles_per_ssb = numberOfRA_Preambles;
    ra->starting_preamble_nb = 0;
cig's avatar
cig committed
235 236 237
  }
}

238
// This routine implements RA preamble configuration according to
cig's avatar
cig committed
239 240 241 242 243 244
// section 5.1 (Random Access procedure) of 3GPP TS 38.321 version 16.2.1 Release 16
void ra_preambles_config(NR_PRACH_RESOURCES_t *prach_resources, NR_UE_MAC_INST_t *mac, int16_t dl_pathloss){

  int messageSizeGroupA = 0;
  int sizeOfRA_PreamblesGroupA = 0;
  int messagePowerOffsetGroupB = 0;
245
  int PLThreshold = 0;
246
  long deltaPreamble_Msg3 = 0;
cig's avatar
cig committed
247
  uint8_t noGroupB = 0;
248
  RA_config_t *ra = &mac->ra;
cig's avatar
cig committed
249 250 251
  NR_ServingCellConfigCommon_t *scc = mac->scc;
  NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup;
  NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &nr_rach_ConfigCommon->rach_ConfigGeneric;
Mario Hudon's avatar
Mario Hudon committed
252

253 254 255 256
  if (scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->msg3_DeltaPreamble){
    deltaPreamble_Msg3 = (*scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->msg3_DeltaPreamble) * 2; // dB
    LOG_D(MAC, "In %s: deltaPreamble_Msg3 set to %ld\n", __FUNCTION__, deltaPreamble_Msg3);
  }
257

258 259 260 261 262 263 264 265 266 267
  if (!nr_rach_ConfigCommon->groupBconfigured) {
    noGroupB = 1;
    LOG_D(MAC, "In %s:%d: preambles group B is not configured...\n", __FUNCTION__, __LINE__);
  } else {
    // RA preambles group B is configured
    // - Random Access Preambles group B is configured for 4-step RA type
    // - Defining the number of RA preambles in RA Preamble Group A for each SSB
    LOG_D(MAC, "In %s:%d: preambles group B is configured...\n", __FUNCTION__, __LINE__);
    sizeOfRA_PreamblesGroupA = nr_rach_ConfigCommon->groupBconfigured->numberOfRA_PreamblesGroupA;
    switch (nr_rach_ConfigCommon->groupBconfigured->ra_Msg3SizeGroupA){
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
      /* - Threshold to determine the groups of RA preambles */
      case 0:
      messageSizeGroupA = 56;
      break;
      case 1:
      messageSizeGroupA = 144;
      break;
      case 2:
      messageSizeGroupA = 208;
      break;
      case 3:
      messageSizeGroupA = 256;
      break;
      case 4:
      messageSizeGroupA = 282;
      break;
      case 5:
      messageSizeGroupA = 480;
      break;
      case 6:
      messageSizeGroupA = 640;
      break;
      case 7:
      messageSizeGroupA = 800;
      break;
      case 8:
      messageSizeGroupA = 1000;
      break;
      case 9:
      messageSizeGroupA = 72;
      break;
      default:
cig's avatar
cig committed
300
      AssertFatal(1 == 0, "Unknown ra_Msg3SizeGroupA %lu\n", nr_rach_ConfigCommon->groupBconfigured->ra_Msg3SizeGroupA);
301 302
      /* todo cases 10 -15*/
      }
cig's avatar
cig committed
303

304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
      /* Power offset for preamble selection in dB */
      messagePowerOffsetGroupB = -9999;
      switch (nr_rach_ConfigCommon->groupBconfigured->messagePowerOffsetGroupB){
      case 0:
      messagePowerOffsetGroupB = -9999;
      break;
      case 1:
      messagePowerOffsetGroupB = 0;
      break;
      case 2:
      messagePowerOffsetGroupB = 5;
      break;
      case 3:
      messagePowerOffsetGroupB = 8;
      break;
      case 4:
      messagePowerOffsetGroupB = 10;
      break;
      case 5:
      messagePowerOffsetGroupB = 12;
      break;
      case 6:
      messagePowerOffsetGroupB = 15;
      break;
      case 7:
      messagePowerOffsetGroupB = 18;
      break;
      default:
      AssertFatal(1 == 0,"Unknown messagePowerOffsetGroupB %lu\n", nr_rach_ConfigCommon->groupBconfigured->messagePowerOffsetGroupB);
333
    }
334

335
    PLThreshold = prach_resources->RA_PCMAX - rach_ConfigGeneric->preambleReceivedTargetPower - deltaPreamble_Msg3 - messagePowerOffsetGroupB;
cig's avatar
cig committed
336 337

  }
338

cig's avatar
cig committed
339
  /* Msg3 has not been transmitted yet */
340
  if (ra->first_Msg3) {
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
    if(ra->ra_PreambleIndex < 0 || ra->ra_PreambleIndex > 63) {
      if (noGroupB) {
        // use Group A preamble
        ra->ra_PreambleIndex = ra->starting_preamble_nb + ((taus()) % ra->cb_preambles_per_ssb);
        ra->RA_usedGroupA = 1;
      } else if ((ra->Msg3_size < messageSizeGroupA) && (dl_pathloss > PLThreshold)) {
        // Group B is configured and RA preamble Group A is used
        // - todo add condition on CCCH_sdu_size for initiation by CCCH
        ra->ra_PreambleIndex = ra->starting_preamble_nb + ((taus()) % sizeOfRA_PreamblesGroupA);
        ra->RA_usedGroupA = 1;
      } else {
        // Group B preamble is configured and used
        // the first sizeOfRA_PreamblesGroupA RA preambles belong to RA Preambles Group A
        // the remaining belong to RA Preambles Group B
        ra->ra_PreambleIndex = ra->starting_preamble_nb + sizeOfRA_PreamblesGroupA + ((taus()) % (ra->cb_preambles_per_ssb - sizeOfRA_PreamblesGroupA));
        ra->RA_usedGroupA = 0;
      }
cig's avatar
cig committed
358 359
    }
  } else { // Msg3 is being retransmitted
360
    if (ra->RA_usedGroupA && noGroupB) {
361
      ra->ra_PreambleIndex = ra->starting_preamble_nb + ((taus()) % ra->cb_preambles_per_ssb);
362
    } else if (ra->RA_usedGroupA && !noGroupB){
363
      ra->ra_PreambleIndex = ra->starting_preamble_nb + ((taus()) % sizeOfRA_PreamblesGroupA);
cig's avatar
cig committed
364
    } else {
365
      ra->ra_PreambleIndex = ra->starting_preamble_nb + sizeOfRA_PreamblesGroupA + ((taus()) % (ra->cb_preambles_per_ssb - sizeOfRA_PreamblesGroupA));
366
    }
cig's avatar
cig committed
367
  }
368
  prach_resources->ra_PreambleIndex = ra->ra_PreambleIndex;
cig's avatar
cig committed
369
}
370

371 372 373 374 375 376 377 378
// RA-RNTI computation (associated to PRACH occasion in which the RA Preamble is transmitted)
// - this does not apply to contention-free RA Preamble for beam failure recovery request
// - getting star_symb, SFN_nbr from table 6.3.3.2-3 (TDD and FR1 scenario)
// - ul_carrier_id: UL carrier used for RA preamble transmission, hardcoded for NUL carrier
// - f_id: index of the PRACH occasion in the frequency domain
// - s_id is starting symbol of the PRACH occasion [0...14]
// - t_id is the first slot of the PRACH occasion in a system frame [0...80]
uint16_t set_ra_rnti(NR_UE_MAC_INST_t *mac, fapi_nr_ul_config_prach_pdu *prach_pdu){
379 380

  RA_config_t *ra = &mac->ra;
381 382 383 384
  uint8_t ul_carrier_id = 0; // NUL
  uint8_t f_id = prach_pdu->num_ra;
  uint8_t t_id = prach_pdu->prach_slot;
  uint8_t s_id = prach_pdu->prach_start_symbol;
385 386 387 388 389 390 391

  ra->ra_rnti = 1 + s_id + 14 * t_id + 1120 * f_id + 8960 * ul_carrier_id;

  LOG_D(MAC, "Computed ra_RNTI is %x \n", ra->ra_rnti);

  return ra->ra_rnti;

392 393
}

cig's avatar
cig committed
394 395
// This routine implements Section 5.1.2 (UE Random Access Resource Selection)
// and Section 5.1.3 (Random Access Preamble Transmission) from 3GPP TS 38.321
cig's avatar
cig committed
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
// - currently the PRACH preamble is set through RRC configuration for 4-step CFRA mode
// todo:
// - determine next available PRACH occasion
// -- if RA initiated for SI request and ra_AssociationPeriodIndex and si-RequestPeriod are configured
// -- else if SSB is selected above
// -- else if CSI-RS is selected above
// - switch initialisation cases
// -- RA initiated by beam failure recovery operation (subclause 5.17 TS 38.321)
// --- SSB selection, set prach_resources->ra_PreambleIndex
// -- RA initiated by PDCCH: ra_preamble_index provided by PDCCH && ra_PreambleIndex != 0b000000
// --- set PREAMBLE_INDEX to ra_preamble_index
// --- select the SSB signalled by PDCCH
// -- RA initiated for SI request:
// --- SSB selection, set prach_resources->ra_PreambleIndex
// - condition on notification of suspending power ramping counter from lower layer (5.1.3 TS 38.321)
// - check if SSB or CSI-RS have not changed since the selection in the last RA Preamble tranmission
// - Contention-based RA preamble selection:
// -- selection of SSB with SS-RSRP above rsrp-ThresholdSSB else select any SSB
cig's avatar
cig committed
414 415 416 417 418 419 420 421
void nr_get_prach_resources(module_id_t mod_id,
                            int CC_id,
                            uint8_t gNB_id,
                            NR_PRACH_RESOURCES_t *prach_resources,
                            fapi_nr_ul_config_prach_pdu *prach_pdu,
                            NR_RACH_ConfigDedicated_t * rach_ConfigDedicated){

  NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
422
  RA_config_t *ra = &mac->ra;
cig's avatar
cig committed
423 424
  NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = mac->scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup;

425
  LOG_D(PHY, "In %s: getting PRACH resources frame (first_Msg3 %d)\n", __FUNCTION__, ra->first_Msg3);
cig's avatar
cig committed
426 427 428 429 430

  if (rach_ConfigDedicated) {
    if (rach_ConfigDedicated->cfra){
      uint8_t cfra_ssb_resource_idx = 0;
      prach_resources->ra_PreambleIndex = rach_ConfigDedicated->cfra->resources.choice.ssb->ssb_ResourceList.list.array[cfra_ssb_resource_idx]->ra_PreambleIndex;
cig's avatar
cig committed
431
      LOG_D(MAC, "In %s: selected RA preamble index %d for contention-free random access procedure for SSB with Id %d\n", __FUNCTION__, prach_resources->ra_PreambleIndex, cfra_ssb_resource_idx);
cig's avatar
cig committed
432 433 434
    }
  } else {
    int16_t dl_pathloss = get_nr_PL(mod_id, CC_id, gNB_id);
435
    ssb_rach_config(ra, prach_resources, nr_rach_ConfigCommon, prach_pdu);
cig's avatar
cig committed
436
    ra_preambles_config(prach_resources, mac, dl_pathloss);
437
    LOG_D(MAC, "[RAPROC] - Selected RA preamble index %d for contention-based random access procedure... \n", prach_resources->ra_PreambleIndex);
cig's avatar
cig committed
438
  }
439

440 441
  if (prach_resources->RA_PREAMBLE_TRANSMISSION_COUNTER > 1)
    prach_resources->RA_PREAMBLE_POWER_RAMPING_COUNTER++;
442
  prach_resources->ra_PREAMBLE_RECEIVED_TARGET_POWER = nr_get_Po_NOMINAL_PUSCH(prach_resources, mod_id, CC_id);
443
  prach_resources->ra_RNTI = set_ra_rnti(mac, prach_pdu);
cig's avatar
cig committed
444

445 446
}

cig's avatar
cig committed
447
// TbD: RA_attempt_number not used
448
void nr_Msg1_transmitted(module_id_t mod_id, uint8_t CC_id, frame_t frameP, uint8_t gNB_id){
cig's avatar
cig committed
449
  NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
450 451 452
  RA_config_t *ra = &mac->ra;
  ra->ra_state = WAIT_RAR;
  ra->RA_attempt_number++;
cig's avatar
cig committed
453
}
454 455

void nr_Msg3_transmitted(module_id_t mod_id, uint8_t CC_id, frame_t frameP, uint8_t gNB_id){
456

457
  NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
458
  NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = mac->scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup;
459
  RA_config_t *ra = &mac->ra;
460 461 462

  LOG_D(MAC,"In %s: [UE %d] Frame %d, CB-RA: starting contention resolution timer\n", __FUNCTION__, mod_id, frameP);

463
  // start contention resolution timer
464 465
  ra->RA_contention_resolution_cnt = (nr_rach_ConfigCommon->ra_ContentionResolutionTimer + 1) * 8;
  ra->RA_contention_resolution_timer_active = 1;
466
  ra->ra_state = WAIT_CONTENTION_RESOLUTION;
467

468 469 470
}

/////////////////////////////////////////////////////////////////////////
cig's avatar
cig committed
471 472 473 474
// This function handles:
// - Random Access Preamble Initialization (5.1.1 TS 38.321)
// - Random Access Response reception (5.1.4 TS 38.321)
/// In the current implementation, RA is 4-step contention free only
475
/////////////////////////////////////////////////////////////////////////
cig's avatar
cig committed
476 477
// todo TS 38.321:
// - BWP operation (subclause 5.15 TS 38.321)
cig's avatar
cig committed
478
// - beam failure recovery
cig's avatar
cig committed
479
// - handle initialization by handover
cig's avatar
cig committed
480 481
// - handle DL assignment on PDCCH for RA-RNTI
// - transmission on DCCH using PRACH (during handover, or sending SR for example)
cig's avatar
cig committed
482 483 484 485
// - take into account MAC CEs in size_sdu (currently hardcoded size to 1 MAC subPDU and 1 padding subheader)
// - fix rrc data req logic
// - retrieve TBS
// - add mac_rrc_nr_data_req_ue, etc ...
cig's avatar
cig committed
486
// - Msg3 Retransmissions to be scheduled by DCI 0_0
cig's avatar
cig committed
487
uint8_t nr_ue_get_rach(NR_PRACH_RESOURCES_t *prach_resources,
488
                       fapi_nr_ul_config_prach_pdu *prach_pdu,
cig's avatar
cig committed
489 490 491 492
                       module_id_t mod_id,
                       int CC_id,
                       frame_t frame,
                       uint8_t gNB_id,
493
                       int nr_slot_tx){
494

cig's avatar
cig committed
495
  NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
496
  RA_config_t *ra = &mac->ra;
497
  uint8_t mac_sdus[MAX_NR_ULSCH_PAYLOAD_BYTES];
498 499
  uint8_t lcid = UL_SCH_LCID_CCCH;
  uint8_t *payload;
cig's avatar
cig committed
500 501
  uint16_t size_sdu = 0;
  unsigned short post_padding;
cig's avatar
cig committed
502
  NR_ServingCellConfigCommon_t *scc = mac->scc;
cig's avatar
cig committed
503
  AssertFatal(scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup != NULL, "In %s: FATAL! nr_rach_ConfigCommon is NULL...\n", __FUNCTION__);
cig's avatar
cig committed
504
  NR_RACH_ConfigCommon_t *setup = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup;
cig's avatar
cig committed
505
  AssertFatal(&setup->rach_ConfigGeneric != NULL, "In %s: FATAL! rach_ConfigGeneric is NULL...\n", __FUNCTION__);
cig's avatar
cig committed
506
  NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric;
507
  NR_RACH_ConfigDedicated_t *rach_ConfigDedicated = ra->rach_ConfigDedicated;
508

cig's avatar
cig committed
509 510
  uint8_t sdu_lcids[NB_RB_MAX] = {0};
  uint16_t sdu_lengths[NB_RB_MAX] = {0};
rmagueta's avatar
rmagueta committed
511 512
  int num_sdus = 0;
  int offset = 0;
513

cig's avatar
cig committed
514 515 516 517 518 519 520 521 522
  // Delay init RA procedure to allow the convergence of the IIR filter on PRACH noise measurements at gNB side
  if (!prach_resources->init_msg1) {
    if (((MAX_FRAME_NUMBER + frame - prach_resources->sync_frame) % MAX_FRAME_NUMBER) > 150){
      prach_resources->init_msg1 = 1;
    } else {
      return 0;
    }
  }

523
  if (prach_resources->init_msg1 && ra->ra_state != RA_SUCCEEDED) {
cig's avatar
cig committed
524

525
    if (ra->RA_active == 0) {
526 527
      /* RA not active - checking if RRC is ready to initiate the RA procedure */

528
      LOG_D(MAC, "RA not active. Checking for data to transmit from upper layers...\n");
cig's avatar
cig committed
529

rmagueta's avatar
rmagueta committed
530 531 532
      uint8_t TBS_max = 8 + sizeof(NR_MAC_SUBHEADER_SHORT) + sizeof(NR_MAC_SUBHEADER_SHORT);
      payload = (uint8_t*) mac->CCCH_pdu.payload;

cig's avatar
cig committed
533 534
      num_sdus = 1;
      post_padding = 1;
rmagueta's avatar
rmagueta committed
535
      sdu_lcids[0] = lcid;
cig's avatar
cig committed
536

rmagueta's avatar
rmagueta committed
537
      // initialisation by RRC
538 539

      // TODO: To be removed after RA procedures fully implemented
540 541 542 543
      if(get_softmodem_params()->do_ra) {
        nr_rrc_ue_generate_RRCSetupRequest(mod_id,gNB_id);
      }

rmagueta's avatar
rmagueta committed
544 545 546 547 548 549
      // CCCH PDU
      size_sdu = (uint16_t) nr_mac_rrc_data_req_ue(mod_id, CC_id, gNB_id, frame, CCCH, mac_sdus);

      sdu_lengths[0] = size_sdu;

      LOG_D(MAC,"[UE %d] Frame %d: Requested RRCConnectionRequest, got %d bytes\n", mod_id, frame, size_sdu);
550

cig's avatar
cig committed
551
      if (size_sdu > 0) {
552

rmagueta's avatar
rmagueta committed
553 554 555 556 557
        // UE Contention Resolution Identity
        // Store the first 48 bits belonging to the uplink CCCH SDU within Msg3 to determine whether or not the
        // Random Access Procedure has been successful after reception of Msg4
        memcpy(ra->cont_res_id, mac_sdus, sizeof(uint8_t) * 6);

558
        LOG_D(MAC, "[UE %d][%d.%d]: starting initialisation Random Access Procedure...\n", mod_id, frame, nr_slot_tx);
559

560
        ra->Msg3_size = size_sdu + sizeof(NR_MAC_SUBHEADER_SHORT) + sizeof(NR_MAC_SUBHEADER_SHORT);
561

cig's avatar
cig committed
562
        init_RA(mod_id, prach_resources, setup, rach_ConfigGeneric, rach_ConfigDedicated);
cig's avatar
cig committed
563
        prach_resources->Msg3 = payload;
cig's avatar
cig committed
564
        nr_get_RA_window(mac);
565 566

        // Fill in preamble and PRACH resources
567
        if (ra->generate_nr_prach == GENERATE_PREAMBLE)
cig's avatar
cig committed
568
          nr_get_prach_resources(mod_id, CC_id, gNB_id, prach_resources, prach_pdu, rach_ConfigDedicated);
569

cig's avatar
cig committed
570
        offset = nr_generate_ulsch_pdu((uint8_t *) mac_sdus,              // sdus buffer
cig's avatar
cig committed
571
                                       (uint8_t *) payload,               // UL MAC pdu pointer
cig's avatar
cig committed
572 573 574 575 576 577 578 579
                                       num_sdus,                          // num sdus
                                       sdu_lengths,                       // sdu length
                                       sdu_lcids,                         // sdu lcid
                                       0,                                 // power headroom
                                       0,                                 // crnti
                                       0,                                 // truncated bsr
                                       0,                                 // short bsr
                                       0,                                 // long_bsr
580 581
                                       post_padding,
                                       0);
cig's avatar
cig committed
582

rmagueta's avatar
rmagueta committed
583 584
        AssertFatal(TBS_max > offset, "Frequency resources are not enough for Msg3!\n");

cig's avatar
cig committed
585
        // Padding: fill remainder with 0
cig's avatar
cig committed
586
        if (post_padding > 0){
rmagueta's avatar
rmagueta committed
587 588
          for (int j = 0; j < (TBS_max - offset); j++)
            payload[offset + j] = 0;
cig's avatar
cig committed
589
        }
rmagueta's avatar
rmagueta committed
590 591 592 593 594 595 596 597
      }

      LOG_D(MAC,"size_sdu = %i\n", size_sdu);
      LOG_D(MAC,"offset = %i\n", offset);
      for(int k = 0; k < TBS_max; k++) {
        LOG_D(MAC,"(%i): %i\n", k, prach_resources->Msg3[k]);
      }

598
      // Msg3 was initialized with TBS_max bytes because the RA_Msg3_size will only be known after
rmagueta's avatar
rmagueta committed
599
      // receiving Msg2 (which contains the Msg3 resource reserve).
600
      // Msg3 will be transmitted with RA_Msg3_size bytes, removing unnecessary 0s.
rmagueta's avatar
rmagueta committed
601 602 603
      mac->ulsch_pdu.Pdu_size = TBS_max;
      memcpy(mac->ulsch_pdu.payload, prach_resources->Msg3, TBS_max);

604
    } else if (ra->RA_window_cnt != -1) { // RACH is active
605

606
      LOG_D(MAC, "In %s [%d.%d] RA is active: RA window count %d, RA backoff count %d\n", __FUNCTION__, frame, nr_slot_tx, ra->RA_window_cnt, ra->RA_backoff_cnt);
607

608 609
      if (ra->RA_BI_found){
        prach_resources->RA_PREAMBLE_BACKOFF = prach_resources->RA_SCALING_FACTOR_BI * ra->RA_backoff_indicator;
cig's avatar
cig committed
610 611 612
      } else {
        prach_resources->RA_PREAMBLE_BACKOFF = 0;
      }
613

614
      if (ra->RA_window_cnt >= 0 && ra->RA_RAPID_found == 1) {
cig's avatar
cig committed
615

616 617 618 619
        if(ra->cfra) {
          // Reset RA_active flag: it disables Msg3 retransmission (8.3 of TS 38.213)
          nr_ra_succeeded(mod_id, frame, nr_slot_tx);
        } else {
620
          ra->generate_nr_prach = GENERATE_IDLE;
621
        }
cig's avatar
cig committed
622

623
      } else if (ra->RA_window_cnt == 0 && !ra->RA_RAPID_found) {
cig's avatar
cig committed
624

cig's avatar
cig committed
625
        LOG_I(MAC, "[UE %d][%d:%d] RAR reception failed \n", mod_id, frame, nr_slot_tx);
626

627
        nr_ra_failed(mod_id, CC_id, prach_resources, frame, nr_slot_tx);
cig's avatar
cig committed
628

629
      } else if (ra->RA_window_cnt > 0) {
630

631
        LOG_D(MAC, "[UE %d][%d.%d]: RAR not received yet (RA window count %d) \n", mod_id, frame, nr_slot_tx, ra->RA_window_cnt);
632

633
        // Fill in preamble and PRACH resources
634
        ra->RA_window_cnt--;
cig's avatar
cig committed
635
        nr_get_prach_resources(mod_id, CC_id, gNB_id, prach_resources, prach_pdu, rach_ConfigDedicated);
636

637
      } else if (ra->RA_backoff_cnt > 0) {
cig's avatar
cig committed
638

639
        LOG_D(MAC, "[UE %d][%d.%d]: RAR not received yet (RA backoff count %d) \n", mod_id, frame, nr_slot_tx, ra->RA_backoff_cnt);
cig's avatar
cig committed
640

641
        ra->RA_backoff_cnt--;
cig's avatar
cig committed
642

643
        if ((ra->RA_backoff_cnt > 0 && ra->generate_nr_prach == GENERATE_PREAMBLE) || ra->RA_backoff_cnt == 0){
cig's avatar
cig committed
644
          nr_get_prach_resources(mod_id, CC_id, gNB_id, prach_resources, prach_pdu, rach_ConfigDedicated);
cig's avatar
cig committed
645
        }
646

647 648
      }
    }
649
  }
cig's avatar
cig committed
650

651
  if (ra->RA_contention_resolution_timer_active){
652
    nr_ue_contention_resolution(mod_id, CC_id, frame, nr_slot_tx, prach_resources);
653
  }
cig's avatar
cig committed
654

655 656 657 658 659
  if(ra->generate_nr_prach != GENERATE_IDLE) {
    return ra->generate_nr_prach;
  } else {
    return ra->ra_state;
  }
cig's avatar
cig committed
660

661
}
cig's avatar
cig committed
662 663 664 665

void nr_get_RA_window(NR_UE_MAC_INST_t *mac){

  uint8_t mu, ra_ResponseWindow;
666
  RA_config_t *ra = &mac->ra;
cig's avatar
cig committed
667 668 669 670 671 672 673 674 675 676 677 678
  NR_ServingCellConfigCommon_t *scc = mac->scc;
  NR_RACH_ConfigCommon_t *setup = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup;
  NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric;
  NR_FrequencyInfoDL_t *frequencyInfoDL = scc->downlinkConfigCommon->frequencyInfoDL;

  ra_ResponseWindow = rach_ConfigGeneric->ra_ResponseWindow;

  if (setup->msg1_SubcarrierSpacing)
    mu = *setup->msg1_SubcarrierSpacing;
  else
    mu = frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing;

679
  ra->RA_window_cnt = ra->RA_offset*nr_slots_per_frame[mu]; // taking into account the 2 frames gap introduced by OAI gNB
cig's avatar
cig committed
680 681

  switch (ra_ResponseWindow) {
cig's avatar
cig committed
682
    case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl1:
683
      ra->RA_window_cnt += 1;
cig's avatar
cig committed
684
      break;
cig's avatar
cig committed
685
    case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl2:
686
      ra->RA_window_cnt += 2;
cig's avatar
cig committed
687
      break;
cig's avatar
cig committed
688
    case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl4:
689
      ra->RA_window_cnt += 4;
cig's avatar
cig committed
690
      break;
cig's avatar
cig committed
691
    case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl8:
692
      ra->RA_window_cnt += 8;
cig's avatar
cig committed
693
      break;
cig's avatar
cig committed
694
    case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl10:
695
      ra->RA_window_cnt += 10;
cig's avatar
cig committed
696
      break;
cig's avatar
cig committed
697
    case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl20:
698
      ra->RA_window_cnt += 20;
cig's avatar
cig committed
699
      break;
cig's avatar
cig committed
700
    case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl40:
701
      ra->RA_window_cnt += 40;
cig's avatar
cig committed
702
      break;
cig's avatar
cig committed
703
    case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl80:
704
      ra->RA_window_cnt += 80;
cig's avatar
cig committed
705 706
      break;
  }
707
}
708 709 710 711 712 713 714 715 716 717 718

////////////////////////////////////////////////////////////////////////////
/////////* Random Access Contention Resolution (5.1.35 TS 38.321) */////////
////////////////////////////////////////////////////////////////////////////
// Handling contention resolution timer
// WIP todo:
// - beam failure recovery
// - RA completed
void nr_ue_contention_resolution(module_id_t module_id, int cc_id, frame_t frame, int slot, NR_PRACH_RESOURCES_t *prach_resources){
  
  NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
719
  RA_config_t *ra = &mac->ra;
720

721
  if (ra->RA_contention_resolution_timer_active == 1) {
722

723
      ra->RA_contention_resolution_cnt--;
724

725
      LOG_D(MAC, "In %s: [%d.%d] RA contention resolution timer %d\n", __FUNCTION__, frame, slot, ra->RA_contention_resolution_cnt);
726

727 728 729 730
      if (ra->RA_contention_resolution_cnt == 0) {
        ra->t_crnti = 0;
        ra->RA_active = 0;
        ra->RA_contention_resolution_timer_active = 0;
731 732 733 734 735 736 737 738 739 740 741 742 743 744 745
        // Signal PHY to quit RA procedure
        LOG_E(MAC, "[UE %d] CB-RA: Contention resolution timer has expired, RA procedure has failed...\n", module_id);
        nr_ra_failed(module_id, cc_id, prach_resources, frame, slot);
      }
    
  }
}

// Handlig successful RA completion @ MAC layer
// according to section 5 of 3GPP TS 38.321 version 16.2.1 Release 16
// todo:
// - complete handling of received contention-based RA preamble
void nr_ra_succeeded(module_id_t mod_id, frame_t frame, int slot){

  NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
746
  RA_config_t *ra = &mac->ra;
747

748
  if (ra->cfra) {
749

750
    LOG_I(MAC, "[UE %d][%d.%d][RAPROC] RA procedure succeeded. CF-RA: RAR successfully received.\n", mod_id, frame, slot);
751

752
    ra->RA_window_cnt = -1;
753
    mac->crnti = ra->t_crnti;
754 755 756

  } else {

757
    LOG_I(MAC, "[UE %d][%d.%d][RAPROC] RA procedure succeeded. CB-RA: Contention Resolution is successful.\n", mod_id, frame, slot);
758

759 760
    ra->RA_contention_resolution_cnt = -1;
    ra->RA_contention_resolution_timer_active = 0;
761
    mac->crnti = ra->t_crnti;
762
    ra->t_crnti = 0;
763 764 765 766 767 768 769

    LOG_D(MAC, "In %s: [UE %d][%d.%d] CB-RA: cleared contention resolution timer...\n", __FUNCTION__, mod_id, frame, slot);

  }

  LOG_D(MAC, "In %s: [UE %d] clearing RA_active flag...\n", __FUNCTION__, mod_id);
  ra->RA_active = 0;
770
  ra->generate_nr_prach = GENERATE_IDLE;
771 772 773 774 775 776 777 778 779 780 781 782
  ra->ra_state = RA_SUCCEEDED;

}

// Handlig failure of RA procedure @ MAC layer
// according to section 5 of 3GPP TS 38.321 version 16.2.1 Release 16
// todo:
// - complete handling of received contention-based RA preamble
// - 2-step RA implementation
void nr_ra_failed(uint8_t mod_id, uint8_t CC_id, NR_PRACH_RESOURCES_t *prach_resources, frame_t frame, int slot) {

  NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
783
  RA_config_t *ra = &mac->ra;
784

785
  ra->first_Msg3 = 1;
786
  ra->ra_PreambleIndex     = -1;
787
  ra->generate_nr_prach = RA_FAILED;
788
  ra->ra_state = RA_UE_IDLE;
789 790 791 792 793

  prach_resources->RA_PREAMBLE_TRANSMISSION_COUNTER++;

  if(prach_resources->RA_TYPE == RA_4STEP){

794
    if (prach_resources->RA_PREAMBLE_TRANSMISSION_COUNTER == ra->preambleTransMax + 1){
795

796
      LOG_D(MAC, "In %s: [UE %d][%d.%d] Maximum number of RACH attempts (%d) reached, selecting backoff time...\n", __FUNCTION__, mod_id, frame, slot, ra->preambleTransMax);
797

798
      ra->RA_backoff_cnt = rand() % (prach_resources->RA_PREAMBLE_BACKOFF + 1);
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817

      prach_resources->RA_PREAMBLE_TRANSMISSION_COUNTER = 1;
      prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP += 2; // 2 dB increment
      prach_resources->ra_PREAMBLE_RECEIVED_TARGET_POWER = nr_get_Po_NOMINAL_PUSCH(prach_resources, mod_id, CC_id);

    } else {

      // Resetting RA window
      nr_get_RA_window(mac);

    }

  } else if (prach_resources->RA_TYPE == RA_2STEP){

    LOG_E(MAC, "Missing implementation of RA failure handling for 2-step RA...\n");

  }

}