diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h index 143d4623d70f51419369374dd31c77ab83954dcb..a83c85dd254b6b3017a8343bc94ea8c912daa470 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h @@ -461,36 +461,6 @@ typedef struct { #define NR_MAX_NUM_LCGID 8 #define MAX_RLC_SDU_SUBHEADER_SIZE 3 -//=========== -// PRACH defs -//=========== - -// =============================================== -// SSB to RO mapping public defines and structures -// =============================================== -#define MAX_SSB_PER_RO (16) // Maximum number of SSBs that can be mapped to a single RO -#define MAX_TDM (7) // Maximum nb of PRACH occasions TDMed in a slot -#define MAX_FDM (8) // Maximum nb of PRACH occasions FDMed in a slot - -// PRACH occasion details -typedef struct prach_occasion_info { - uint8_t start_symbol; // 0 - 13 (14 symbols in a slot) - uint8_t fdm; // 0-7 (possible values of msg1-FDM: 1, 2, 4 or 8) - uint8_t slot; // 0 - 159 (maximum number of slots in a 10ms frame - @ 240kHz) - uint8_t frame; // 0 - 15 (maximum number of frames in a 160ms association pattern) - uint8_t mapped_ssb_idx[MAX_SSB_PER_RO]; // List of mapped SSBs - uint8_t nb_mapped_ssb; - uint16_t format; // RO preamble format -} prach_occasion_info_t; - -// PRACH occasion slot details -// A PRACH occasion slot is a series of PRACH occasions in time (symbols) and frequency -typedef struct prach_occasion_slot { - prach_occasion_info_t *prach_occasion; // Starting symbol of each PRACH occasions in a slot - uint8_t nb_of_prach_occasion_in_time; - uint8_t nb_of_prach_occasion_in_freq; -} prach_occasion_slot_t; - //========= // DCI defs //========= diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index fd3fb5e8e4e0ccef661c03215d09fa5fb5a086f7..2da3d9df93c8d95b774268293873ea6471c5d2b6 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -1579,6 +1579,7 @@ nr_prach_info_t get_nr_prach_occasion_info_from_index(uint8_t index, frequency_r if (unpaired) { // FR1 TDD info.x = table_6_3_3_2_3_prachConfig_Index[index][2]; info.y = table_6_3_3_2_3_prachConfig_Index[index][3]; + info.y2 = -1; info.s_map = table_6_3_3_2_3_prachConfig_Index[index][4]; info.N_RA_sfn += count_bits64(info.s_map); info.N_RA_slot = table_6_3_3_2_3_prachConfig_Index[index][6]; @@ -1604,6 +1605,7 @@ nr_prach_info_t get_nr_prach_occasion_info_from_index(uint8_t index, frequency_r // FR1 FDD info.x = table_6_3_3_2_2_prachConfig_Index[index][2]; info.y = table_6_3_3_2_2_prachConfig_Index[index][3]; + info.y2 = -1; info.s_map = table_6_3_3_2_2_prachConfig_Index[index][4]; info.N_RA_sfn += count_bits64(info.s_map); info.N_RA_slot = table_6_3_3_2_2_prachConfig_Index[index][6]; diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index 4a34fd3a5f28c2727dfbc33af26fa815ddd7b418..4dc295acf3c2590b1938d494090c15c02ac3338b 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -169,6 +169,34 @@ UE_STATE(UE_CONNECTED) \ UE_STATE(UE_DETACHING) +// =============================================== +// SSB to RO mapping public defines and structures +// =============================================== +#define MAX_SSB_PER_RO (16) // Maximum number of SSBs that can be mapped to a single RO +#define MAX_TDM (7) // Maximum nb of PRACH occasions TDMed in a slot +#define MAX_FDM (8) // Maximum nb of PRACH occasions FDMed in a slot + +// PRACH occasion details +typedef struct prach_occasion_info { + int start_symbol; // 0 - 13 (14 symbols in a slot) + int fdm; // 0-7 (possible values of msg1-FDM: 1, 2, 4 or 8) + int slot; + int frame; // 0 - 15 (maximum number of frames in a 160ms association pattern) + uint8_t mapped_ssb_idx[MAX_SSB_PER_RO]; // List of mapped SSBs + uint8_t nb_mapped_ssb; + int format; // RO preamble format + int frame_info[2]; + int association_period_idx; +} prach_occasion_info_t; + +// PRACH occasion slot details +// A PRACH occasion slot is a series of PRACH occasions in time (symbols) and frequency +typedef struct prach_occasion_slot { + prach_occasion_info_t *prach_occasion; // Starting symbol of each PRACH occasions in a slot + uint8_t nb_of_prach_occasion_in_time; + uint8_t nb_of_prach_occasion_in_freq; +} prach_occasion_slot_t; + typedef enum { phr_cause_prohibit_timer = 0, phr_cause_periodic_timer, @@ -292,6 +320,11 @@ typedef struct { int Pc_max; } NR_PRACH_RESOURCES_t; +typedef struct{ + float ssb_per_ro; + int preambles_per_ssb; +} ssb_ro_preambles_t; + typedef struct { bool active; uint32_t preamble_index; @@ -333,7 +366,7 @@ typedef struct { uint8_t ssb_nb_in_ro; int zeroCorrelationZoneConfig; int restricted_set_config; - // selected SSB for RACH + // selected SSB for RACH (not the SSB-Index but the cumulative index, excluding not trasmitted SSBs) int ra_ssb; /// Random-access window counter int16_t RA_window_cnt; @@ -368,6 +401,11 @@ typedef struct { NR_pdcch_order_config_t pdcch_order; NR_PRACH_RESOURCES_t prach_resources; + + ssb_ro_preambles_t ssb_ro_config; + int association_periods; + prach_occasion_info_t sched_ro_info; + int ro_mask_index; } RA_config_t; typedef struct { diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c index 903b740f10f0acf1bd320d3f63b68ddd98bfff92..039788b62ef1945e1490c5dcf72b796ae345858b 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c @@ -191,25 +191,20 @@ static void select_preamble_group(NR_UE_MAC_INST_t *mac) // else if Msg3 is being retransmitted, we keep what used in first transmission of Msg3 } -typedef struct{ - float ssb_per_ro; - int preambles_per_ssb; -} ssb_ro_preambles_t; - static ssb_ro_preambles_t get_ssb_ro_preambles_4step(struct NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB *config) { ssb_ro_preambles_t ret = {0}; switch (config->present) { case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_oneEighth: - ret.ssb_per_ro = 1 / 8; + ret.ssb_per_ro = 0.125; ret.preambles_per_ssb = (config->choice.oneEighth + 1) << 2; break; case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_oneFourth: - ret.ssb_per_ro = 1 / 4; + ret.ssb_per_ro = 0.25; ret.preambles_per_ssb = (config->choice.oneFourth + 1) << 2; break; case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_oneHalf: - ret.ssb_per_ro = 1 / 2; + ret.ssb_per_ro = 0.5; ret.preambles_per_ssb = (config->choice.oneHalf + 1) << 2; break; case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_one: @@ -235,6 +230,7 @@ static ssb_ro_preambles_t get_ssb_ro_preambles_4step(struct NR_RACH_ConfigCommon default: AssertFatal(false, "Invalid ssb_perRACH_OccasionAndCB_PreamblesPerSSB\n"); } + LOG_D(NR_MAC, "SSB per RO %f preambles per SSB %d\n", ret.ssb_per_ro, ret.preambles_per_ssb); return ret; } @@ -243,15 +239,15 @@ static ssb_ro_preambles_t get_ssb_ro_preambles_2step(struct NR_RACH_ConfigCommon ssb_ro_preambles_t ret = {0}; switch (config->present) { case NR_RACH_ConfigCommonTwoStepRA_r16__msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16_PR_oneEighth : - ret.ssb_per_ro = 1 / 8; + ret.ssb_per_ro = 0.125; ret.preambles_per_ssb = (config->choice.oneEighth + 1) << 2; break; case NR_RACH_ConfigCommonTwoStepRA_r16__msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16_PR_oneFourth : - ret.ssb_per_ro = 1 / 4; + ret.ssb_per_ro = 0.25; ret.preambles_per_ssb = (config->choice.oneFourth + 1) << 2; break; case NR_RACH_ConfigCommonTwoStepRA_r16__msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16_PR_oneHalf : - ret.ssb_per_ro = 1 / 2; + ret.ssb_per_ro = 0.5; ret.preambles_per_ssb = (config->choice.oneHalf + 1) << 2; break; case NR_RACH_ConfigCommonTwoStepRA_r16__msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16_PR_one : @@ -294,14 +290,13 @@ static void config_preamble_index(NR_UE_MAC_INST_t *mac) } NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = mac->current_UL_BWP->rach_ConfigCommon; - ssb_ro_preambles_t config_info; int nb_of_preambles = 64; bool groupBconfigured = false; int preamb_ga = 0; if (ra->ra_type == RA_4_STEP) { AssertFatal(nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB, "Not expeting ssb_perRACH_OccasionAndCB_PreamblesPerSSB to be NULL here\n"); - config_info = get_ssb_ro_preambles_4step(nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB); + ra->ssb_ro_config = get_ssb_ro_preambles_4step(nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB); if (nr_rach_ConfigCommon->totalNumberOfRA_Preambles) nb_of_preambles = *nr_rach_ConfigCommon->totalNumberOfRA_Preambles; // Amongst the contention-based Random Access Preambles associated with an SSB the first numberOfRA-PreamblesGroupA @@ -325,9 +320,9 @@ static void config_preamble_index(NR_UE_MAC_INST_t *mac) // configuration by msgA-SSB-PerRACH-OccasionAndCB-PreamblesPerSSB when provided; // otherwise, by ssb-perRACH-OccasionAndCB-PreamblesPerSSB if (twostep->msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16) - config_info = get_ssb_ro_preambles_2step(twostep->msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16); + ra->ssb_ro_config = get_ssb_ro_preambles_2step(twostep->msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16); else - config_info = get_ssb_ro_preambles_4step(nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB); + ra->ssb_ro_config = get_ssb_ro_preambles_4step(nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB); if (twostep->msgA_TotalNumberOfRA_Preambles_r16) nb_of_preambles = *twostep->msgA_TotalNumberOfRA_Preambles_r16; } @@ -342,12 +337,12 @@ static void config_preamble_index(NR_UE_MAC_INST_t *mac) nb_of_preambles = preamb_ga; } } - int rand_preamb = (rand_r(&seed) % config_info.preambles_per_ssb); - if (config_info.ssb_per_ro < 1) + int rand_preamb = (rand_r(&seed) % ra->ssb_ro_config.preambles_per_ssb); + if (ra->ssb_ro_config.ssb_per_ro < 1) ra->ra_PreambleIndex = groupOffset + rand_preamb; else { - int ssb_pr_idx = mac->ssb_list.nb_ssb_per_index[ra->ra_ssb] % (int)config_info.ssb_per_ro; - ra->ra_PreambleIndex = groupOffset + (ssb_pr_idx * config_info.preambles_per_ssb) + rand_preamb; + int ssb_pr_idx = mac->ssb_list.nb_ssb_per_index[mac->mib_ssb] % (int)ra->ssb_ro_config.ssb_per_ro; + ra->ra_PreambleIndex = groupOffset + (ssb_pr_idx * ra->ssb_ro_config.preambles_per_ssb) + rand_preamb; } AssertFatal(ra->ra_PreambleIndex < nb_of_preambles, "Error! Selected preamble %d which exceeds number of prambles available %d\n", @@ -359,7 +354,8 @@ static void config_preamble_index(NR_UE_MAC_INST_t *mac) static void ra_resource_selection(NR_UE_MAC_INST_t *mac) { RA_config_t *ra = &mac->ra; - ra->ra_ssb = -1; // init as not selected + int ssb = -1; // init as not selected + ra->ro_mask_index = -1; // init as not selected NR_RACH_ConfigDedicated_t *rach_ConfigDedicated = ra->rach_ConfigDedicated; if (ra->ra_type == RA_4_STEP) { // TODO if the Random Access procedure was initiated for SpCell beam failure recovery @@ -369,7 +365,8 @@ static void ra_resource_selection(NR_UE_MAC_INST_t *mac) // set the PREAMBLE_INDEX to the signalled ra-PreambleIndex; ra->ra_PreambleIndex = ra->pdcch_order.preamble_index; // select the SSB signalled by PDCCH - ra->ra_ssb = ra->pdcch_order.ssb_index; + ssb = ra->pdcch_order.ssb_index; + ra->ro_mask_index = ra->pdcch_order.prach_mask; } else if (rach_ConfigDedicated && rach_ConfigDedicated->cfra) { NR_CFRA_t *cfra = rach_ConfigDedicated->cfra; AssertFatal(cfra->occasions == NULL, "Dedicated PRACH occasions for CFRA not supported\n"); @@ -379,16 +376,17 @@ static void ra_resource_selection(NR_UE_MAC_INST_t *mac) NR_CFRA_SSB_Resource_t *res = ssb_list->ssb_ResourceList.list.array[i]; // TODO select an SSB with SS-RSRP above rsrp-ThresholdSSB amongst the associated SSBs if (res->ssb == mac->mib_ssb) { - ra->ra_ssb = mac->mib_ssb; + ssb = mac->mib_ssb; // set the PREAMBLE_INDEX to a ra-PreambleIndex corresponding to the selected SSB ra->ra_PreambleIndex = res->ra_PreambleIndex; + ra->ro_mask_index = ssb_list->ra_ssb_OccasionMaskIndex; break; } } } else { // for the contention-based Random Access preamble selection // TODO if at least one of the SSBs with SS-RSRP above rsrp-ThresholdSSB is available // else select any SSB - ra->ra_ssb = mac->mib_ssb; + ssb = mac->mib_ssb; config_preamble_index(mac); } } else { // 2-step RA @@ -402,19 +400,156 @@ static void ra_resource_selection(NR_UE_MAC_INST_t *mac) for (int i = 0; i < cfra->resourcesTwoStep_r16.ssb_ResourceList.list.count; i++) { NR_CFRA_SSB_Resource_t *res = cfra->resourcesTwoStep_r16.ssb_ResourceList.list.array[i]; if (res->ssb == mac->mib_ssb) { - ra->ra_ssb = mac->mib_ssb; + ssb = mac->mib_ssb; // set the PREAMBLE_INDEX to a ra-PreambleIndex corresponding to the selected SSB ra->ra_PreambleIndex = res->ra_PreambleIndex; + ra->ro_mask_index = cfra->resourcesTwoStep_r16.ra_ssb_OccasionMaskIndex; break; } } } else { // for the contention-based Random Access Preamble selection // TODO if at least one of the SSBs with SS-RSRP above msgA-RSRP-ThresholdSSB is available // else select any SSB - ra->ra_ssb = mac->mib_ssb; + ssb = mac->mib_ssb; config_preamble_index(mac); } } + AssertFatal(ra->ra_ssb >= 0, "Something wrong! RA resource selection didn't set any SSB\n"); + // setting the RA ssb value as the progressive number of SSB transmitted + // non-transmitted SSBs are not taken into account + ra->ra_ssb = mac->ssb_list.nb_ssb_per_index[ssb]; +} + +static bool check_mixed_slot_prach(frame_structure_t *fs, int slot, int start_prach, int end_prach) +{ + bool is_mixed = is_mixed_slot(slot, fs); + if (is_mixed) { + tdd_bitmap_t *bitmap = &fs->period_cfg.tdd_slot_bitmap[slot % fs->numb_slots_period]; + if (bitmap->num_ul_symbols == 0) + return false; + int ul_end = NR_NUMBER_OF_SYMBOLS_PER_SLOT - 1; + int ul_start = NR_NUMBER_OF_SYMBOLS_PER_SLOT - bitmap->num_ul_symbols; + if (start_prach < ul_start || end_prach > ul_end) + return false; + } + return true; +} + +static void select_prach_occasion(RA_config_t *ra, + int nb_tx_ssb, + int n, + prach_occasion_info_t ra_occasions_period[n], + int num_ra_occasions_period) +{ + unsigned int seed; + if (IS_SOFTMODEM_IQPLAYER || IS_SOFTMODEM_IQRECORDER) { + // Overwrite seed with non-random seed for IQ player/recorder + seed = 1; + } else { + // & to truncate the int64_t and keep only the LSB bits, up to sizeof(int) + seed = (unsigned int) (rdtsc_oai() & ~0); + } + + int num_ros_per_ssb = 0; + int idx_ssb = 0; + int temp_idx = 0; + if (ra->ssb_ro_config.ssb_per_ro < 1) { + num_ros_per_ssb = (int) (1 / ra->ssb_ro_config.ssb_per_ro); + idx_ssb = (rand_r(&seed) % num_ros_per_ssb); + temp_idx = ra->ra_ssb * num_ros_per_ssb + idx_ssb; + } else { + int ssb_per_ro = nb_tx_ssb < ra->ssb_ro_config.ssb_per_ro ? nb_tx_ssb : ra->ssb_ro_config.ssb_per_ro; + num_ros_per_ssb = ra->association_periods * ssb_per_ro * num_ra_occasions_period / nb_tx_ssb; + idx_ssb = (rand_r(&seed) % num_ros_per_ssb); + int eq_ssb = ra->ra_ssb + (idx_ssb * nb_tx_ssb); + temp_idx = eq_ssb / ra->ssb_ro_config.ssb_per_ro; + } + int ro_index = temp_idx % num_ra_occasions_period; + int ass_period_idx = temp_idx / num_ra_occasions_period; + ra->sched_ro_info = ra_occasions_period[ro_index]; + ra->sched_ro_info.association_period_idx = ass_period_idx; +} + +static void configure_prach_occasions(NR_UE_MAC_INST_t *mac, int prach_config_index, int num_fd_occasions, int scs) +{ + RA_config_t *ra = &mac->ra; + int num_ra_occasions_period = 0; + frame_structure_t *fs = &mac->frame_structure; + nr_prach_info_t prach_info = get_nr_prach_occasion_info_from_index(prach_config_index, mac->frequency_range, fs->frame_type); + int max_num_occasions = prach_info.N_RA_sfn * prach_info.N_t_slot * prach_info.N_RA_slot * num_fd_occasions; + prach_occasion_info_t ra_occasions_period[max_num_occasions]; + // Number of PRACH slots within a subframe (or 60kHz slot) to be taken into account only for 30 and 120kHz + // as defined in 5.3.2 of 211 + int prach_slots_in_sf = (scs == 1 || scs == 3) ? prach_info.N_RA_slot : 1; + uint64_t temp_s_map = prach_info.s_map; + int n_frames = prach_info.y2 == -1 ? 1 : 2; + for (int n = 0; n < n_frames; n++) { + int sf = 0; + for (int s = 0; s < prach_info.N_RA_sfn; s++) { // subframe/60kHz slot occasions in period + while (((temp_s_map >> sf) & 0x01) == 0) + sf++; + int sl = sf; + for (int i = 0; i < prach_slots_in_sf; i++) { // slot per subframe/60kHz slot + int add_slot = i; + if (scs == 1 || scs == 3) { + sl *= 2; + // if only 1 slot per subframe (or 60kHz slot) in case of 30 or 120kHz it's the odd one + // as defined in 5.3.2 of 211 + if (prach_slots_in_sf == 1) + add_slot = 1; + } + int slot = sl + add_slot; + if (!is_ul_slot(slot, fs)) + continue; // valid PRACH occasion only if slot is UL + for (int t = 0; t < prach_info.N_t_slot; t++) { // td occasions within a slot + int start_symbol = prach_info.start_symbol + t * prach_info.N_dur; + int end_symbol = start_symbol + prach_info.N_dur; + // valid occasion only if PRACH symbols are UL symbols in mixed slot + if (fs->frame_type == TDD && !check_mixed_slot_prach(fs, slot, start_symbol, end_symbol)) + continue; + for (int f = 0; f < num_fd_occasions; f++) { // fd occasions + ra_occasions_period[num_ra_occasions_period] = (prach_occasion_info_t) { + .slot = slot, + .frame_info[0] = prach_info.x, + .frame_info[1] = n == 0 ? prach_info.y : prach_info.y2, + .start_symbol = start_symbol, + .fdm = f, + .format = prach_info.format}; + LOG_D(NR_MAC, + "RA occasion %d: slot %d start symbol %d fd occasion %d\n", + num_ra_occasions_period, + slot, + start_symbol, + f); + num_ra_occasions_period++; + } + } + } + sf++; + } + } + + int config_period = prach_info.x; // configuration period + ra->association_periods = 1; + int nb_eq_ssb = mac->ssb_list.nb_tx_ssb; + if (ra->ssb_ro_config.ssb_per_ro < 1) + nb_eq_ssb *= (int) (1 / ra->ssb_ro_config.ssb_per_ro); + int nb_eq_ro = num_ra_occasions_period; + if (ra->ssb_ro_config.ssb_per_ro > 1) + nb_eq_ro *= (int) ra->ssb_ro_config.ssb_per_ro; + while (nb_eq_ssb > nb_eq_ro) { + // not enough PRACH occasions -> need to increase association period + ra->association_periods <<= 1; + AssertFatal(ra->association_periods * config_period <= 16, + "Cannot find an association period for %d SSB and %d RO with %f SSB per RO\n", + mac->ssb_list.nb_tx_ssb, + num_ra_occasions_period, + ra->ssb_ro_config.ssb_per_ro); + nb_eq_ro <<= 1; // doubling the association period -> doubling ROs + } + LOG_D(NR_MAC, "PRACH configuration period %d association period %d\n", config_period, ra->association_periods); + + select_prach_occasion(ra, mac->ssb_list.nb_tx_ssb, max_num_occasions, ra_occasions_period, num_ra_occasions_period); } // Random Access procedure initialization as per 5.1.1 and initialization of variables specific @@ -639,6 +774,21 @@ bool init_RA(NR_UE_MAC_INST_t *mac, int frame) ra->RA_backoff_cnt = 0; ra->RA_window_cnt = -1; + int ra_config_index = 0; + if (ra->ra_type == RA_2_STEP && twostep_generic && twostep_generic->msgA_PRACH_ConfigurationIndex_r16) + ra_config_index = *twostep_generic->msgA_PRACH_ConfigurationIndex_r16; + else { + if (rach_ConfigGeneric->ext1 && rach_ConfigGeneric->ext1->prach_ConfigurationIndex_v1610) + ra_config_index = *rach_ConfigGeneric->ext1->prach_ConfigurationIndex_v1610; + else + ra_config_index = rach_ConfigGeneric->prach_ConfigurationIndex; + } + int fdm = 0; + if (ra->ra_type == RA_2_STEP && twostep_generic && twostep_generic->msgA_RO_FDM_r16) + fdm = 1 << *twostep_generic->msgA_RO_FDM_r16; + else + fdm = 1 << rach_ConfigGeneric->msg1_FDM; + configure_prach_occasions(mac, ra_config_index, fdm, prach_scs); return true; }