diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index ee0c226af4..79fdb4c0d1 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -333,6 +333,8 @@ typedef struct { uint8_t ssb_nb_in_ro; int zeroCorrelationZoneConfig; int restricted_set_config; + // selected SSB for RACH + int ra_ssb; /// Random-access window counter int16_t RA_window_cnt; /// Flag to monitor if matching RAPID was received in RAR @@ -341,25 +343,21 @@ typedef struct { uint8_t RA_BI_found; /// Random-access backoff counter int16_t RA_backoff_indicator; - /// Flag to indicate whether preambles Group A was used - uint8_t RA_usedGroupA; + /// Flag to indicate whether preambles Group A is selected + bool RA_GroupA; /// RA backoff counter int16_t RA_backoff_cnt; /// RA max number of preamble transmissions int preambleTransMax; - /// Nb of preambles per SSB - long cb_preambles_per_ssb; - int starting_preamble_nb; - /// Received TPC command (in dB) from RAR int8_t Msg3_TPC; - /// Flag to indicate whether it is the first Msg3 to be transmitted - bool first_Msg3; /// RA Msg3 size in bytes uint8_t Msg3_size; /// Msg3 buffer uint8_t *Msg3_buffer; - + // initial Random Access Preamble power + int preambleRxTargetPower; + int deltaPreamble; bool msg3_C_RNTI; /// Random-access Contention Resolution Timer diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index b0627c7bec..724ef743ba 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -321,18 +321,6 @@ void nr_get_RA_window(NR_UE_MAC_INST_t *mac); @returns indication to generate PRACH to phy */ void nr_ue_manage_ra_procedure(NR_UE_MAC_INST_t *mac, int CC_id, frame_t frame, uint8_t gNB_id, int nr_slot_tx); -/* \brief Function implementing the routine for the selection of Random Access resources (5.1.2 TS 38.321). -@param mac pointer to MAC instance -@param CC_id Component Carrier Index -@param gNB_index gNB index -@param rach_ConfigDedicated -@returns void */ -void nr_get_prach_resources(NR_UE_MAC_INST_t *mac, - int CC_id, - uint8_t gNB_id, - NR_PRACH_RESOURCES_t *prach_resources, - NR_RACH_ConfigDedicated_t * rach_ConfigDedicated); - void prepare_msg4_msgb_feedback(NR_UE_MAC_INST_t *mac, int pid, int ack_nack); void configure_initial_pucch(PUCCH_sched_t *pucch, int res_ind); void release_PUCCH_SRS(NR_UE_MAC_INST_t *mac); diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c index 1a46e65eb2..229a977be2 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c @@ -40,7 +40,6 @@ #include "openair2/LAYER2/RLC/rlc.h" #include "openair2/LAYER2/NR_MAC_UE/mac_defs.h" - int16_t get_prach_tx_power(NR_UE_MAC_INST_t *mac) { RA_config_t *ra = &mac->ra; @@ -90,10 +89,337 @@ static void set_preambleTransMax(RA_config_t *ra, long preambleTransMax) } } +static int get_Msg3SizeGroupA(long ra_Msg3SizeGroupA) +{ + int bits = 0; + switch (ra_Msg3SizeGroupA) { + case NR_RACH_ConfigCommon__groupBconfigured__ra_Msg3SizeGroupA_b56: + bits = 56; + break; + case NR_RACH_ConfigCommon__groupBconfigured__ra_Msg3SizeGroupA_b144: + bits = 144; + break; + case NR_RACH_ConfigCommon__groupBconfigured__ra_Msg3SizeGroupA_b208: + bits = 208; + break; + case NR_RACH_ConfigCommon__groupBconfigured__ra_Msg3SizeGroupA_b256: + bits = 256; + break; + case NR_RACH_ConfigCommon__groupBconfigured__ra_Msg3SizeGroupA_b282: + bits = 282; + break; + case NR_RACH_ConfigCommon__groupBconfigured__ra_Msg3SizeGroupA_b480: + bits = 480; + break; + case NR_RACH_ConfigCommon__groupBconfigured__ra_Msg3SizeGroupA_b640: + bits = 640; + break; + case NR_RACH_ConfigCommon__groupBconfigured__ra_Msg3SizeGroupA_b800: + bits = 800; + break; + case NR_RACH_ConfigCommon__groupBconfigured__ra_Msg3SizeGroupA_b1000: + bits = 1000; + break; + case NR_RACH_ConfigCommon__groupBconfigured__ra_Msg3SizeGroupA_b72: + bits = 72; + break; + default: + AssertFatal(false, "Unknown ra-Msg3SizeGroupA %lu\n", ra_Msg3SizeGroupA); + } + return bits / 8; // returning bytes +} + +static int get_messagePowerOffsetGroupB(long messagePowerOffsetGroupB) +{ + int pow_offset = 0; + switch (messagePowerOffsetGroupB) { + case NR_RACH_ConfigCommon__groupBconfigured__messagePowerOffsetGroupB_minusinfinity: + pow_offset = INT_MIN; + break; + case NR_RACH_ConfigCommon__groupBconfigured__messagePowerOffsetGroupB_dB0: + pow_offset = 0; + break; + case NR_RACH_ConfigCommon__groupBconfigured__messagePowerOffsetGroupB_dB5: + pow_offset = 5; + break; + case NR_RACH_ConfigCommon__groupBconfigured__messagePowerOffsetGroupB_dB8: + pow_offset = 8; + break; + case NR_RACH_ConfigCommon__groupBconfigured__messagePowerOffsetGroupB_dB10: + pow_offset = 10; + break; + case NR_RACH_ConfigCommon__groupBconfigured__messagePowerOffsetGroupB_dB12: + pow_offset = 12; + break; + case NR_RACH_ConfigCommon__groupBconfigured__messagePowerOffsetGroupB_dB15: + pow_offset = 15; + break; + case NR_RACH_ConfigCommon__groupBconfigured__messagePowerOffsetGroupB_dB18: + pow_offset = 18; + break; + default: + AssertFatal(false, "Unknown messagePowerOffsetGroupB %lu\n", messagePowerOffsetGroupB); + } + return pow_offset; +} + +static void select_preamble_group(NR_UE_MAC_INST_t *mac) +{ + RA_config_t *ra = &mac->ra; + // TODO if the RA_TYPE is switched from 2-stepRA to 4-stepRA + + if (!ra->Msg3_buffer) { // if Msg3 buffer is empty + NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = mac->current_UL_BWP->rach_ConfigCommon; + if (nr_rach_ConfigCommon && nr_rach_ConfigCommon->groupBconfigured) { // if Random Access Preambles group B is configured + struct NR_RACH_ConfigCommon__groupBconfigured *groupB = nr_rach_ConfigCommon->groupBconfigured; + // if the potential Msg3 size (UL data available for transmission plus MAC subheader(s) and, + // where required, MAC CEs) is greater than ra-Msg3SizeGroupA + // if the pathloss is less than PCMAX (of the Serving Cell performing the Random Access Procedure) + // – preambleReceivedTargetPower – msg3-DeltaPreamble – messagePowerOffsetGroupB + int groupB_pow_offset = get_messagePowerOffsetGroupB(groupB->messagePowerOffsetGroupB); + int PLThreshold = ra->prach_resources.Pc_max - ra->preambleRxTargetPower - ra->deltaPreamble - groupB_pow_offset; + int pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm); + // TODO if the Random Access procedure was initiated for the CCCH logical channel and the CCCH SDU size + // plus MAC subheader is greater than ra-Msg3SizeGroupA + if (ra->Msg3_size > get_Msg3SizeGroupA(groupB->ra_Msg3SizeGroupA) && pathloss < PLThreshold) + ra->RA_GroupA = false; + else + ra->RA_GroupA = true; + } else + ra->RA_GroupA = true; + } + // 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.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.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.preambles_per_ssb = (config->choice.oneHalf + 1) << 2; + break; + case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_one: + ret.ssb_per_ro = 1; + ret.preambles_per_ssb = (config->choice.one + 1) << 2; + break; + case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_two: + ret.ssb_per_ro = 2; + ret.preambles_per_ssb = (config->choice.two + 1) << 2; + break; + case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_four: + ret.ssb_per_ro = 4; + ret.preambles_per_ssb = config->choice.four; + break; + case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_eight: + ret.ssb_per_ro = 8; + ret.preambles_per_ssb = config->choice.eight; + break; + case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_sixteen: + ret.ssb_per_ro = 16; + ret.preambles_per_ssb = config->choice.sixteen; + break; + default: + AssertFatal(false, "Invalid ssb_perRACH_OccasionAndCB_PreamblesPerSSB\n"); + } + return ret; +} + +static ssb_ro_preambles_t get_ssb_ro_preambles_2step(struct NR_RACH_ConfigCommonTwoStepRA_r16__msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16 *config) +{ + 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.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.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.preambles_per_ssb = (config->choice.oneHalf + 1) << 2; + break; + case NR_RACH_ConfigCommonTwoStepRA_r16__msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16_PR_one : + ret.ssb_per_ro = 1; + ret.preambles_per_ssb = (config->choice.one + 1) << 2; + break; + case NR_RACH_ConfigCommonTwoStepRA_r16__msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16_PR_two : + ret.ssb_per_ro = 2; + ret.preambles_per_ssb = (config->choice.two + 1) << 2; + break; + case NR_RACH_ConfigCommonTwoStepRA_r16__msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16_PR_four : + ret.ssb_per_ro = 4; + ret.preambles_per_ssb = config->choice.four; + break; + case NR_RACH_ConfigCommonTwoStepRA_r16__msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16_PR_eight : + ret.ssb_per_ro = 8; + ret.preambles_per_ssb = config->choice.eight; + break; + case NR_RACH_ConfigCommonTwoStepRA_r16__msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16_PR_sixteen : + ret.ssb_per_ro = 16; + ret.preambles_per_ssb = config->choice.sixteen; + break; + default : + AssertFatal(false, "Invalid msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16\n"); + } + return ret; +} + +static void config_preamble_index(NR_UE_MAC_INST_t *mac) +{ + RA_config_t *ra = &mac->ra; + // Random seed generation + 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); + } + + 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); + 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 + // included in groupBconfigured Random Access Preambles belong to Random Access Preambles group A. + // The remaining Random Access Preambles associated with the SSB belong to Random Access Preambles group B (if configured) + select_preamble_group(mac); + if (nr_rach_ConfigCommon->groupBconfigured) { + groupBconfigured = true; + preamb_ga = nr_rach_ConfigCommon->groupBconfigured->numberOfRA_PreamblesGroupA; + } + } else { + NR_RACH_ConfigCommonTwoStepRA_r16_t *twostep = &mac->current_UL_BWP->msgA_ConfigCommon_r16->rach_ConfigCommonTwoStepRA_r16; + AssertFatal(twostep->groupB_ConfiguredTwoStepRA_r16 == NULL, "GroupB preambles not supported for 2-step RA\n"); + ra->RA_GroupA = true; + // The field is mandatory present if the 2-step random access type occasions are shared with 4-step random access type, + // otherwise the field is not present + bool sharedROs = twostep->msgA_CB_PreamblesPerSSB_PerSharedRO_r16 != NULL; + AssertFatal(sharedROs == false, "Shared ROs between 2- and 4-step RA not supported\n"); + + // For Type-2 random access procedure with separate configuration of PRACH occasions with Type-1 random access procedure + // 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); + else + config_info = 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; + } + + int groupOffset = 0; + if (groupBconfigured) { + AssertFatal(preamb_ga < nb_of_preambles, "Nb of preambles for groupA not compatible with total number of preambles\n"); + if (!ra->RA_GroupA) { // groupB + groupOffset = preamb_ga; + nb_of_preambles = nb_of_preambles - preamb_ga; + } else { + nb_of_preambles = preamb_ga; + } + } + int rand_preamb = (rand_r(&seed) % config_info.preambles_per_ssb); + if (config_info.ssb_per_ro < 1) + ra->ra_PreambleIndex = groupOffset + rand_preamb; + else { + ssb_list_info_t *ssb_list = &mac->ssb_list[mac->current_DL_BWP->bwp_id]; + int ssb_pr_idx = 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; + } + AssertFatal(ra->ra_PreambleIndex < nb_of_preambles, + "Error! Selected preamble %d which exceeds number of prambles available %d\n", + ra->ra_PreambleIndex, + nb_of_preambles); +} + +// 38.321 Section 5.1.2 Random Access Resource selection +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 + 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 + // TODO if the Random Access procedure was initiated for SI request + + if (ra->pdcch_order.active && ra->pdcch_order.preamble_index != 0xb000000) { + // 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; + } 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"); + AssertFatal(cfra->resources.present == NR_CFRA__resources_PR_ssb, "SSB-based CFRA supported only\n"); + struct NR_CFRA__resources__ssb *ssb_list = cfra->resources.choice.ssb; + for (int i = 0; i < ssb_list->ssb_ResourceList.list.count; i++) { + 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; + // set the PREAMBLE_INDEX to a ra-PreambleIndex corresponding to the selected SSB + ra->ra_PreambleIndex = res->ra_PreambleIndex; + 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; + config_preamble_index(mac); + } + } else { // 2-step RA + // if the contention-free 2-step RA type Resources associated with SSBs have been explicitly provided in rach-ConfigDedicated + // TODO and at least one SSB with SS-RSRP above msgA-RSRP-ThresholdSSB amongst the associated SSBs is available + if (ra->cfra) { + AssertFatal(rach_ConfigDedicated->ext1 && rach_ConfigDedicated->ext1->cfra_TwoStep_r16, + "Two-step CFRA should be configured here\n"); + NR_CFRA_TwoStep_r16_t *cfra = rach_ConfigDedicated->ext1->cfra_TwoStep_r16; + AssertFatal(cfra->occasionsTwoStepRA_r16 == NULL, "Dedicated PRACH occasions for CFRA not supported\n"); + 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; + // set the PREAMBLE_INDEX to a ra-PreambleIndex corresponding to the selected SSB + ra->ra_PreambleIndex = res->ra_PreambleIndex; + 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; + config_preamble_index(mac); + } + } +} + // 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) bool init_RA(NR_UE_MAC_INST_t *mac, int frame) { RA_config_t *ra = &mac->ra; @@ -297,11 +623,20 @@ bool init_RA(NR_UE_MAC_INST_t *mac, int frame) // TODO msgA-TransMax not implemented // TODO ra-Prioritization not implemented - ra->ra_PreambleIndex = -1; - ra->RA_usedGroupA = 1; + if (ra->ra_type == RA_2_STEP && twostep_generic && twostep_generic->msgA_PreambleReceivedTargetPower_r16) + ra->preambleRxTargetPower = *twostep_generic->msgA_PreambleReceivedTargetPower_r16; + else + ra->preambleRxTargetPower = rach_ConfigGeneric->preambleReceivedTargetPower; + + if (ra->ra_type == RA_2_STEP + && current_UL_BWP->msgA_ConfigCommon_r16 + && current_UL_BWP->msgA_ConfigCommon_r16->msgA_PUSCH_Config_r16 + && current_UL_BWP->msgA_ConfigCommon_r16->msgA_PUSCH_Config_r16->msgA_DeltaPreamble_r16) + ra->deltaPreamble = *current_UL_BWP->msgA_ConfigCommon_r16->msgA_PUSCH_Config_r16->msgA_DeltaPreamble_r16 << 1; + else + ra->deltaPreamble = mac->current_UL_BWP->msg3_DeltaPreamble ? *mac->current_UL_BWP->msg3_DeltaPreamble << 1 : 0; + ra->RA_RAPID_found = 0; - ra->first_Msg3 = true; - ra->starting_preamble_nb = 0; ra->RA_backoff_cnt = 0; ra->RA_window_cnt = -1; @@ -309,15 +644,12 @@ bool init_RA(NR_UE_MAC_INST_t *mac, int frame) } /* TS 38.321 subclause 7.3 - return DELTA_PREAMBLE values in dB */ -static int8_t nr_get_DELTA_PREAMBLE(const NR_UE_MAC_INST_t *mac, int CC_id, uint16_t prach_format) +static int8_t nr_get_DELTA_PREAMBLE(const NR_UE_MAC_INST_t *mac, uint16_t prach_format) { const NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = mac->current_UL_BWP->rach_ConfigCommon; int prach_sequence_length = nr_rach_ConfigCommon->prach_RootSequenceIndex.present - 1; - AssertFatal(CC_id == 0, "Transmission on secondary CCs is not supported yet\n"); - // Preamble formats given by prach_ConfigurationIndex and tables 6.3.3.2-2 and 6.3.3.2-2 in TS 38.211 - unsigned int prachConfigIndex = nr_rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex; if (prach_sequence_length == 0) { @@ -343,37 +675,36 @@ static int8_t nr_get_DELTA_PREAMBLE(const NR_UE_MAC_INST_t *mac, int CC_id, uint } } else { // SCS configuration from msg1_SubcarrierSpacing and table 4.2-1 in TS 38.211 - AssertFatal(nr_rach_ConfigCommon->msg1_SubcarrierSpacing, "msg1_SubcarrierSpacing required but missing\n"); NR_SubcarrierSpacing_t scs = *nr_rach_ConfigCommon->msg1_SubcarrierSpacing; AssertFatal(scs >= NR_SubcarrierSpacing_kHz15 && scs <= NR_SubcarrierSpacing_spare1, "Unknown msg1_SubcarrierSpacing %lu\n", scs); const unsigned int mu = scs; - switch (prach_format) { // short preamble formats case 0: case 3: - return 8 + 3*mu; + return 8 + 3 * mu; case 1: case 4: case 8: - return 5 + 3*mu; + return 5 + 3 * mu; case 2: case 5: - return 3 + 3*mu; + return 3 + 3 * mu; case 6: - return 3*mu; + return 3 * mu; case 7: - return 5 + 3*mu; + return 5 + 3 * mu; default: - AssertFatal(1 == 0, "[UE %d] ue_procedures.c: FATAL, Illegal preambleFormat %d, prachConfigIndex %d\n", - mac->ue_id, - prach_format, - prachConfigIndex); + AssertFatal(false, + "[UE %d] ue_procedures.c: FATAL, Illegal preambleFormat %d, prachConfigIndex %d\n", + mac->ue_id, + prach_format, + prachConfigIndex); } } return 0; @@ -386,14 +717,14 @@ static int8_t nr_get_DELTA_PREAMBLE(const NR_UE_MAC_INST_t *mac, int CC_id, uint // - RA_PREAMBLE_POWER_RAMPING_STEP dB // - POWER_OFFSET_2STEP_RA dB // returns receivedTargerPower in dBm -static int nr_get_Po_NOMINAL_PUSCH(NR_UE_MAC_INST_t *mac, NR_PRACH_RESOURCES_t *prach_resources, uint8_t CC_id) +static int nr_get_Po_NOMINAL_PUSCH(NR_UE_MAC_INST_t *mac, NR_PRACH_RESOURCES_t *prach_resources) { int8_t receivedTargerPower; int8_t delta_preamble; NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = mac->current_UL_BWP->rach_ConfigCommon; long preambleReceivedTargetPower = nr_rach_ConfigCommon->rach_ConfigGeneric.preambleReceivedTargetPower; - delta_preamble = nr_get_DELTA_PREAMBLE(mac, CC_id, prach_resources->prach_format); + delta_preamble = nr_get_DELTA_PREAMBLE(mac, prach_resources->prach_format); receivedTargerPower = preambleReceivedTargetPower + delta_preamble + @@ -404,220 +735,6 @@ static int nr_get_Po_NOMINAL_PUSCH(NR_UE_MAC_INST_t *mac, NR_PRACH_RESOURCES_t * return receivedTargerPower; } -void ssb_rach_config(RA_config_t *ra, NR_PRACH_RESOURCES_t *prach_resources, NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon) -{ - // Determine the SSB to RACH mapping ratio - // ======================================= - - NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR ssb_perRACH_config = nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present; - bool 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; - - 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); - } - - if (nr_rach_ConfigCommon->totalNumberOfRA_Preambles) - numberOfRA_Preambles = *(nr_rach_ConfigCommon->totalNumberOfRA_Preambles); - - // 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 = ra->ssb_nb_in_ro; - ra->starting_preamble_nb = total_preambles_per_ssb * ssb_nb_in_ro; - } else { - total_preambles_per_ssb = numberOfRA_Preambles; - ra->starting_preamble_nb = 0; - } -} - -// This routine implements RA preamble configuration according to -// 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; - int PLThreshold = 0; - long deltaPreamble_Msg3 = 0; - uint8_t noGroupB = 0; - // Random seed generation - 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); - } - - RA_config_t *ra = &mac->ra; - NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon; - NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric; - - if (mac->current_UL_BWP->msg3_DeltaPreamble) { - deltaPreamble_Msg3 = (*mac->current_UL_BWP->msg3_DeltaPreamble) * 2; // dB - LOG_D(MAC, "In %s: deltaPreamble_Msg3 set to %ld\n", __FUNCTION__, deltaPreamble_Msg3); - } - - if (!setup->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 = setup->groupBconfigured->numberOfRA_PreamblesGroupA; - switch (setup->groupBconfigured->ra_Msg3SizeGroupA){ - /* - 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: - AssertFatal(1 == 0, "Unknown ra_Msg3SizeGroupA %lu\n", setup->groupBconfigured->ra_Msg3SizeGroupA); - /* todo cases 10 -15*/ - } - - /* Power offset for preamble selection in dB */ - messagePowerOffsetGroupB = -9999; - switch (setup->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", setup->groupBconfigured->messagePowerOffsetGroupB); - } - - PLThreshold = prach_resources->Pc_max - rach_ConfigGeneric->preambleReceivedTargetPower - deltaPreamble_Msg3 - messagePowerOffsetGroupB; - - } - - /* Msg3 has not been transmitted yet */ - if (ra->first_Msg3) { - if(ra->ra_PreambleIndex < 0 || ra->ra_PreambleIndex > 63) { - if (noGroupB) { - // use Group A preamble - ra->ra_PreambleIndex = ra->starting_preamble_nb + (rand_r(&seed) % 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 + (rand_r(&seed) % 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 + (rand_r(&seed) % (ra->cb_preambles_per_ssb - sizeOfRA_PreamblesGroupA)); - ra->RA_usedGroupA = 0; - } - } - } else { // Msg3 is being retransmitted - if (ra->RA_usedGroupA && noGroupB) { - ra->ra_PreambleIndex = ra->starting_preamble_nb + (rand_r(&seed) % ra->cb_preambles_per_ssb); - } else if (ra->RA_usedGroupA && !noGroupB){ - ra->ra_PreambleIndex = ra->starting_preamble_nb + (rand_r(&seed) % sizeOfRA_PreamblesGroupA); - } else { - ra->ra_PreambleIndex = ra->starting_preamble_nb + sizeOfRA_PreamblesGroupA + (rand_r(&seed) % (ra->cb_preambles_per_ssb - sizeOfRA_PreamblesGroupA)); - } - } -} - // 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 // - currently the PRACH preamble is set through RRC configuration for 4-step CFRA mode @@ -638,38 +755,13 @@ void ra_preambles_config(NR_PRACH_RESOURCES_t *prach_resources, NR_UE_MAC_INST_t // - 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 -void nr_get_prach_resources(NR_UE_MAC_INST_t *mac, - int CC_id, - uint8_t gNB_id, - NR_PRACH_RESOURCES_t *prach_resources, - NR_RACH_ConfigDedicated_t *rach_ConfigDedicated) +static void nr_get_prach_resources(NR_UE_MAC_INST_t *mac, + NR_PRACH_RESOURCES_t *prach_resources, + NR_RACH_ConfigDedicated_t *rach_ConfigDedicated) { - RA_config_t *ra = &mac->ra; - - NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = mac->current_UL_BWP->rach_ConfigCommon; - - LOG_D(MAC, "Getting PRACH resources (first_Msg3 %d)\n", ra->first_Msg3); - - if (rach_ConfigDedicated) { - if (rach_ConfigDedicated->cfra){ - uint8_t cfra_ssb_resource_idx = 0; - ra->ra_PreambleIndex = rach_ConfigDedicated->cfra->resources.choice.ssb->ssb_ResourceList.list.array[cfra_ssb_resource_idx]->ra_PreambleIndex; - LOG_D(MAC, "Selected RA preamble index %d for contention-free random access procedure for SSB with Id %d\n", - ra->ra_PreambleIndex, - cfra_ssb_resource_idx); - } - } else { - /* TODO: This controls the tx_power of UE and the ramping procedure of RA of UE. Later we - can abstract this, perhaps in the proxy. But for the time being lets leave it as below. */ - int16_t dl_pathloss = !get_softmodem_params()->emulate_l1 ? compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm) : 0; - ssb_rach_config(ra, prach_resources, nr_rach_ConfigCommon); - ra_preambles_config(prach_resources, mac, dl_pathloss); - LOG_D(MAC, "[RAPROC] - Selected RA preamble index %d for contention-based random access procedure... \n", ra->ra_PreambleIndex); - } - if (prach_resources->preamble_tx_counter > 1) prach_resources->preamble_power_ramping_cnt++; - prach_resources->ra_PREAMBLE_RECEIVED_TARGET_POWER = nr_get_Po_NOMINAL_PUSCH(mac, prach_resources, CC_id); + prach_resources->ra_PREAMBLE_RECEIVED_TARGET_POWER = nr_get_Po_NOMINAL_PUSCH(mac, prach_resources); } // TbD: RA_attempt_number not used @@ -790,6 +882,10 @@ void nr_ue_manage_ra_procedure(NR_UE_MAC_INST_t *mac, int CC_id, frame_t frame, bool init_success = init_RA(mac, frame); if (!init_success) return; + else { + // perform the Random Access Resource selection procedure (see clause 5.1.2 and .2a) + ra_resource_selection(mac); + } } LOG_D(NR_MAC, "[UE %d][%d.%d]: ra_state %d, RA_active %d\n", mac->ue_id, frame, nr_slot_tx, ra->ra_state, ra->RA_active); @@ -824,7 +920,7 @@ void nr_ue_manage_ra_procedure(NR_UE_MAC_INST_t *mac, int CC_id, frame_t frame, // Fill in preamble and PRACH resources ra->RA_window_cnt--; if (ra->ra_state == nrRA_GENERATE_PREAMBLE) { - nr_get_prach_resources(mac, CC_id, gNB_id, prach_resources, rach_ConfigDedicated); + nr_get_prach_resources(mac, prach_resources, rach_ConfigDedicated); } } else if (ra->RA_backoff_cnt > 0) { @@ -833,7 +929,7 @@ void nr_ue_manage_ra_procedure(NR_UE_MAC_INST_t *mac, int CC_id, frame_t frame, ra->RA_backoff_cnt--; if ((ra->RA_backoff_cnt > 0 && ra->ra_state == nrRA_GENERATE_PREAMBLE) || ra->RA_backoff_cnt == 0) { - nr_get_prach_resources(mac, CC_id, gNB_id, prach_resources, rach_ConfigDedicated); + nr_get_prach_resources(mac, prach_resources, rach_ConfigDedicated); } } } @@ -1016,10 +1112,9 @@ void nr_ra_failed(NR_UE_MAC_INST_t *mac, uint8_t CC_id, NR_PRACH_RESOURCES_t *pr seed = 1; } else { // & to truncate the int64_t and keep only the LSB bits, up to sizeof(int) - seed = (unsigned int) (rdtsc_oai() & ~0); + seed = (unsigned int)(rdtsc_oai() & ~0); } - ra->first_Msg3 = true; ra->ra_PreambleIndex = -1; ra->ra_state = nrRA_UE_IDLE; @@ -1041,7 +1136,7 @@ void nr_ra_failed(NR_UE_MAC_INST_t *mac, uint8_t CC_id, NR_PRACH_RESOURCES_t *pr ra->RA_backoff_cnt = rand_r(&seed) % (prach_resources->preamble_backoff + 1); prach_resources->preamble_tx_counter = 1; prach_resources->preamble_power_ramping_step += 2; // 2 dB increment - prach_resources->ra_PREAMBLE_RECEIVED_TARGET_POWER = nr_get_Po_NOMINAL_PUSCH(mac, prach_resources, CC_id); + prach_resources->ra_PREAMBLE_RECEIVED_TARGET_POWER = nr_get_Po_NOMINAL_PUSCH(mac, prach_resources); } else { nr_get_RA_window(mac); diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 0872787bd5..1bfdc034ee 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -2706,7 +2706,6 @@ static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t } } // if format1 - nr_get_prach_resources(mac, 0, 0, &ra->prach_resources, ra->rach_ConfigDedicated); pdu->prach_config_pdu.ra_PreambleIndex = ra->ra_PreambleIndex; pdu->prach_config_pdu.prach_tx_power = get_prach_tx_power(mac); unsigned int slot_RA; diff --git a/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_ra_procedures.cpp b/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_ra_procedures.cpp index 914d0ef984..6e8916f6f0 100644 --- a/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_ra_procedures.cpp +++ b/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_ra_procedures.cpp @@ -88,6 +88,7 @@ TEST(test_init_ra, four_step_cbra) NR_UE_DL_BWP_t dl_bwp; mac.current_UL_BWP = ¤t_bwp; mac.current_DL_BWP = &dl_bwp; + mac.mib_ssb = 0; long scs = 1; current_bwp.scs = scs; current_bwp.bwp_id = 0; @@ -122,6 +123,7 @@ TEST(test_init_ra, four_step_cfra) NR_UE_DL_BWP_t dl_bwp; mac.current_UL_BWP = ¤t_bwp; mac.current_DL_BWP = &dl_bwp; + mac.mib_ssb = 0; long scs = 1; current_bwp.scs = scs; current_bwp.bwp_id = 0; @@ -138,7 +140,7 @@ TEST(test_init_ra, four_step_cfra) int frame = 151; NR_RACH_ConfigDedicated_t rach_ConfigDedicated = {0}; - struct NR_CFRA cfra; + NR_CFRA_t cfra; rach_ConfigDedicated.cfra = &cfra; ra->rach_ConfigDedicated = &rach_ConfigDedicated; diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index f6dead1213..a6c2ae1c9c 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -3819,11 +3819,7 @@ NR_ReconfigurationWithSync_t *get_reconfiguration_with_sync(rnti_t rnti, uid_t u uplink->ra_Prioritization = NULL; uplink->cfra = calloc(1, sizeof(struct NR_CFRA)); uplink->cfra->ext1 = NULL; - uplink->cfra->occasions = calloc(1, sizeof(struct NR_CFRA__occasions)); - memcpy(&uplink->cfra->occasions->rach_ConfigGeneric, - &scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric, - sizeof(NR_RACH_ConfigGeneric_t)); - asn1cCallocOne(uplink->cfra->occasions->ssb_perRACH_Occasion, NR_CFRA__occasions__ssb_perRACH_Occasion_one); + uplink->cfra->occasions = NULL; uplink->cfra->resources.present = NR_CFRA__resources_PR_ssb; uplink->cfra->resources.choice.ssb = calloc(1, sizeof(struct NR_CFRA__resources__ssb)); uplink->cfra->resources.choice.ssb->ra_ssb_OccasionMaskIndex = 0;