diff --git a/ci-scripts/Jenkinsfile-GitLab-Container b/ci-scripts/Jenkinsfile-GitLab-Container index 37e6a0554b94b1fe032ee7e2cb2f027d2b26d746..3ad376f3da4b60ac4de36783874574b9436c1846 100644 --- a/ci-scripts/Jenkinsfile-GitLab-Container +++ b/ci-scripts/Jenkinsfile-GitLab-Container @@ -65,8 +65,8 @@ pipeline { message += " - ~BUILD-ONLY (execute only build stages)\n" message += " - ~4G-LTE (perform 4G tests)\n" message += " - ~5G-NR (perform 5G tests)\n" - message += " - ~CI (perform both 4G and 5G tests)\n\n" - message += " - ~nrUE (perform only 5G-UE related tests including physims excluding LDPC tests)\n" + message += " - ~CI (perform both 4G and 5G tests)\n" + message += " - ~nrUE (perform only 5G-UE related tests including physims excluding LDPC tests)\n\n" message += "Not performing CI due to lack of labels" addGitLabMRComment comment: message error('Not performing CI due to lack of labels') diff --git a/ci-scripts/cls_cluster.py b/ci-scripts/cls_cluster.py index 7293e252a16f3d2c60e54114ba1410e595c8afd5..bfa315b28ed250021541768a73bfdf86b6f96498 100644 --- a/ci-scripts/cls_cluster.py +++ b/ci-scripts/cls_cluster.py @@ -72,8 +72,8 @@ def OC_deploy_CN(cmd, ocUserName, ocPassword, ocNamespace, path): succeeded = OC_login(cmd, ocUserName, ocPassword, ocNamespace) if not succeeded: return False, CONST.OC_LOGIN_FAIL - cmd.run('helm uninstall oai5gcn --wait --timeout 60s') - ret = cmd.run(f'helm install --wait --timeout 120s oai5gcn {path}/ci-scripts/charts/oai-5g-basic/.') + cmd.run(f'helm list -aq -n {ocNamespace} | xargs -r helm uninstall -n {ocNamespace} --wait') + ret = cmd.run(f'helm install --wait oai5gcn {path}/ci-scripts/charts/oai-5g-basic/.') if ret.returncode != 0: logging.error('OC OAI CN5G: Deployment failed') OC_logout(cmd) @@ -100,10 +100,10 @@ def OC_undeploy_CN(cmd, ocUserName, ocPassword, ocNamespace, path): cmd.run(f'oc logs -f {podName} {ci} &> {path}/logs/{ii}.log &') cmd.run(f'cd {path}/logs && zip -r -qq test_logs_CN.zip *.log') cmd.copyin(f'{path}/logs/test_logs_CN.zip','test_logs_CN.zip') - ret = cmd.run('helm uninstall --wait --timeout 60s oai5gcn') + ret = cmd.run(f'helm list -aq -n {ocNamespace} | xargs -r helm uninstall -n {ocNamespace} --wait') if ret.returncode != 0: logging.error('OC OAI CN5G: Undeployment failed') - cmd.run('helm uninstall --wait --timeout 60s oai5gcn') + cmd.run(f'helm list -aq -n {ocNamespace} | xargs -r helm uninstall -n {ocNamespace} --wait') OC_logout(cmd) return False, CONST.OC_PROJECT_FAIL report = cmd.run('oc get pods') @@ -330,7 +330,7 @@ class Cluster: self._recreate_bc('ran-base', baseTag, 'openshift/ran-base-bc.yaml') ranbase_job = self._start_build('ran-base') attemptedImages += ['ran-base'] - status = ranbase_job is not None and self._wait_build_end([ranbase_job], 800) + status = ranbase_job is not None and self._wait_build_end([ranbase_job], 1000) if not status: logging.error('failure during build of ran-base') self.cmd.run(f'oc logs {ranbase_job} &> cmake_targets/log/ran-base.log') # cannot use cmd.run because of redirect # recover logs by mounting image @@ -392,7 +392,7 @@ class Cluster: gnb_aw2s_job = self._start_build('oai-gnb-aw2s') attemptedImages += ['oai-gnb-aw2s'] - wait = enb_job is not None and gnb_job is not None and gnb_aw2s_job is not None and self._wait_build_end([enb_job, gnb_job, gnb_aw2s_job], 600) + wait = enb_job is not None and gnb_job is not None and gnb_aw2s_job is not None and self._wait_build_end([enb_job, gnb_job, gnb_aw2s_job], 800) if not wait: logging.error('error during build of eNB/gNB') status = status and wait # recover logs @@ -421,7 +421,7 @@ class Cluster: nrue_job = self._start_build('oai-nr-ue') attemptedImages += ['oai-nr-ue'] - wait = nr_cuup_job is not None and lteue_job is not None and nrue_job is not None and self._wait_build_end([nr_cuup_job, lteue_job, nrue_job], 600) + wait = nr_cuup_job is not None and lteue_job is not None and nrue_job is not None and self._wait_build_end([nr_cuup_job, lteue_job, nrue_job], 800) if not wait: logging.error('error during build of nr-cuup/lteUE/nrUE') status = status and wait # recover logs diff --git a/ci-scripts/xml_files/container_5g_rfsim_24prb.xml b/ci-scripts/xml_files/container_5g_rfsim_24prb.xml index 5c2a0691220699b14fd6b8a34daafcc1e6b1c9a3..fe80891678ef72ee11ea908995a45039a93363b7 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_24prb.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_24prb.xml @@ -34,6 +34,9 @@ 020002 030001 030002 + 040001 + 000004 + 020002 100001 222222 </TestCaseRequestedList> @@ -76,6 +79,12 @@ <nodes>cacofonix</nodes> </testCase> + <testCase id="000004"> + <class>IdleSleep</class> + <desc>Sleep</desc> + <idle_sleep_time_in_sec>5</idle_sleep_time_in_sec> + </testCase> + <testCase id="020001"> <class>Ping</class> <desc>Ping ext-dn from NR-UE</desc> @@ -118,6 +127,14 @@ <iperf_bitrate_threshold>90</iperf_bitrate_threshold> </testCase> + <testCase id="040001"> + <class>Custom_Command</class> + <desc>Force Msg3 C-RNTI RA</desc> + <node>cacofonix</node> + <command>echo ciUE force_crnti_ra | nc 192.168.71.150 8091</command> + <command_fail>yes</command_fail> + </testCase> + <testCase id="100001"> <class>Undeploy_Object</class> <always_exec>true</always_exec> diff --git a/ci-scripts/yaml_files/5g_rfsimulator_24prb/docker-compose.yaml b/ci-scripts/yaml_files/5g_rfsimulator_24prb/docker-compose.yaml index ae74649a8309e191d375a63b41f55e31e940d618..2fd9a3e1fb8f00079770231e0e20a3e51cffffba 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_24prb/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_rfsimulator_24prb/docker-compose.yaml @@ -109,7 +109,10 @@ services: - NET_ADMIN # for interface bringup - NET_RAW # for ping environment: - USE_ADDITIONAL_OPTIONS: --rfsim -r 24 --ssb 24 --numerology 1 -C 3604800000 --uicc0.imsi 208990100001100 --rfsimulator.serveraddr 192.168.71.140 --log_config.global_log_options level,nocolor,time + USE_ADDITIONAL_OPTIONS: --rfsim -r 24 --ssb 24 --numerology 1 -C 3604800000 --uicc0.imsi 208990100001100 + --rfsimulator.serveraddr 192.168.71.140 --log_config.global_log_options level,nocolor,time + --telnetsrv --telnetsrv.shrmod ciUE --telnetsrv.listenaddr 192.168.71.150 --telnetsrv.listenport 8091 + ASAN_OPTIONS: detect_leaks=0:detect_odr_violation=0 depends_on: - oai-gnb networks: diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index 1d1e683dce4c0b675b913ce8878e6671508681b8..58c18bfd368bcf1dc5ee1fa75ea772d2993eacfd 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -1380,15 +1380,22 @@ int set_default_nta_offset(frequency_range_t freq_range, uint32_t samples_per_su void nr_timer_start(NR_timer_t *timer) { timer->active = true; + timer->suspended = false; timer->counter = 0; } void nr_timer_stop(NR_timer_t *timer) { timer->active = false; + timer->suspended = false; timer->counter = 0; } +void nr_timer_suspension(NR_timer_t *timer) +{ + timer->suspended = !timer->suspended; +} + bool nr_timer_is_active(const NR_timer_t *timer) { return timer->active; @@ -1399,7 +1406,7 @@ bool nr_timer_tick(NR_timer_t *timer) bool expired = false; if (timer->active) { timer->counter += timer->step; - if (timer->target == UINT_MAX) // infinite target, never expires + if (timer->target == UINT_MAX || timer->suspended) // infinite target, never expires return false; expired = nr_timer_expired(timer); if (expired) @@ -1410,7 +1417,7 @@ bool nr_timer_tick(NR_timer_t *timer) bool nr_timer_expired(const NR_timer_t *timer) { - if (timer->target == UINT_MAX) // infinite target, never expires + if (timer->target == UINT_MAX || timer->suspended) // infinite target, never expires return false; return timer->counter >= timer->target; } diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index ce71500eb002da429594ef3ebf0bf49c0eebb19f..1dc6a1169df70c9e9289f66d2087a8cadeae29f9 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -156,6 +156,7 @@ typedef struct { typedef struct { bool active; + bool suspended; uint32_t counter; uint32_t target; uint32_t step; @@ -171,6 +172,12 @@ void nr_timer_start(NR_timer_t *timer); * @param timer Timer to stopped */ void nr_timer_stop(NR_timer_t *timer); +/** + * @brief To suspend/resume a timer + * @param timer Timer to be stopped/suspended + */ +void nr_timer_suspension(NR_timer_t *timer); + /** * @brief If active, it increases timer counter by an amout of units equal to step. It stops timer if expired * @param timer Timer to be handled diff --git a/common/utils/telnetsrv/telnetsrv_ciUE.c b/common/utils/telnetsrv/telnetsrv_ciUE.c index dd95f8009c0fe2318cd7493cb0bf2730475bbb8a..721cb0e5cd772e4d9d9b76e244772850e2adc7d0 100644 --- a/common/utils/telnetsrv/telnetsrv_ciUE.c +++ b/common/utils/telnetsrv/telnetsrv_ciUE.c @@ -94,11 +94,20 @@ int force_RRC_IDLE(char *buf, int debug, telnet_printfunc_t prnt) return 0; } +/** @brief Trigger RA with Msg3 C-RNTI */ +int force_crnti_ra(char *buf, int debug, telnet_printfunc_t prnt) +{ + NR_UE_MAC_INST_t *mac = get_mac_inst(0); + trigger_MAC_UE_RA(mac, NULL); + return 0; +} + /* Telnet shell command definitions */ static telnetshell_cmddef_t cicmds[] = { {"sync_state", "[UE_ID(int,opt)]", get_sync_state}, {"force_rlf", "", force_rlf}, {"force_RRC_IDLE", "", force_RRC_IDLE}, + {"force_crnti_ra", "", force_crnti_ra}, {"", "", NULL}, }; diff --git a/executables/nr-ue.c b/executables/nr-ue.c index cc72eed263067d4ad28a3c15b15b77a35c7888a3..41032a3d42c131042b3a55881f5c61e9b989ec50 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -147,6 +147,24 @@ static void *nrL1_UE_stats_thread(void *param) return NULL; } +static int determine_N_TA_offset(PHY_VARS_NR_UE *ue) { + if (ue->sl_mode == 2) + return 0; + else { + int N_TA_offset = ue->nrUE_config.cell_config.N_TA_offset; + if (N_TA_offset == -1) { + return set_default_nta_offset(ue->frame_parms.freq_range, ue->frame_parms.samples_per_subframe); + } else { + // Return N_TA_offet in samples, as described in 38.211 4.1 and 4.3.1 + // T_c[s] = 1/(Δf_max x N_f) = 1 / (480 * 1000 * 4096) + // N_TA_offset[s] = N_TA_offset x T_c + // N_TA_offset[samples] = samples_per_second x N_TA_offset[s] + // N_TA_offset[samples] = N_TA_offset x samples_per_subframe x 1000 x T_c + return (N_TA_offset * ue->frame_parms.samples_per_subframe) / (4096 * 480); + } + } +} + void init_nr_ue_vars(PHY_VARS_NR_UE *ue, uint8_t UE_id) { int nb_connected_gNB = 1; @@ -165,8 +183,8 @@ void init_nr_ue_vars(PHY_VARS_NR_UE *ue, uint8_t UE_id) // intialize transport init_nr_ue_transport(ue); - // init N_TA offset - init_N_TA_offset(ue); + ue->ta_frame = -1; + ue->ta_slot = -1; } void init_nrUE_standalone_thread(int ue_idx) @@ -519,7 +537,7 @@ void processSlotTX(void *arg) bool sl_tx_action = false; if (UE->if_inst) - UE->if_inst->slot_indication(UE->Mod_id); + UE->if_inst->slot_indication(UE->Mod_id, true); if (proc->tx_slot_type == NR_UPLINK_SLOT || proc->tx_slot_type == NR_MIXED_SLOT) { if (UE->sl_mode == 2 && proc->tx_slot_type == NR_SIDELINK_SLOT) { @@ -650,6 +668,9 @@ static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE, } } + if (UE->if_inst) + UE->if_inst->slot_indication(UE->Mod_id, false); + bool dl_slot = false; if (proc->rx_slot_type == NR_DOWNLINK_SLOT || proc->rx_slot_type == NR_MIXED_SLOT) { dl_slot = true; @@ -867,6 +888,7 @@ void *UE_thread(void *arg) initNotifiedFIFO_nothreadSafe(&freeBlocks); int timing_advance = UE->timing_advance; + UE->N_TA_offset = determine_N_TA_offset(UE); NR_UE_MAC_INST_t *mac = get_mac_inst(UE->Mod_id); bool syncRunning = false; @@ -1095,9 +1117,16 @@ void *UE_thread(void *arg) // but use current UE->timing_advance value to compute writeBlockSize int writeBlockSize = fp->get_samples_per_slot((slot_nr + duration_rx_to_tx) % nb_slot_frame, fp) - iq_shift_to_apply; - if (UE->timing_advance != timing_advance) { - writeBlockSize -= UE->timing_advance - timing_advance; - timing_advance = UE->timing_advance; + int new_timing_advance = UE->timing_advance; + if (new_timing_advance != timing_advance) { + writeBlockSize -= new_timing_advance- timing_advance; + timing_advance = new_timing_advance; + } + int new_N_TA_offset = determine_N_TA_offset(UE); + if (new_N_TA_offset != UE->N_TA_offset) { + LOG_I(PHY, "N_TA_offset changed from %d to %d\n", UE->N_TA_offset, new_N_TA_offset); + writeBlockSize -= new_N_TA_offset - UE->N_TA_offset; + UE->N_TA_offset = new_N_TA_offset; } if (curMsg.proc.nr_slot_tx == 0) diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index d5f4a528ffd19c93d26be660881da7876cbdb7f6..2ba05ae20037180fe6568cdce2274b2f45c0bc31 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -465,6 +465,10 @@ int main(int argc, char **argv) get_channel_model_mode(uniqCfg); } + // Delay to allow the convergence of the IIR filter on PRACH noise measurements at gNB side + if (IS_SOFTMODEM_RFSIM && !get_softmodem_params()->phy_test) + sleep(3); + if (!get_softmodem_params()->nsa && get_softmodem_params()->emulate_l1) start_oai_nrue_threads(); diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index 881d7fad8e0c60ad347915408cd0393bea71bc92..a5d6087856c2ac916c2f47410abe01d8d4e59ca5 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -551,7 +551,6 @@ typedef struct { int ta_frame; int ta_slot; int ta_command; - int ta_offset; bool is_rar; } fapi_nr_ta_command_pdu; @@ -616,7 +615,7 @@ typedef struct { uint8_t phy_cell_id;//Physical Cell ID, ð‘_{ð¼ð·}^{ð‘ð‘’ð‘™ð‘™} [38.211, sec 7.4.2.1] Value: 0 ->1007 uint8_t frame_duplex_type;//Frame duplex type Value: 0 = FDD 1 = TDD - + uint32_t N_TA_offset; } fapi_nr_cell_config_t; typedef struct diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c index 9b36197e45ee9ea22a04fbfe55f4d50d5d6e8cdf..c7bb47c581a56ba3424b0fd0cc32d77650b101e5 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c @@ -218,7 +218,7 @@ static void nr_process_decode_segment(void *arg) int decodeIterations = LDPCdecoder(p_decoderParms, 0, 0, 0, l, llrProcBuf, p_procTime, rdata->abort_decode); - if (decodeIterations <= p_decoderParms->numMaxIter) { + if (decodeIterations < p_decoderParms->numMaxIter) { memcpy(rdata->c, llrProcBuf, K >> 3); *rdata->decodeSuccess = true; } else { diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c index 7960215ab7bb8ba76f081196f82eb9d4c2e375a1..b23db3781da1106585b9171846c5f86a634fb156 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c @@ -277,8 +277,8 @@ int decoder_xdma(nrLDPC_TB_decoding_parameters_t *TB_params, int frame_rx, int s for (uint32_t job = 0; job < num_threads_prepare; job++) { args_fpga_decode_prepare_t *args = &arr[job]; - if (args->no_iteration_ldpc > TB_params->max_ldpc_iterations) - no_iteration_ldpc = TB_params->max_ldpc_iterations + 1; + if (args->no_iteration_ldpc >= TB_params->max_ldpc_iterations) + no_iteration_ldpc = TB_params->max_ldpc_iterations; } // launch decode with FPGA @@ -306,12 +306,12 @@ int decoder_xdma(nrLDPC_TB_decoding_parameters_t *TB_params, int frame_rx, int s #ifdef DEBUG_CRC LOG_I(PHY, "segment %d CRC NOK\n", r); #endif - no_iteration_ldpc = TB_params->max_ldpc_iterations + 1; + no_iteration_ldpc = TB_params->max_ldpc_iterations; } for (int i = 0; i < out_CBoffset; i++) { segment_params->c[i] = multi_outdata[i + r * out_CBoffset]; } - segment_params->decodeSuccess = (no_iteration_ldpc <= TB_params->max_ldpc_iterations); + segment_params->decodeSuccess = (no_iteration_ldpc < TB_params->max_ldpc_iterations); if (segment_params->decodeSuccess) { *TB_params->processedSegments = *TB_params->processedSegments + 1; } @@ -396,7 +396,7 @@ void nr_ulsch_FPGA_decoding_prepare_blocks(void *args) == -1) { stop_meas(&segment_params->ts_rate_unmatch); LOG_E(PHY, "ulsch_decoding.c: Problem in rate_matching\n"); - no_iteration_ldpc = max_ldpc_iterations + 1; + no_iteration_ldpc = max_ldpc_iterations; arguments->no_iteration_ldpc = no_iteration_ldpc; return; } else { diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c index fcee71c1510b303d6fa5cea5a5c34ab7885ddfa3..e2ed7fce10fa491649d36ae987efc01fdd844368 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c +++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c @@ -187,7 +187,7 @@ int32_t LDPCdecoder(t_nrLDPC_dec_params* p_decParams, // Launch LDPC decoder core for one segment int numIter = nrLDPC_decoder_core(p_llr, p_out, numLLR, p_lut, p_decParams, p_profiler, ab); - if (numIter > p_decParams->numMaxIter) { + if (numIter >= p_decParams->numMaxIter) { LOG_D(PHY, "set abort: %d, %d\n", numIter, p_decParams->numMaxIter); set_abort(ab, true); } @@ -549,13 +549,11 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, // estimated after only one iteration // First iteration finished - uint32_t numIter = 1; + uint32_t numIter = 0; int32_t pcRes = 1; // pcRes is 0 if the ldpc decoder is succesful - while ((numIter <= numMaxIter) && (pcRes != 0)) { - // Increase iteration counter - numIter++; + while ((numIter < numMaxIter) && (pcRes != 0)) { if (check_abort(ab)) { - numIter = numMaxIter + 2; + numIter = numMaxIter; break; } // CN processing @@ -847,7 +845,7 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, pcRes = nrLDPC_cnProcPc_BG2(p_lut, cnProcBuf, cnProcBufRes, Z); NR_LDPC_PROFILER_DETAIL(stop_meas(&p_profiler->cnProcPc)); } else { - if (numIter > 2) { + if (numIter > 0) { int8_t llrOut[NR_LDPC_MAX_NUM_LLR] __attribute__((aligned(64))) = {0}; int8_t* p_llrOut = outMode == nrLDPC_outMode_LLRINT8 ? p_out : llrOut; nrLDPC_llrRes2llrOut(p_lut, p_llrOut, llrRes, Z, BG); @@ -861,6 +859,8 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr, } } } + // Increase iteration counter + numIter++; } if (!p_decParams->check_crc) { int8_t llrOut[NR_LDPC_MAX_NUM_LLR] __attribute__((aligned(64))) = {0}; diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index 019e386fd0944dc230f3dd97eb5eb402b308930e..19816e215fda7a5d337cc758ff42ad0592068077 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -492,24 +492,6 @@ void clean_UE_harq(PHY_VARS_NR_UE *UE) } } - -void init_N_TA_offset(PHY_VARS_NR_UE *ue) -{ - NR_DL_FRAME_PARMS *fp = &ue->frame_parms; - - // No timing offset for Sidelink, refer to 3GPP 38.211 Section 8.5 - if (ue->sl_mode == 2) - ue->N_TA_offset = 0; - else - ue->N_TA_offset = set_default_nta_offset(fp->freq_range, fp->samples_per_subframe); - ue->ta_frame = -1; - ue->ta_slot = -1; - - LOG_I(PHY, - "UE %d Setting N_TA_offset to %d samples (UL Freq %lu, N_RB %d, mu %d)\n", - ue->Mod_id, ue->N_TA_offset, fp->ul_CarrierFreq, fp->N_RB_DL, fp->numerology_index); -} - void phy_init_nr_top(PHY_VARS_NR_UE *ue) { NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; init_delay_table(frame_parms->ofdm_symbol_size, MAX_DELAY_COMP, NR_MAX_OFDM_SYMBOL_SIZE, frame_parms->delay_table); diff --git a/openair1/PHY/INIT/nr_phy_init.h b/openair1/PHY/INIT/nr_phy_init.h index d2c65e939f20836f49bb08009919a011b04dd783..1b1a0fa1b084c7502bccb3beb946cb0ac0088640 100644 --- a/openair1/PHY/INIT/nr_phy_init.h +++ b/openair1/PHY/INIT/nr_phy_init.h @@ -36,7 +36,6 @@ int nr_init_frame_parms_ue_sl(NR_DL_FRAME_PARMS *fp, int init_nr_ue_signal(PHY_VARS_NR_UE *ue,int nb_connected_eNB); void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB); void init_nr_ue_transport(PHY_VARS_NR_UE *ue); -void init_N_TA_offset(PHY_VARS_NR_UE *ue); void nr_dump_frame_parms(NR_DL_FRAME_PARMS *frame_parms); void phy_init_nr_gNB(PHY_VARS_gNB *gNB); int init_codebook_gNB(PHY_VARS_gNB *gNB); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c index a3138f5d7fd80b4f7e267589000cf0e30844dfe2..e6b4503e1bbc53009aee909e9fac4f62e69e8be7 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c @@ -59,14 +59,14 @@ void nr_dlsch_unscrambling(int16_t *llr, uint32_t size, uint8_t q, uint32_t Nid, /*! \brief Prepare necessary parameters for nrLDPC_coding_interface */ -uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, - const UE_nr_rxtx_proc_t *proc, - NR_UE_DLSCH_t *dlsch, - int16_t **dlsch_llr, - uint8_t **b, - int *G, - int nb_dlsch, - uint8_t *DLSCH_ids) +void nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, + const UE_nr_rxtx_proc_t *proc, + NR_UE_DLSCH_t *dlsch, + int16_t **dlsch_llr, + uint8_t **b, + int *G, + int nb_dlsch, + uint8_t *DLSCH_ids) { nrLDPC_TB_decoding_parameters_t TBs[nb_dlsch]; memset(TBs, 0, sizeof(TBs)); @@ -100,7 +100,7 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, if (!harq_process) { LOG_E(PHY, "dlsch_decoding_slot.c: NULL harq_process pointer\n"); - return dlsch[DLSCH_id].max_ldpc_iterations + 1; + return; } nrLDPC_TB_decoding_parameters_t *TB_parameters = &TBs[pdsch_id]; @@ -164,7 +164,7 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, if (harq_process->C > MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * TB_parameters->nb_layers) { LOG_E(PHY, "nr_segmentation.c: too many segments %d, A %d\n", harq_process->C, TB_parameters->A); - return dlsch[DLSCH_id].max_ldpc_iterations + 1; + return; } if (LOG_DEBUGFLAG(DEBUG_DLSCH_DECOD) && (!slot_parameters.frame % 100)) @@ -242,7 +242,8 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, int ret_decoder = phy_vars_ue->nrLDPC_coding_interface.nrLDPC_coding_decoder(&slot_parameters); if (ret_decoder != 0) { - return dlsch->max_ldpc_iterations + 1; + LOG_E(PHY, "nrLDPC_coding_decoder returned an error: %d\n", ret_decoder); + return; } // post decode @@ -316,11 +317,11 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, if (harq_process->decodeResult) { LOG_D(PHY, "DLSCH received ok \n"); harq_process->status = SCH_IDLE; - dlsch->last_iteration_cnt = dlsch->max_ldpc_iterations; + dlsch->last_iteration_cnt = dlsch->max_ldpc_iterations - 1; } else { LOG_D(PHY, "DLSCH received nok \n"); kpiStructure.nb_nack++; - dlsch->last_iteration_cnt = dlsch->max_ldpc_iterations + 1; + dlsch->last_iteration_cnt = dlsch->max_ldpc_iterations; UEdumpScopeData(phy_vars_ue, proc->nr_slot_rx, proc->frame_rx, "DLSCH_NACK"); } @@ -355,5 +356,4 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, } - return dlsch[0].last_iteration_cnt; } diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h index 0ca616ba341bf6f545dbec457b521d438ec4b1d6..bb1a6c03df85fd98c49642cb103c930b88b083f5 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -81,14 +81,14 @@ void nr_conjch0_mult_ch1(int *ch0, @param[in] DLSCH_ids array of active downlink shared channels @returns 0 on success, 1 on unsuccessful decoding */ -uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, - const UE_nr_rxtx_proc_t *proc, - NR_UE_DLSCH_t *dlsch, - short **dlsch_llr, - uint8_t **b, - int *G, - int nb_dlsch, - uint8_t *DLSCH_ids); +void nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, + const UE_nr_rxtx_proc_t *proc, + NR_UE_DLSCH_t *dlsch, + short **dlsch_llr, + uint8_t **b, + int *G, + int nb_dlsch, + uint8_t *DLSCH_ids); /** \brief This is the alternative top-level entry point for ULSCH encoding in UE. It handles all the HARQ processes in only one call. The routine first diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h index 419988a9612a9912985c4ee09a3c84ff30fe2127..07917b9075e6461702e084c6e8cc1cecf38c0973 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h @@ -147,7 +147,7 @@ typedef struct { /// Maximum number of LDPC iterations uint8_t max_ldpc_iterations; /// number of iterations used in last turbo decoding - uint8_t last_iteration_cnt; + int8_t last_iteration_cnt; /// bit mask of PT-RS ofdm symbol indicies uint16_t ptrs_symbols; // PTRS symbol index, to be updated every PTRS symbol within a slot. diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index eb0a1acc0e92ef4e038acf7145f2ca27075b280e..47d41db44bc7a5562a0592f3f6426ff94561f536 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -239,7 +239,7 @@ typedef struct { /// Maximum number of LDPC iterations uint8_t max_ldpc_iterations; /// number of iterations used in last LDPC decoding - uint8_t last_iteration_cnt; + int8_t last_iteration_cnt; /// Status Flag indicating for this ULSCH bool active; /// Flag to indicate that the UL configuration has been handled. Used to remove a stale ULSCH when frame wraps around diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 1484d44ddfb21cff71dc5cc36d651fd45806988d..4f1f8ff01004ea67e06f025a12e3b332f065de92 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -424,7 +424,7 @@ static int nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, boo LOG_D(PHY, "ULSCH received ok \n"); ulsch->active = false; ulsch_harq->round = 0; - ulsch->last_iteration_cnt = ulsch->max_ldpc_iterations; // Setting to max_ldpc_iterations is sufficient given that this variable is only used for checking for failure + ulsch->last_iteration_cnt = ulsch->max_ldpc_iterations - 1; // Setting to max_ldpc_iterations - 1 is sufficient given that this variable is only used for checking for failure } else { LOG_D(PHY, "[gNB %d] ULSCH: Setting NAK for SFN/SF %d/%d (pid %d, ndi %d, status %d, round %d, RV %d, prb_start %d, prb_size %d, " @@ -444,7 +444,7 @@ static int nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, boo gNBdumpScopeData(gNB, ulsch->slot, ulsch->frame, "ULSCH_NACK"); ulsch->handled = 1; LOG_D(PHY, "ULSCH %d in error\n",ULSCH_id); - ulsch->last_iteration_cnt = ulsch->max_ldpc_iterations + 1; // Setting to max_ldpc_iterations + 1 is sufficient given that this variable is only used for checking for failure + ulsch->last_iteration_cnt = ulsch->max_ldpc_iterations; // Setting to max_ldpc_iterations is sufficient given that this variable is only used for checking for failure } } diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c index fbfc9d838903df9cba79f588373964663a6a5347..ba4ad4a0f7b0d9d7700b94a12d222106b4b78b18 100644 --- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c +++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c @@ -419,15 +419,6 @@ static void configure_ta_command(PHY_VARS_NR_UE *ue, fapi_nr_ta_command_pdu *ta_ LOG_D(PHY, "TA command received in %d.%d Starting UL time alignment procedures. TA update will be applied at frame %d slot %d\n", ta_command_pdu->ta_frame, ta_command_pdu->ta_slot, ue->ta_frame, ue->ta_slot); - - if (ta_command_pdu->ta_offset != -1) { - // ta_offset_samples : ta_offset = samples_per_subframe : (Δf_max x N_f / 1000) - // As described in Section 4.3.1 in 38.211 - int ta_offset_samples = (ta_command_pdu->ta_offset * samples_per_subframe) / (4096 * 480); - ue->N_TA_offset = ta_offset_samples; - LOG_D(PHY, "Received N_TA offset %d from upper layers. Corresponds to %d samples.\n", - ta_command_pdu->ta_offset, ta_offset_samples); - } } static void nr_ue_scheduled_response_dl(NR_UE_MAC_INST_t *mac, diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index b57bf4eff34e0ff39ecd95b9b26892c0221a4979..283673a6df921e9137c365e2c72232e3157ae349 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -686,20 +686,18 @@ static uint32_t compute_csi_rm_unav_res(fapi_nr_dl_config_dlsch_pdu_rel15_t *dls /*! \brief Process the whole DLSCH slot */ -static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, +static void nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, NR_UE_DLSCH_t dlsch[2], int16_t *llr[2]) { if (dlsch[0].active == false) { LOG_E(PHY, "DLSCH should be active when calling this function\n"); - return true; + return; } - bool dec = false; int harq_pid = dlsch[0].dlsch_config.harq_process_nbr; int frame_rx = proc->frame_rx; int nr_slot_rx = proc->nr_slot_rx; - uint32_t ret = UINT32_MAX; NR_DL_UE_HARQ_t *dl_harq0 = &ue->dl_harq_processes[0][harq_pid]; NR_DL_UE_HARQ_t *dl_harq1 = &ue->dl_harq_processes[1][harq_pid]; uint16_t dmrs_len = get_num_dmrs(dlsch[0].dlsch_config.dlDmrsSymbPos); @@ -732,7 +730,7 @@ static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, const int ack_nack_slot_and_frame = (proc->nr_slot_rx + dlsch[0].dlsch_config.k1_feedback) + proc->frame_rx * ue->frame_parms.slots_per_frame; dynamic_barrier_join(&ue->process_slot_tx_barriers[ack_nack_slot_and_frame % NUM_PROCESS_SLOT_TX_BARRIERS]); - return false; + return; } int G[2]; @@ -765,11 +763,9 @@ static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, } start_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS); - ret = nr_dlsch_decoding(ue, proc, dlsch, llr, p_b, G, nb_dlsch, DLSCH_ids); + nr_dlsch_decoding(ue, proc, dlsch, llr, p_b, G, nb_dlsch, DLSCH_ids); stop_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS); - if (ret < ue->max_ldpc_iterations + 1) dec = true; - int ind_type = -1; switch (dlsch[0].rnti_type) { case TYPE_RA_RNTI_: @@ -829,7 +825,6 @@ static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue, else if (ue->phy_sim_dlsch_b && is_cw1_active == ACTIVE) memcpy(ue->phy_sim_dlsch_b, p_b[1], dlsch_bytes); - return dec; } static bool is_ssb_index_transmitted(const PHY_VARS_NR_UE *ue, const int index) diff --git a/openair1/SIMULATION/NR_PHY/dlschsim.c b/openair1/SIMULATION/NR_PHY/dlschsim.c index de5c598015d8bd0673652bfcd6a40300798c877e..977970c9f7394d22dae085141ed2368601b532b5 100644 --- a/openair1/SIMULATION/NR_PHY/dlschsim.c +++ b/openair1/SIMULATION/NR_PHY/dlschsim.c @@ -123,7 +123,6 @@ int main(int argc, char **argv) NR_DL_FRAME_PARMS *frame_parms; double sigma; unsigned char qbits = 8; - int ret; int loglvl = OAILOG_WARNING; uint8_t dlsch_threads = 0; float target_error_rate = 0.01; @@ -577,18 +576,18 @@ int main(int argc, char **argv) short *p_channel_output_fixed = channel_output_fixed; uint8_t *p_b = b; int available_bits_array[1] = { available_bits }; - ret = nr_dlsch_decoding(UE, - &proc, - dlsch0_ue, - &p_channel_output_fixed, - &p_b, - available_bits_array, - 1, - DLSCH_ids); + nr_dlsch_decoding(UE, + &proc, + dlsch0_ue, + &p_channel_output_fixed, + &p_b, + available_bits_array, + 1, + DLSCH_ids); vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DECODING0, VCD_FUNCTION_OUT); - if (ret > dlsch0_ue->max_ldpc_iterations) + if (dlsch0_ue->last_iteration_cnt > dlsch0_ue->max_ldpc_iterations) n_errors++; //count errors diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 9014cd33ef07758dee3f05875a0fe09ef4efc40e..76c888194553c2dc233449f6a77c9d3fa4962252 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -1163,7 +1163,7 @@ printf("%d\n", slot); //---------------------- count errors ---------------------- //---------------------------------------------------------- - if (dlsch0->last_iteration_cnt >= dlsch0->max_ldpc_iterations+1) + if (dlsch0->last_iteration_cnt >= dlsch0->max_ldpc_iterations) n_errors[round]++; int16_t *UE_llr = (int16_t*)UE->phy_sim_pdsch_llr; diff --git a/openair1/SIMULATION/NR_PHY/nr_dummy_functions.c b/openair1/SIMULATION/NR_PHY/nr_dummy_functions.c index d55322156b3a2a3a5b53d9f48a62f5a460ce30d7..973aa60930075eac9fbf54a56b248d4db9be6f4e 100644 --- a/openair1/SIMULATION/NR_PHY/nr_dummy_functions.c +++ b/openair1/SIMULATION/NR_PHY/nr_dummy_functions.c @@ -36,7 +36,7 @@ void nr_mac_rrc_sync_ind(const module_id_t module_id, void nr_mac_rrc_msg3_ind(const module_id_t mod_id, int rnti, int gnb_id) {} -void nr_mac_rrc_ra_ind(const module_id_t mod_id, int frame, bool success) {} +void nr_mac_rrc_ra_ind(const module_id_t mod_id, bool success) {} void nr_mac_rrc_inactivity_timer_ind(const module_id_t mod_id) {} diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c index ce00f6ae9e761ed51e062d0f6028360498a6ded3..eb3537650b1e2189f763ee5f3864dbc6ca12c68f 100644 --- a/openair1/SIMULATION/NR_PHY/prachsim.c +++ b/openair1/SIMULATION/NR_PHY/prachsim.c @@ -136,13 +136,11 @@ int main(int argc, char **argv){ c16_t **txdata; int N_RB_UL = 106, delay = 0, NCS_config = 13, rootSequenceIndex = 1, threequarter_fs = 0, mu = 1, fd_occasion = 0, loglvl = OAILOG_INFO, numRA = 0, prachStartSymbol = 0; uint8_t snr1set = 0, ue_speed1set = 0, transmission_mode = 1, n_tx = 1, n_rx = 1, awgn_flag = 0, msg1_frequencystart = 0, num_prach_fd_occasions = 1, prach_format=0; - uint8_t config_index = 98, prach_sequence_length = 1, restrictedSetConfig = 0, N_dur, N_t_slot, start_symbol; - uint16_t Nid_cell = 0, preamble_tx = 0, preamble_delay, format, format0, format1; + uint8_t config_index = 98, prach_sequence_length = 1, restrictedSetConfig = 0; + uint16_t Nid_cell = 0, preamble_tx = 0, preamble_delay, format0, format1; uint32_t tx_lev = 10000, prach_errors = 0; //,tx_lev_dB; uint64_t SSB_positions = 0x01; uint16_t RA_sfn_index; - uint8_t N_RA_slot; - uint8_t config_period; int prachOccasion = 0; double DS_TDL = .03; @@ -482,25 +480,24 @@ int main(int argc, char **argv){ gNB->gNB_config.prach_config.num_prach_fd_occasions.value = num_prach_fd_occasions; gNB->gNB_config.prach_config.num_prach_fd_occasions_list = (nfapi_nr_num_prach_fd_occasions_t *) malloc(num_prach_fd_occasions*sizeof(nfapi_nr_num_prach_fd_occasions_t)); - gNB->proc.slot_rx = slot; - - int ret = get_nr_prach_info_from_index(config_index, - (int)frame, - (int)slot, - absoluteFrequencyPointA, - mu, - frame_parms->frame_type, - &format, - &start_symbol, - &N_t_slot, - &N_dur, - &RA_sfn_index, - &N_RA_slot, - &config_period); - - if (ret == 0) {printf("No prach in %d.%d, mu %d, config_index %d\n",frame,slot,mu,config_index); exit(-1);} - format0 = format&0xff; // first column of format from table - format1 = (format>>8)&0xff; // second column of format from table + gNB->proc.slot_rx = slot; + frequency_range_t freq_range = absoluteFrequencyPointA > 2016666 ? FR2 : FR1; + nr_prach_info_t prach_info = get_nr_prach_occasion_info_from_index(config_index, freq_range, frame_parms->frame_type); + int ret = get_nr_prach_sched_from_info(prach_info, + config_index, + frame, + slot, + mu, + freq_range, + &RA_sfn_index, + frame_parms->frame_type); + + if (ret == 0) { + printf("No prach in %d.%d, mu %d, config_index %d\n", frame, slot, mu, config_index); + exit(-1); + } + format0 = prach_info.format & 0xff; // first column of format from table + format1 = (prach_info.format >> 8) & 0xff; // second column of format from table if (format1 != 0xff) { switch(format0) { diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index b45ca38254a8583bbe5cfb60f4eefd54011485c4..4013951cab82ceba1706eaf52c1add29e27d12b2 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -1420,7 +1420,7 @@ int main(int argc, char *argv[]) 0); } - if ((ulsch_gNB->last_iteration_cnt >= ulsch_gNB->max_ldpc_iterations + 1) || ul_proc_error == 1) { + if ((ulsch_gNB->last_iteration_cnt >= ulsch_gNB->max_ldpc_iterations) || ul_proc_error == 1) { error_flag = 1; n_errors[round]++; crc_status = 1; diff --git a/openair2/COMMON/mac_messages_types.h b/openair2/COMMON/mac_messages_types.h index bc9e8f6c8aec2926720c6241604fdb8d3fef0042..ebbda2fc268e398c71279d1fc32e05dadba7e555 100644 --- a/openair2/COMMON/mac_messages_types.h +++ b/openair2/COMMON/mac_messages_types.h @@ -72,13 +72,13 @@ // Messages between RRC and MAC layers typedef struct NRRrcMacRaInd_s { - uint32_t frame; bool RA_succeeded; } NRRrcMacRaInd; typedef struct NRRrcMacMsg3Ind_s { uint16_t rnti; int gnb_id; + bool prepare_payload; } NRRrcMacMsg3Ind; typedef struct NRRrcMacInacInd_s { 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 f3693e2791097a16932d9c731b7859d5468cf294..2da3d9df93c8d95b774268293873ea6471c5d2b6 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -571,34 +571,33 @@ NR_tda_info_t get_dl_tda_info(const NR_UE_DL_BWP_t *dl_BWP, return tda_info; } -uint16_t get_NCS(uint8_t index, uint16_t format0, uint8_t restricted_set_config) { - - LOG_D(MAC,"get_NCS: indx %d,format0 %d, restriced_set_config %d\n", - index,format0,restricted_set_config); +uint16_t get_NCS(uint8_t index, uint16_t format0, uint8_t restricted_set_config) +{ + LOG_D(NR_MAC, "get_NCS: indx %d,format0 %d, restriced_set_config %d\n", index, format0, restricted_set_config); if (format0 < 3) { - switch(restricted_set_config){ + switch (restricted_set_config) { case 0: return(NCS_unrestricted_delta_f_RA_125[index]); case 1: return(NCS_restricted_TypeA_delta_f_RA_125[index]); case 2: return(NCS_restricted_TypeB_delta_f_RA_125[index]); - default: - AssertFatal(1==0,"Invalid restricted set config value %d",restricted_set_config); + default: + AssertFatal(false, "Invalid restricted set config value %d", restricted_set_config); } } else { if (format0 == 3) { - switch(restricted_set_config){ + switch (restricted_set_config) { case 0: return(NCS_unrestricted_delta_f_RA_5[index]); case 1: return(NCS_restricted_TypeA_delta_f_RA_5[index]); case 2: return(NCS_restricted_TypeB_delta_f_RA_5[index]); - default: - AssertFatal(1==0,"Invalid restricted set config value %d",restricted_set_config); + default: + AssertFatal(false, "Invalid restricted set config value %d", restricted_set_config); } } else @@ -1418,11 +1417,9 @@ static const int64_t table_6_3_3_2_4_prachConfig_Index[256][10] = { {0xa3, 0xb3, 1, 0, -1, 733007751850, 2, 1, 2, 6} // (subframe number :1,3,5,7,…,37,39) }; -int get_format0(uint8_t index, - uint8_t unpaired, - frequency_range_t frequency_range){ - - uint16_t format=0; +int get_format0(uint8_t index, uint8_t unpaired, frequency_range_t frequency_range) +{ + int format = 0; if (unpaired) { if (frequency_range==FR1) format = table_6_3_3_2_3_prachConfig_Index[index][0]; @@ -1438,23 +1435,6 @@ int get_format0(uint8_t index, return format; } -const int64_t *get_prach_config_info(frequency_range_t freq_range, uint8_t index, uint8_t unpaired) -{ - const int64_t *prach_config_info_p; - - if (freq_range == FR2) { //FR2 - prach_config_info_p = table_6_3_3_2_4_prachConfig_Index[index]; - } - else { // FR1 - if (unpaired) - prach_config_info_p = table_6_3_3_2_3_prachConfig_Index[index]; - else - prach_config_info_p = table_6_3_3_2_2_prachConfig_Index[index]; - } // FR2 / FR1 - - return prach_config_info_p; -} - void find_aggregation_candidates(uint8_t *aggregation_level, uint8_t *nr_of_candidates, const NR_SearchSpace_t *ss, @@ -1567,97 +1547,83 @@ void set_monitoring_periodicity_offset(NR_SearchSpace_t *ss, } -int get_nr_prach_occasion_info_from_index(uint8_t index, - uint32_t pointa, - uint8_t mu, - uint8_t unpaired, - uint16_t *format, - uint8_t *start_symbol, - uint8_t *N_t_slot, - uint8_t *N_dur, - uint8_t *N_RA_slot, - uint16_t *N_RA_sfn, - uint8_t *max_association_period) +nr_prach_info_t get_nr_prach_occasion_info_from_index(uint8_t index, frequency_range_t freq_range, uint8_t unpaired) { - int x; - uint64_t s_map; uint8_t format2 = 0xff; - if (pointa > 2016666) { //FR2 - x = table_6_3_3_2_4_prachConfig_Index[index][2]; - s_map = table_6_3_3_2_4_prachConfig_Index[index][5]; - *N_RA_sfn += count_bits64(s_map); - *N_RA_slot = table_6_3_3_2_4_prachConfig_Index[index][7]; // Number of RACH slots within a subframe - *max_association_period = 160/(x * 10); - if (start_symbol != NULL && N_t_slot != NULL && N_dur != NULL && format != NULL){ - *start_symbol = table_6_3_3_2_4_prachConfig_Index[index][6];//multiple prach occasions in diff slot - *N_t_slot = table_6_3_3_2_4_prachConfig_Index[index][8]; - *N_dur = table_6_3_3_2_4_prachConfig_Index[index][9]; - if (table_6_3_3_2_4_prachConfig_Index[index][1] != -1) - format2 = (uint8_t) table_6_3_3_2_4_prachConfig_Index[index][1]; - - *format = ((uint8_t) table_6_3_3_2_4_prachConfig_Index[index][0]) | (format2<<8); - LOG_D(MAC,"Getting Total PRACH info from index %d absoluteFrequencyPointA %u mu %u frame_type %u start_symbol %u N_t_slot %u N_dur %u N_RA_sfn = %u\n", - index, - pointa, - mu, - unpaired, - *start_symbol, - *N_t_slot, - *N_dur, - *N_RA_sfn); - } - return 1; - } - else { - if (unpaired) { - x = table_6_3_3_2_3_prachConfig_Index[index][2]; - s_map = table_6_3_3_2_3_prachConfig_Index[index][4]; - *N_RA_sfn += count_bits64(s_map); - *N_RA_slot = table_6_3_3_2_3_prachConfig_Index[index][6]; // Number of RACH slots within a subframe - *max_association_period = 160/(x * 10); - if (start_symbol != NULL && N_t_slot != NULL && N_dur != NULL && format != NULL){ - *start_symbol = table_6_3_3_2_3_prachConfig_Index[index][5]; - *N_t_slot = table_6_3_3_2_3_prachConfig_Index[index][7]; - *N_dur = table_6_3_3_2_3_prachConfig_Index[index][8]; - if (table_6_3_3_2_3_prachConfig_Index[index][1] != -1) - format2 = (uint8_t) table_6_3_3_2_3_prachConfig_Index[index][1]; - *format = ((uint8_t) table_6_3_3_2_3_prachConfig_Index[index][0]) | (format2<<8); - LOG_D(NR_MAC,"Getting Total PRACH info from index %d (col %lu ) absoluteFrequencyPointA %u mu %u frame_type %u start_symbol %u N_t_slot %u N_dur %u N_RA_sfn = %u\n", - index, table_6_3_3_2_3_prachConfig_Index[index][6], - pointa, - mu, - unpaired, - *start_symbol, - *N_t_slot, - *N_dur, - *N_RA_sfn); - } - return 1; - } - else { // FDD - x = table_6_3_3_2_2_prachConfig_Index[index][2]; - s_map = table_6_3_3_2_2_prachConfig_Index[index][4]; - *N_RA_sfn += count_bits64(s_map); - *N_RA_slot = table_6_3_3_2_2_prachConfig_Index[index][6]; - if (start_symbol != NULL && N_t_slot != NULL && N_dur != NULL && format != NULL){ - *start_symbol = table_6_3_3_2_2_prachConfig_Index[index][5]; - *N_t_slot = table_6_3_3_2_2_prachConfig_Index[index][7]; - *N_dur = table_6_3_3_2_2_prachConfig_Index[index][8]; - if (table_6_3_3_2_2_prachConfig_Index[index][1] != -1) - format2 = (uint8_t) table_6_3_3_2_2_prachConfig_Index[index][1]; - *format = ((uint8_t) table_6_3_3_2_2_prachConfig_Index[index][0]) | (format2<<8); - LOG_D(MAC,"Getting Total PRACH info from index %d absoluteFrequencyPointA %u mu %u frame_type %u start_symbol %u N_t_slot %u N_dur %u \n", - index, - pointa, - mu, - unpaired, - *start_symbol, - *N_t_slot, - *N_dur); - } - return 1; - } + nr_prach_info_t info; + if (freq_range == FR2) { + info.x = table_6_3_3_2_4_prachConfig_Index[index][2]; + info.y = table_6_3_3_2_4_prachConfig_Index[index][3]; + info.y2 = table_6_3_3_2_4_prachConfig_Index[index][4]; + info.s_map = table_6_3_3_2_4_prachConfig_Index[index][5]; + info.N_RA_sfn += count_bits64(info.s_map); + info.N_RA_slot = table_6_3_3_2_4_prachConfig_Index[index][7]; + info.max_association_period = 160 / (info.x * 10); + info.start_symbol = table_6_3_3_2_4_prachConfig_Index[index][6]; + info.N_t_slot = table_6_3_3_2_4_prachConfig_Index[index][8]; + info.N_dur = table_6_3_3_2_4_prachConfig_Index[index][9]; + if (table_6_3_3_2_4_prachConfig_Index[index][1] != -1) + format2 = (uint8_t)table_6_3_3_2_4_prachConfig_Index[index][1]; + info.format = ((uint8_t)table_6_3_3_2_4_prachConfig_Index[index][0]) | (format2 << 8); + LOG_D(NR_MAC, + "PRACH info from index %d frame_type %u start_symbol %u N_t_slot %u N_dur %u N_RA_sfn = %u\n", + index, + unpaired, + info.start_symbol, + info.N_t_slot, + info.N_dur, + info.N_RA_sfn); + return info; + } + + 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]; + info.max_association_period = 160 / (info.x * 10); + info.start_symbol = table_6_3_3_2_3_prachConfig_Index[index][5]; + info.N_t_slot = table_6_3_3_2_3_prachConfig_Index[index][7]; + info.N_dur = table_6_3_3_2_3_prachConfig_Index[index][8]; + if (table_6_3_3_2_3_prachConfig_Index[index][1] != -1) + format2 = (uint8_t)table_6_3_3_2_3_prachConfig_Index[index][1]; + info.format = ((uint8_t)table_6_3_3_2_3_prachConfig_Index[index][0]) | (format2 << 8); + LOG_D(NR_MAC, + "PRACH info from index %d (col %lu) frame_type %u start_symbol %u N_t_slot %u N_dur %u N_RA_sfn = %u\n", + index, + table_6_3_3_2_3_prachConfig_Index[index][6], + unpaired, + info.start_symbol, + info.N_t_slot, + info.N_dur, + info.N_RA_sfn); + return info; } + + // 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]; + info.max_association_period = 160 / (info.x * 10); + info.start_symbol = table_6_3_3_2_2_prachConfig_Index[index][5]; + info.N_t_slot = table_6_3_3_2_2_prachConfig_Index[index][7]; + info.N_dur = table_6_3_3_2_2_prachConfig_Index[index][8]; + if (table_6_3_3_2_2_prachConfig_Index[index][1] != -1) + format2 = (uint8_t)table_6_3_3_2_2_prachConfig_Index[index][1]; + info.format = ((uint8_t)table_6_3_3_2_2_prachConfig_Index[index][0]) | (format2 << 8); + LOG_D(NR_MAC, + "PRACH info from index %d frame_type %u start_symbol %u N_t_slot %u N_dur %u \n", + index, + unpaired, + info.start_symbol, + info.N_t_slot, + info.N_dur); + return info; } uint16_t get_nr_prach_format_from_index(uint8_t index, uint32_t pointa, uint8_t unpaired) @@ -1682,177 +1648,83 @@ uint16_t get_nr_prach_format_from_index(uint8_t index, uint32_t pointa, uint8_t return format; } -int get_nr_prach_info_from_index(uint8_t index, - int frame, - int slot, - uint32_t pointa, - uint8_t mu, - uint8_t unpaired, - uint16_t *format, - uint8_t *start_symbol, - uint8_t *N_t_slot, - uint8_t *N_dur, - uint16_t *RA_sfn_index, - uint8_t *N_RA_slot, - uint8_t *config_period) +bool get_nr_prach_sched_from_info(nr_prach_info_t info, + int config_index, + int frame, + int slot, + int mu, + frequency_range_t freq_range, + uint16_t *RA_sfn_index, + uint8_t unpaired) { - int x,y; - int64_t s_map; - uint8_t format2 = 0xff; - - if (pointa > 2016666) { //FR2 - int y2; - uint8_t slot_60khz; - x = table_6_3_3_2_4_prachConfig_Index[index][2]; - y = table_6_3_3_2_4_prachConfig_Index[index][3]; - y2 = table_6_3_3_2_4_prachConfig_Index[index][4]; + if (freq_range == FR2) { // checking n_sfn mod x = y - if ((frame % x) == y || (frame % x) == y2) { - slot_60khz = slot >> (mu - 2); // in table slots are numbered wrt 60kHz - s_map = table_6_3_3_2_4_prachConfig_Index[index][5]; - if ((s_map >> slot_60khz) & 0x01) { + if ((frame % info.x) == info.y || (frame % info.x) == info.y2) { + int slot_60khz = slot >> (mu - 2); // in table slots are numbered wrt 60kHz + if ((info.s_map >> slot_60khz) & 0x01) { for(int i = 0; i <= slot_60khz ;i++) { - if ((s_map >> i) & 0x01) { + if ((info.s_map >> i) & 0x01) { (*RA_sfn_index)++; } } } - if (((s_map >> slot_60khz) & 0x01)) { - *N_RA_slot = table_6_3_3_2_4_prachConfig_Index[index][7]; // Number of RACH slots within a subframe + if (((info.s_map >> slot_60khz) & 0x01)) { if (mu == 3) { - if ((*N_RA_slot == 1) && (slot % 2 == 0) ) - return 0; // no prach in even slots @ 120kHz for 1 prach per 60khz slot - } - if (start_symbol != NULL && N_t_slot != NULL && N_dur != NULL && format != NULL){ - *config_period = x; - *start_symbol = table_6_3_3_2_4_prachConfig_Index[index][6]; - *N_t_slot = table_6_3_3_2_4_prachConfig_Index[index][8]; - *N_dur = table_6_3_3_2_4_prachConfig_Index[index][9]; - if (table_6_3_3_2_4_prachConfig_Index[index][1] != -1) - format2 = (uint8_t) table_6_3_3_2_4_prachConfig_Index[index][1]; - *format = ((uint8_t) table_6_3_3_2_4_prachConfig_Index[index][0]) | (format2<<8); - LOG_D(MAC,"Frame %d slot %d: Getting PRACH info from index %d absoluteFrequencyPointA %u mu %u frame_type %u start_symbol %u N_t_slot %u N_dur %u N_RA_slot %u RA_sfn_index %u\n", - frame, - slot, - index, - pointa, - mu, - unpaired, - *start_symbol, - *N_t_slot, - *N_dur, - *N_RA_slot, - *RA_sfn_index); + if ((info.N_RA_slot == 1) && (slot % 2 == 0)) + return false; // no prach in even slots @ 120kHz for 1 prach per 60khz slot } - return 1; - } - else - return 0; // no prach in current slot + return true; + } else + return false; // no prach in current slot } else - return 0; // no prach in current frame - } - else { - uint8_t subframe; - if (unpaired) { - x = table_6_3_3_2_3_prachConfig_Index[index][2]; - y = table_6_3_3_2_3_prachConfig_Index[index][3]; - if ((frame % x) == y) { - subframe = slot >> mu; - s_map = table_6_3_3_2_3_prachConfig_Index[index][4]; - if ((s_map >> subframe) & 0x01) { + return false; // no prach in current frame + } else { + if (unpaired) { // TDD + if ((frame % info.x) == info.y) { + int subframe = slot >> mu; + if ((info.s_map >> subframe) & 0x01) { for(int i = 0; i <= subframe ;i++) { - if ((s_map >> i) & 0x01) { + if ((info.s_map >> i) & 0x01) { (*RA_sfn_index)++; } } } - if ((s_map >> subframe) & 0x01 ) { - *N_RA_slot = table_6_3_3_2_3_prachConfig_Index[index][6]; // Number of RACH slots within a subframe - if (index >= 67) { - if ((mu == 1) && (*N_RA_slot <= 1) && (slot % 2 == 0)) - return 0; // no prach in even slots @ 30kHz for 1 prach per subframe + if ((info.s_map >> subframe) & 0x01) { + if (config_index >= 67) { + if ((mu == 1) && (info.N_RA_slot <= 1) && (slot % 2 == 0)) + return false; // no prach in even slots @ 30kHz for 1 prach per subframe } else { if ((slot % 2) && (mu > 0)) - return 0; // slot does not contain start symbol of this prach time resource - } - if (start_symbol != NULL && N_t_slot != NULL && N_dur != NULL && format != NULL) { - *config_period = x; - *start_symbol = table_6_3_3_2_3_prachConfig_Index[index][5]; - *N_t_slot = table_6_3_3_2_3_prachConfig_Index[index][7]; - *N_dur = table_6_3_3_2_3_prachConfig_Index[index][8]; - if (table_6_3_3_2_3_prachConfig_Index[index][1] != -1) - format2 = (uint8_t) table_6_3_3_2_3_prachConfig_Index[index][1]; - *format = ((uint8_t) table_6_3_3_2_3_prachConfig_Index[index][0]) | (format2<<8); - LOG_D(MAC,"Frame %d slot %d: Getting PRACH info from index %d (col 6 %lu) absoluteFrequencyPointA %u mu %u frame_type %u start_symbol %u N_t_slot %u N_dur %u N_RA_slot %u RA_sfn_index %u \n", - frame, - slot, - index, - table_6_3_3_2_3_prachConfig_Index[index][6], - pointa, - mu, - unpaired, - *start_symbol, - *N_t_slot, - *N_dur, - *N_RA_slot, - *RA_sfn_index); + return false; // slot does not contain start symbol of this prach time resource } - return 1; - } - else - return 0; // no prach in current slot - } - else - return 0; // no prach in current frame - } - else { // FDD - x = table_6_3_3_2_2_prachConfig_Index[index][2]; - y = table_6_3_3_2_2_prachConfig_Index[index][3]; - if ((frame % x) == y) { - subframe = slot >> mu; - s_map = table_6_3_3_2_2_prachConfig_Index[index][4]; - if ((s_map>>subframe) & 0x01) { - *N_RA_slot = table_6_3_3_2_2_prachConfig_Index[index][6]; // Number of RACH slots within a subframe - if (index >= 87) { - if ((mu == 1) && (*N_RA_slot <= 1) && (slot % 2 == 0)) { - return 0; // no prach in even slots @ 30kHz for 1 prach per subframe + return true; + } else + return false; // no prach in current slot + } else + return false; // no prach in current frame + } else { // FDD + if ((frame % info.x) == info.y) { + int subframe = slot >> mu; + if ((info.s_map >> subframe) & 0x01) { + if (config_index >= 87) { + if ((mu == 1) && (info.N_RA_slot <= 1) && (slot % 2 == 0)) { + return false; // no prach in even slots @ 30kHz for 1 prach per subframe } } else { if ((slot % 2) && (mu > 0)) return 0; // slot does not contain start symbol of this prach time resource } for(int i = 0; i <= subframe ; i++) { - if ((s_map >> i) & 0x01) { + if ((info.s_map >> i) & 0x01) { (*RA_sfn_index)++; } } - if (start_symbol != NULL && N_t_slot != NULL && N_dur != NULL && format != NULL){ - *start_symbol = table_6_3_3_2_2_prachConfig_Index[index][5]; - *config_period = x; - *N_t_slot = table_6_3_3_2_2_prachConfig_Index[index][7]; - *N_dur = table_6_3_3_2_2_prachConfig_Index[index][8]; - if (table_6_3_3_2_2_prachConfig_Index[index][1] != -1) - format2 = (uint8_t) table_6_3_3_2_2_prachConfig_Index[index][1]; - *format = ((uint8_t) table_6_3_3_2_2_prachConfig_Index[index][0]) | (format2<<8); - LOG_D(MAC,"Frame %d slot %d: Getting PRACH info from index %d absoluteFrequencyPointA %u mu %u frame_type %u start_symbol %u N_t_slot %u N_dur %u \n", - frame, - slot, - index, - pointa, - mu, - unpaired, - *start_symbol, - *N_t_slot, - *N_dur); - } - return 1; - } - else - return 0; // no prach in current slot - } - else - return 0; // no prach in current frame + return true; + } else + return false; // no prach in current slot + } else + return false; // no prach in current frame } } } diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h index e5f7fb4fcf614c4f0415782c8138cfac3c70852f..b8d1fae38c59a5d9ff493f6da46ef7391a43fa54 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h @@ -52,6 +52,20 @@ typedef enum { pusch_len2 = 2 } pusch_maxLength_t; +typedef struct { + uint32_t format; + uint32_t start_symbol; + uint32_t N_t_slot; + uint32_t N_dur; + uint32_t N_RA_slot; + uint32_t N_RA_sfn; + uint32_t max_association_period; + int x; + int y; + int y2; + uint64_t s_map; +} nr_prach_info_t; + uint32_t get_Y(const NR_SearchSpace_t *ss, int slot, rnti_t rnti); uint8_t get_BG(uint32_t A, uint16_t R); @@ -144,31 +158,16 @@ void find_aggregation_candidates(uint8_t *aggregation_level, uint16_t get_nr_prach_format_from_index(uint8_t index, uint32_t pointa, uint8_t unpaired); -int get_nr_prach_info_from_index(uint8_t index, - int frame, - int slot, - uint32_t pointa, - uint8_t mu, - uint8_t unpaired, - uint16_t *format, - uint8_t *start_symbol, - uint8_t *N_t_slot, - uint8_t *N_dur, - uint16_t *RA_sfn_index, - uint8_t *N_RA_slot, - uint8_t *config_period); - -int get_nr_prach_occasion_info_from_index(uint8_t index, - uint32_t pointa, - uint8_t mu, - uint8_t unpaired, - uint16_t *format, - uint8_t *start_symbol, - uint8_t *N_t_slot, - uint8_t *N_dur, - uint8_t *N_RA_slot, - uint16_t *N_RA_sfn, - uint8_t *max_association_period); +bool get_nr_prach_sched_from_info(nr_prach_info_t info, + int config_index, + int frame, + int slot, + int mu, + frequency_range_t freq_range, + uint16_t *RA_sfn_index, + uint8_t unpaired); + +nr_prach_info_t get_nr_prach_occasion_info_from_index(uint8_t index, frequency_range_t freq_range, uint8_t unpaired); uint8_t get_pusch_mcs_table(long *mcs_Table, int is_tp, @@ -186,9 +185,7 @@ int ul_ant_bits(NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig, long transformPrec uint8_t get_pdsch_mcs_table(long *mcs_Table, int dci_format, int rnti_type, int ss_type); -int get_format0(uint8_t index, uint8_t unpaired,frequency_range_t); - -const int64_t *get_prach_config_info(frequency_range_t freq_range, uint8_t index, uint8_t unpaired); +int get_format0(uint8_t index, uint8_t unpaired, frequency_range_t frequency_range); uint16_t get_NCS(uint8_t index, uint16_t format, uint8_t restricted_set_config); int compute_pucch_crc_size(int O_uci); diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 09d0eb29281a117f3c069b9f2c4484afeca9009b..8c905a8f588ca7d86dede52898fe44eacc17f5a2 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -44,6 +44,44 @@ #include "oai_asn1.h" #include "executables/position_interface.h" +// Build the list of all the valid/transmitted SSBs according to the config +static void build_ssb_list(NR_UE_MAC_INST_t *mac) +{ + // Create the list of transmitted SSBs + memset(&mac->ssb_list, 0, sizeof(ssb_list_info_t)); + ssb_list_info_t *ssb_list = &mac->ssb_list; + fapi_nr_config_request_t *cfg = &mac->phy_config.config_req; + ssb_list->nb_tx_ssb = 0; + + for (int ssb_index = 0; ssb_index < MAX_NB_SSB; ssb_index++) { + uint32_t curr_mask = cfg->ssb_table.ssb_mask_list[ssb_index / 32].ssb_mask; + // check if if current SSB is transmitted + if ((curr_mask >> (31 - (ssb_index % 32))) & 0x01) { + ssb_list->nb_ssb_per_index[ssb_index] = ssb_list->nb_tx_ssb; + ssb_list->nb_tx_ssb++; + } else + ssb_list->nb_ssb_per_index[ssb_index] = -1; + } +} + +static int get_ta_offset(long *n_TimingAdvanceOffset) +{ + if (!n_TimingAdvanceOffset) + return -1; + + switch (*n_TimingAdvanceOffset) { + case NR_ServingCellConfigCommonSIB__n_TimingAdvanceOffset_n0 : + return 0; + case NR_ServingCellConfigCommonSIB__n_TimingAdvanceOffset_n25600 : + return 25600; + case NR_ServingCellConfigCommonSIB__n_TimingAdvanceOffset_n39936 : + return 39936; + default : + AssertFatal(false, "Invalid n-TimingAdvanceOffset\n"); + } + return -1; +} + static void set_tdd_config_nr_ue(fapi_nr_tdd_table_t *tdd_table, const frame_structure_t *fs) { tdd_table->tdd_period_in_slots = fs->numb_slots_period; @@ -142,6 +180,7 @@ static void config_common_ue_sa(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommo // cell config cfg->cell_config.phy_cell_id = mac->physCellId; cfg->cell_config.frame_duplex_type = frame_type; + cfg->cell_config.N_TA_offset = get_ta_offset(scc->n_TimingAdvanceOffset); // SSB config cfg->ssb_config.ss_pbch_power = scc->ss_PBCH_BlockPower; @@ -187,8 +226,7 @@ static void config_common_ue_sa(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommo else { // If absent, the UE applies the SCS as derived from the prach-ConfigurationIndex (for 839) int config_index = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex; - const int64_t *prach_config_info_p = get_prach_config_info(mac->frequency_range, config_index, frame_type); - int format = prach_config_info_p[0]; + int format = get_format0(config_index, frame_type, mac->frequency_range); cfg->prach_config.prach_sub_c_spacing = get_delta_f_RA_long(format); } @@ -344,6 +382,7 @@ static void config_common_ue(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommon_t // cell config cfg->cell_config.phy_cell_id = *scc->physCellId; cfg->cell_config.frame_duplex_type = frame_type; + cfg->cell_config.N_TA_offset = get_ta_offset(scc->n_TimingAdvanceOffset); // SSB config cfg->ssb_config.ss_pbch_power = scc->ss_PBCH_BlockPower; @@ -411,8 +450,7 @@ static void config_common_ue(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommon_t else { // If absent, the UE applies the SCS as derived from the prach-ConfigurationIndex (for 839) int config_index = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex; - const int64_t *prach_config_info_p = get_prach_config_info(mac->frequency_range, config_index, frame_type); - int format = prach_config_info_p[0]; + int format = get_format0(config_index, frame_type, mac->frequency_range); cfg->prach_config.prach_sub_c_spacing = format == 3 ? 5 : 4; } @@ -1399,7 +1437,7 @@ static void setup_srsconfig(NR_UE_UL_BWP_t *bwp, NR_SRS_Config_t *source, NR_SRS } } -static NR_UE_DL_BWP_t *get_dl_bwp_structure(NR_UE_MAC_INST_t *mac, int bwp_id, bool setup) +NR_UE_DL_BWP_t *get_dl_bwp_structure(NR_UE_MAC_INST_t *mac, int bwp_id, bool setup) { NR_UE_DL_BWP_t *bwp = NULL; for (int i = 0; i < mac->dl_BWPs.count; i++) { @@ -1423,7 +1461,7 @@ static NR_UE_DL_BWP_t *get_dl_bwp_structure(NR_UE_MAC_INST_t *mac, int bwp_id, b return bwp; } -static NR_UE_UL_BWP_t *get_ul_bwp_structure(NR_UE_MAC_INST_t *mac, int bwp_id, bool setup) +NR_UE_UL_BWP_t *get_ul_bwp_structure(NR_UE_MAC_INST_t *mac, int bwp_id, bool setup) { NR_UE_UL_BWP_t *bwp = NULL; for (int i = 0; i < mac->ul_BWPs.count; i++) { @@ -1684,24 +1722,6 @@ void nr_rrc_mac_config_req_reset(module_id_t module_id, NR_UE_MAC_reset_cause_t AssertFatal(!ret, "mutex failed %d\n", ret); } -static int get_ta_offset(long *n_TimingAdvanceOffset) -{ - if (!n_TimingAdvanceOffset) - return -1; - - switch (*n_TimingAdvanceOffset) { - case NR_ServingCellConfigCommonSIB__n_TimingAdvanceOffset_n0 : - return 0; - case NR_ServingCellConfigCommonSIB__n_TimingAdvanceOffset_n25600 : - return 25600; - case NR_ServingCellConfigCommonSIB__n_TimingAdvanceOffset_n39936 : - return 39936; - default : - AssertFatal(false, "Invalid n-TimingAdvanceOffset\n"); - } - return -1; -} - static void configure_si_schedulingInfo(NR_UE_MAC_INST_t *mac, NR_SI_SchedulingInfo_t *si_SchedulingInfo, NR_SI_SchedulingInfo_v1700_t *si_SchedulingInfo_v1700) @@ -1743,17 +1763,18 @@ void nr_rrc_mac_config_req_sib1(module_id_t module_id, int cc_idP, NR_SIB1_t *si AssertFatal(scc, "SIB1 SCC should not be NULL\n"); UPDATE_IE(mac->tdd_UL_DL_ConfigurationCommon, scc->tdd_UL_DL_ConfigurationCommon, NR_TDD_UL_DL_ConfigCommon_t); configure_si_schedulingInfo(mac, si_SchedulingInfo, si_SchedulingInfo_v1700); - mac->n_ta_offset = get_ta_offset(scc->n_TimingAdvanceOffset); config_common_ue_sa(mac, scc, cc_idP); - configure_common_BWP_dl(mac, - 0, // bwp-id - &scc->downlinkConfigCommon.initialDownlinkBWP); + + // Build the list of all the valid/transmitted SSBs according to the config + LOG_D(NR_MAC, "Build SSB list\n"); + build_ssb_list(mac); + + int bwp_id = 0; + configure_common_BWP_dl(mac, bwp_id, &scc->downlinkConfigCommon.initialDownlinkBWP); if (scc->uplinkConfigCommon) { mac->timeAlignmentTimerCommon = scc->uplinkConfigCommon->timeAlignmentTimerCommon; - configure_common_BWP_ul(mac, - 0, // bwp-id - &scc->uplinkConfigCommon->initialUplinkBWP); + configure_common_BWP_ul(mac, bwp_id, &scc->uplinkConfigCommon->initialUplinkBWP); } // set current BWP only if coming from non-connected state // otherwise it is just a periodically update of the SIB1 content @@ -1767,9 +1788,6 @@ void nr_rrc_mac_config_req_sib1(module_id_t module_id, int cc_idP, NR_SIB1_t *si if (mac->state == UE_RECEIVING_SIB && can_start_ra) mac->state = UE_PERFORMING_RA; - // Setup the SSB to Rach Occasions mapping according to the config - build_ssb_to_ro_map(mac); - if (!get_softmodem_params()->emulate_l1) mac->if_module->phy_config_request(&mac->phy_config); ret = pthread_mutex_unlock(&mac->if_mutex); @@ -1812,12 +1830,15 @@ static void handle_reconfiguration_with_sync(NR_UE_MAC_INST_t *mac, if (reconfWithSync->spCellConfigCommon) { NR_ServingCellConfigCommon_t *scc = reconfWithSync->spCellConfigCommon; - mac->n_ta_offset = get_ta_offset(scc->n_TimingAdvanceOffset); if (scc->physCellId) mac->physCellId = *scc->physCellId; mac->dmrs_TypeA_Position = scc->dmrs_TypeA_Position; UPDATE_IE(mac->tdd_UL_DL_ConfigurationCommon, scc->tdd_UL_DL_ConfigurationCommon, NR_TDD_UL_DL_ConfigCommon_t); config_common_ue(mac, scc, cc_idP); + // Build the list of all the valid/transmitted SSBs according to the config + LOG_D(NR_MAC,"Build SSB list\n"); + build_ssb_list(mac); + const int bwp_id = 0; if (scc->downlinkConfigCommon) configure_common_BWP_dl(mac, bwp_id, scc->downlinkConfigCommon->initialDownlinkBWP); @@ -2625,11 +2646,6 @@ void nr_rrc_mac_config_req_cg(module_id_t module_id, if (ue_Capability) handle_mac_uecap_info(mac, ue_Capability); - // Setup the SSB to Rach Occasions mapping according to the config - // Only if RACH is configured for current BWP - if (mac->current_UL_BWP->rach_ConfigCommon) - build_ssb_to_ro_map(mac); - if (!mac->dl_config_request || !mac->ul_config_request) ue_init_config_request(mac, mac->frame_structure.numb_slots_frame); ret = pthread_mutex_unlock(&mac->if_mutex); diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index fbd96532f98892b804bb40ffe4c6b11a73274dcb..cfa3952759ed227fa31299d09f8c1dfd55d35e26 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -79,23 +79,7 @@ /*!\brief value for indicating BSR Timer is not running */ #define NR_MAC_UE_BSR_TIMER_NOT_RUNNING (0xFFFF) -// ================================================ -// SSB to RO mapping private defines and structures -// ================================================ - -#define MAX_NB_PRACH_CONF_PERIOD_IN_ASSOCIATION_PERIOD (16) // Maximum association period is 16 -#define MAX_NB_PRACH_CONF_PERIOD_IN_ASSOCIATION_PATTERN_PERIOD (16) // Max association pattern period is 160ms and minimum PRACH configuration period is 10ms -#define MAX_NB_ASSOCIATION_PERIOD_IN_ASSOCIATION_PATTERN_PERIOD (16) // Max nb of association periods in an association pattern period of 160ms -#define MAX_NB_FRAME_IN_PRACH_CONF_PERIOD (16) // Max PRACH configuration period is 160ms and frame is 10ms -#define MAX_NB_SLOT_IN_FRAME (160) // Max number of slots in a frame (@ SCS 240kHz = 160) -#define MAX_NB_FRAME_IN_ASSOCIATION_PATTERN_PERIOD (16) // Maximum number of frames in the maximum association pattern period #define MAX_NB_SSB (64) // Maximum number of possible SSB indexes -#define MAX_RO_PER_SSB (8) // Maximum number of consecutive ROs that can be mapped to an SSB according to the ssb_per_RACH config - -// Maximum number of ROs that can be mapped to an SSB in an association pattern -// This is to reserve enough elements in the SSBs list for each mapped ROs for a single SSB -// An arbitrary maximum number is chosen to be safe: maximum number of slots in an association pattern * maximum number of ROs in a slot -#define MAX_NB_RO_PER_SSB_IN_ASSOCIATION_PATTERN (MAX_TDM*MAX_FDM*MAX_NB_SLOT_IN_FRAME*MAX_NB_FRAME_IN_ASSOCIATION_PATTERN_PERIOD) // =============== // DCI fields defs @@ -169,6 +153,23 @@ 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 format; // RO preamble format + int frame_info[2]; + int association_period_idx; +} prach_occasion_info_t; + typedef enum { phr_cause_prohibit_timer = 0, phr_cause_periodic_timer, @@ -272,42 +273,41 @@ static const char *const nrra_ue_text[] = {"UE_IDLE", "GENERATE_PREAMBLE", "WAIT_RAR", "WAIT_MSGB", "WAIT_CONTENTION_RESOLUTION", "RA_SUCCEEDED", "RA_FAILED"}; typedef struct { - /// PRACH format retrieved from prach_ConfigIndex - uint16_t prach_format; /// Preamble Tx Counter - uint8_t RA_PREAMBLE_TRANSMISSION_COUNTER; + uint8_t preamble_tx_counter; /// Preamble Power Ramping Counter - uint8_t RA_PREAMBLE_POWER_RAMPING_COUNTER; + uint8_t preamble_power_ramping_cnt; /// 2-step RA power offset - int POWER_OFFSET_2STEP_RA; + int power_offset_2step; /// Target received power at gNB. Baseline is range -202..-60 dBm. Depends on delta preamble, power ramping counter and step. - int ra_PREAMBLE_RECEIVED_TARGET_POWER; - /// PRACH index for TDD (0 ... 6) depending on TDD configuration and prachConfigIndex - uint8_t ra_TDD_map_index; + int ra_preamble_rx_target_power; /// RA Preamble Power Ramping Step in dB - uint32_t RA_PREAMBLE_POWER_RAMPING_STEP; - /// - uint8_t RA_PREAMBLE_BACKOFF; - /// - uint8_t RA_SCALING_FACTOR_BI; - /// Indicating whether it is 2-step or 4-step RA - nr_ra_type_t RA_TYPE; + uint32_t preamble_power_ramping_step; /// UE configured maximum output power - int RA_PCMAX; + 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; + uint32_t ssb_index; + uint32_t prach_mask; +} NR_pdcch_order_config_t; +typedef struct { // pointer to RACH config dedicated NR_RACH_ConfigDedicated_t *rach_ConfigDedicated; /// state of RA procedure nrRA_UE_state_t ra_state; /// RA contention type - uint8_t cfra; + bool cfra; /// RA type nr_ra_type_t ra_type; - /// RA rx frame offset: compensate RA rx offset introduced by OAI gNB. - uint8_t RA_offset; /// MsgB SuccessRAR MAC subheader int8_t MsgB_R; int8_t MsgB_CH_ACESS_CPEXT; @@ -321,53 +321,51 @@ typedef struct { uint16_t MsgB_rnti; /// Temporary CRNTI uint16_t t_crnti; - /// number of attempt for rach - uint8_t RA_attempt_number; /// Random-access procedure flag bool RA_active; /// Random-access preamble index int ra_PreambleIndex; - // When multiple SSBs per RO is configured, this indicates which one is selected in this RO -> this is used to properly compute the PRACH preamble - uint8_t ssb_nb_in_ro; - - /// Random-access window counter - int16_t RA_window_cnt; - /// Flag to monitor if matching RAPID was received in RAR - uint8_t RA_RAPID_found; - /// Flag to monitor if BI was received in RAR - 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; - /// RA backoff counter - int16_t RA_backoff_cnt; + int zeroCorrelationZoneConfig; + int restricted_set_config; + // selected SSB for RACH (not the SSB-Index but the cumulative index, excluding not trasmitted SSBs) + int ra_ssb; + /// Random-access response window timer + NR_timer_t response_window_timer; + int response_window_setup_time; + /// Random-access backoff timer + NR_timer_t RA_backoff_timer; + int RA_backoff_limit; + uint8_t scaling_factor_bi; + /// Flag to indicate whether preambles Group A is selected + bool RA_GroupA; /// 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; - - bool msg3_C_RNTI; - + // initial Random Access Preamble power + int preambleRxTargetPower; + int msg3_deltaPreamble; + int preambleReceivedTargetPower_config; /// Random-access Contention Resolution Timer NR_timer_t contention_resolution_timer; /// Transmitted UE Contention Resolution Identifier uint8_t cont_res_id[6]; - /// BeamfailurerecoveryConfig - NR_BeamFailureRecoveryConfig_t RA_BeamFailureRecoveryConfig; + NR_pdcch_order_config_t pdcch_order; NR_PRACH_RESOURCES_t prach_resources; + + bool new_ssb; + int num_fd_occasions; + int ra_config_index; + 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 { @@ -435,39 +433,8 @@ typedef struct NR_UL_TIME_ALIGNMENT { int slot; } NR_UL_TIME_ALIGNMENT_t; -// The PRACH Config period is a series of selected slots in one or multiple frames -typedef struct prach_conf_period { - prach_occasion_slot_t prach_occasion_slot_map[MAX_NB_FRAME_IN_PRACH_CONF_PERIOD][MAX_NB_SLOT_IN_FRAME]; - uint16_t nb_of_prach_occasion; // Total number of PRACH occasions in the PRACH Config period - uint8_t nb_of_frame; // Size of the PRACH Config period in number of 10ms frames - uint8_t nb_of_slot; // Nb of slots in each frame -} prach_conf_period_t; - -// The association period is a series of PRACH Config periods -typedef struct prach_association_period { - prach_conf_period_t *prach_conf_period_list[MAX_NB_PRACH_CONF_PERIOD_IN_ASSOCIATION_PERIOD]; - uint8_t nb_of_prach_conf_period; // Nb of PRACH configuration periods within the association period - uint8_t nb_of_frame; // Total number of frames included in the association period -} prach_association_period_t; - -// The association pattern is a series of Association periods -typedef struct prach_association_pattern { - prach_association_period_t prach_association_period_list[MAX_NB_ASSOCIATION_PERIOD_IN_ASSOCIATION_PATTERN_PERIOD]; - prach_conf_period_t prach_conf_period_list[MAX_NB_PRACH_CONF_PERIOD_IN_ASSOCIATION_PATTERN_PERIOD]; - uint8_t nb_of_assoc_period; // Nb of association periods within the association pattern - uint8_t nb_of_prach_conf_period_in_max_period; // Nb of PRACH configuration periods within the maximum association pattern period (according to the size of the configured PRACH - uint8_t nb_of_frame; // Total number of frames included in the association pattern period (after mapping the SSBs and determining the real association pattern length) -} prach_association_pattern_t; - -// SSB details -typedef struct ssb_info { - prach_occasion_info_t *mapped_ro[MAX_NB_RO_PER_SSB_IN_ASSOCIATION_PATTERN]; // List of mapped RACH Occasions to this SSB index - uint32_t nb_mapped_ro; // Total number of mapped ROs to this SSB index -} ssb_info_t; - // List of all the possible SSBs and their details typedef struct ssb_list_info { - ssb_info_t *tx_ssb; int nb_tx_ssb; int nb_ssb_per_index[MAX_NB_SSB]; } ssb_list_info_t; @@ -571,14 +538,12 @@ typedef struct NR_UE_MAC_INST_s { NR_UE_L2_STATE_t state; int servCellIndex; long physCellId; - int first_sync_frame; bool get_sib1; bool get_otherSI; NR_MIB_t *mib; si_schedInfo_t si_SchedInfo; - ssb_list_info_t ssb_list[MAX_NUM_BWP_UE]; - prach_association_pattern_t prach_assoc_pattern[MAX_NUM_BWP_UE]; + ssb_list_info_t ssb_list; NR_UE_ServingCell_Info_t sc_info; A_SEQUENCE_OF(NR_UE_DL_BWP_t) dl_BWPs; @@ -632,7 +597,6 @@ typedef struct NR_UE_MAC_INST_s { int dmrs_TypeA_Position; int p_Max; int p_Max_alt; - int n_ta_offset; // -1 not present, otherwise value to be applied ntn_timing_advance_componets_t ntn_ta; @@ -670,6 +634,7 @@ typedef struct NR_UE_MAC_INST_s { int f_b_f_c; bool pusch_power_control_initialized; int delta_msg2; + bool msg3_C_RNTI; pthread_mutex_t if_mutex; ue_mac_stats_t stats; } NR_UE_MAC_INST_t; diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index fbc98964e3fc277c2a7974275f2e3b5061713b7a..a2b2e0f777bd67334a33009ea999c7f0bb903d33 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -45,8 +45,12 @@ \param mac MAC pointer */ void nr_ue_init_mac(NR_UE_MAC_INST_t *mac); +NR_UE_DL_BWP_t *get_dl_bwp_structure(NR_UE_MAC_INST_t *mac, int bwp_id, bool setup); +NR_UE_UL_BWP_t *get_ul_bwp_structure(NR_UE_MAC_INST_t *mac, int bwp_id, bool setup); + void send_srb0_rrc(int ue_id, const uint8_t *sdu, sdu_size_t sdu_len, void *data); -void update_mac_timers(NR_UE_MAC_INST_t *mac); +void update_mac_ul_timers(NR_UE_MAC_INST_t *mac); +void update_mac_dl_timers(NR_UE_MAC_INST_t *mac); NR_LC_SCHEDULING_INFO *get_scheduling_info_from_lcid(NR_UE_MAC_INST_t *mac, NR_LogicalChannelIdentity_t lcid); /**\brief apply default configuration values in nr_mac instance @@ -177,8 +181,6 @@ typedef struct { enum { b_none, b_long, b_short, b_short_trunc, b_long_trunc } type_bsr; } type_bsr_t; -int nr_write_ce_msg3_pdu(uint8_t *mac_ce, NR_UE_MAC_INST_t *mac, rnti_t crnti, uint8_t *mac_ce_end); - int nr_write_ce_ulsch_pdu(uint8_t *mac_ce, NR_UE_MAC_INST_t *mac, NR_SINGLE_ENTRY_PHR_MAC_CE *power_headroom, @@ -211,7 +213,6 @@ void set_harq_status(NR_UE_MAC_INST_t *mac, bool get_downlink_ack(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, PUCCH_sched_t *pucch); initial_pucch_resource_t get_initial_pucch_resource(const int idx); void multiplex_pucch_resource(NR_UE_MAC_INST_t *mac, PUCCH_sched_t *pucch, int num_res); -uint32_t get_backoff_indicator(int idx); int16_t get_pucch_tx_power_ue(NR_UE_MAC_INST_t *mac, int scs, NR_PUCCH_Config_t *pucch_Config, @@ -274,6 +275,8 @@ void ul_ports_config(NR_UE_MAC_INST_t *mac, dci_pdu_rel15_t *dci, nr_dci_format_t dci_format); +bool init_RA(NR_UE_MAC_INST_t *mac, int frame); + /* Random Access */ /* \brief This function schedules the PRACH according to prach_ConfigurationIndex and TS 38.211 tables 6.3.3.2.x and fills the PRACH PDU per each FD occasion. @@ -290,56 +293,17 @@ void configure_csi_resource_mapping(fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_c uint32_t bwp_size, uint32_t bwp_start); -/* \brief This function schedules the Msg3 transmission -@param -@param -@param -@returns void -*/ -void nr_ue_msg3_scheduler(NR_UE_MAC_INST_t *mac, frame_t current_frame, slot_t current_slot, uint8_t Msg3_tda_id); - -void nr_ue_contention_resolution(NR_UE_MAC_INST_t *mac, int cc_id, frame_t frame, int slot, NR_PRACH_RESOURCES_t *prach_resources); - -void nr_ra_failed(NR_UE_MAC_INST_t *mac, uint8_t CC_id, NR_PRACH_RESOURCES_t *prach_resources, frame_t frame, int slot); +void nr_ra_contention_resolution_failed(NR_UE_MAC_INST_t *mac); void nr_ra_succeeded(NR_UE_MAC_INST_t *mac, const uint8_t gNB_index, const frame_t frame, const int slot); - -int16_t nr_get_RA_window_2Step(const NR_MsgA_ConfigCommon_r16_t *msgA_ConfigCommon_r16); - -int16_t nr_get_RA_window_4Step(const NR_RACH_ConfigCommon_t *rach_ConfigCommon); - +void nr_ra_backoff_setting(RA_config_t *ra); void nr_get_RA_window(NR_UE_MAC_INST_t *mac); - -/* \brief Function called by PHY to retrieve information to be transmitted using the RA procedure. -If the UE is not in PUSCH mode for a particular eNB index, this is assumed to be an Msg3 and MAC -attempts to retrieves the CCCH message from RRC. If the UE is in PUSCH mode for a particular eNB -index and PUCCH format 0 (Scheduling Request) is not activated, the MAC may use this resource for -andom-access to transmit a BSR along with the C-RNTI control element (see 5.1.4 from 38.321) -@param mod_id Index of UE instance -@param CC_id Component Carrier Index -@param frame -@param gNB_id gNB index -@param nr_slot_tx slot for PRACH transmission -@returns indication to generate PRACH to phy */ -void nr_ue_get_rach(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); void nr_ue_reset_sync_state(NR_UE_MAC_INST_t *mac); void nr_ue_send_synch_request(NR_UE_MAC_INST_t *mac, module_id_t module_id, int cc_id, const fapi_nr_synch_request_t *sync_req); +bool is_ss_monitor_occasion(const int frame, const int slot, const int slots_per_frame, const NR_SearchSpace_t *ss); /** * @brief Get UE sync state @@ -348,18 +312,12 @@ void nr_ue_send_synch_request(NR_UE_MAC_INST_t *mac, module_id_t module_id, int */ NR_UE_L2_STATE_t nr_ue_get_sync_state(module_id_t mod_id); -void init_RA(NR_UE_MAC_INST_t *mac, - NR_PRACH_RESOURCES_t *prach_resources, - NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon, - NR_RACH_ConfigGeneric_t *rach_ConfigGeneric, - NR_RACH_ConfigDedicated_t *rach_ConfigDedicated); - int16_t get_prach_tx_power(NR_UE_MAC_INST_t *mac); -void free_rach_structures(NR_UE_MAC_INST_t *nr_mac, int bwp_id); void schedule_RA_after_SR_failure(NR_UE_MAC_INST_t *mac); -void nr_Msg1_transmitted(NR_UE_MAC_INST_t *mac); +void nr_rar_not_successful(NR_UE_MAC_INST_t *mac); +void ra_resource_selection(NR_UE_MAC_INST_t *mac); void nr_Msg3_transmitted(NR_UE_MAC_INST_t *mac, uint8_t CC_id, frame_t frameP, slot_t slotP, uint8_t gNB_id); -void trigger_MAC_UE_RA(NR_UE_MAC_INST_t *mac); +void trigger_MAC_UE_RA(NR_UE_MAC_INST_t *mac, dci_pdu_rel15_t *pdcch_order); void nr_get_Msg3_MsgA_PUSCH_payload(NR_UE_MAC_INST_t *mac, uint8_t *buf, int TBS_max); void handle_time_alignment_timer_expired(NR_UE_MAC_INST_t *mac); int8_t nr_ue_process_dci_freq_dom_resource_assignment(nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu, @@ -370,9 +328,7 @@ int8_t nr_ue_process_dci_freq_dom_resource_assignment(nfapi_nr_ue_pusch_pdu_t *p int start_DLBWP, dci_field_t frequency_domain_assignment); -void build_ssb_to_ro_map(NR_UE_MAC_INST_t *mac); - -void ue_init_config_request(NR_UE_MAC_INST_t *mac, int slots_per_frame); +void ue_init_config_request(NR_UE_MAC_INST_t *mac, int scs); fapi_nr_dl_config_request_t *get_dl_config_request(NR_UE_MAC_INST_t *mac, int slot); diff --git a/openair2/LAYER2/NR_MAC_UE/mac_tables.c b/openair2/LAYER2/NR_MAC_UE/mac_tables.c index bd4cc6d8f381088ae5127b16dde6950cf0ec6980..a3136006099a6e9e9ec7bf838b9b9f2f9a3d78ca 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_tables.c +++ b/openair2/LAYER2/NR_MAC_UE/mac_tables.c @@ -412,30 +412,6 @@ static const uint8_t table_7_3_2_3_3_4_twoCodeword[6][14] = { {2,1,1,1,1,0,0,1,1,1,1,0,0,2}, }; -// table 7.2-1 TS 38.321 -static const uint32_t table_7_2_1[16] = { - 5, // row index 0 - 10, // row index 1 - 20, // row index 2 - 30, // row index 3 - 40, // row index 4 - 60, // row index 5 - 80, // row index 6 - 120, // row index 7 - 160, // row index 8 - 240, // row index 9 - 320, // row index 10 - 480, // row index 11 - 960, // row index 12 - 1920, // row index 13 -}; - -uint32_t get_backoff_indicator(int idx) -{ - AssertFatal(idx < 16, "Backoff indicator index %d exeeding table size\n", idx); - return table_7_2_1[idx]; -} - static inline uint16_t packBits(const uint8_t *toPack, const int nb) { int res = 0; diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c index 35167b6173d47dcaebc86a54f8e9f9acb15c8a34..8df19c7139f1d217a5ded8bacf15cde194cd8807 100644 --- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c +++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c @@ -68,7 +68,7 @@ void nr_ue_init_mac(NR_UE_MAC_INST_t *mac) mac->uecap_maxMIMO_PUSCH_layers_nocb = 0; mac->p_Max = INT_MIN; mac->p_Max_alt = INT_MIN; - mac->n_ta_offset = -1; + mac->msg3_C_RNTI = false; mac->ntn_ta.ntn_params_changed = false; reset_mac_inst(mac); @@ -77,8 +77,7 @@ void nr_ue_init_mac(NR_UE_MAC_INST_t *mac) memset(&mac->ssb_measurements, 0, sizeof(mac->ssb_measurements)); memset(&mac->ul_time_alignment, 0, sizeof(mac->ul_time_alignment)); - memset(mac->ssb_list, 0, sizeof(mac->ssb_list)); - memset(mac->prach_assoc_pattern, 0, sizeof(mac->prach_assoc_pattern)); + memset(&mac->ssb_list, 0, sizeof(mac->ssb_list)); for (int i = 0; i < NR_MAX_SR_ID; i++) memset(&mac->scheduling_info.sr_info[i], 0, sizeof(mac->scheduling_info.sr_info[i])); @@ -115,7 +114,6 @@ void nr_ue_send_synch_request(NR_UE_MAC_INST_t *mac, module_id_t module_id, int void nr_ue_reset_sync_state(NR_UE_MAC_INST_t *mac) { // reset synchornization status - mac->first_sync_frame = -1; mac->state = UE_NOT_SYNC; mac->ra.ra_state = nrRA_UE_IDLE; } @@ -181,9 +179,11 @@ void reset_mac_inst(NR_UE_MAC_INST_t *nr_mac) if (nr_mac->data_inactivity_timer) nr_timer_stop(nr_mac->data_inactivity_timer); nr_timer_stop(&nr_mac->time_alignment_timer); - nr_timer_stop(&nr_mac->ra.contention_resolution_timer); nr_timer_stop(&nr_mac->scheduling_info.sr_DelayTimer); nr_timer_stop(&nr_mac->scheduling_info.retxBSR_Timer); + nr_timer_stop(&nr_mac->ra.response_window_timer); + nr_timer_stop(&nr_mac->ra.RA_backoff_timer); + nr_timer_stop(&nr_mac->ra.contention_resolution_timer); for (int i = 0; i < NR_MAX_SR_ID; i++) nr_timer_stop(&nr_mac->scheduling_info.sr_info[i].prohibitTimer); @@ -195,8 +195,10 @@ void reset_mac_inst(NR_UE_MAC_INST_t *nr_mac) nr_mac->ul_harq_info[k].last_ndi = -1; // initialize to invalid value // stop any ongoing RACH procedure - if (nr_mac->ra.ra_state < nrRA_SUCCEEDED) + if (nr_mac->ra.RA_active) { nr_mac->ra.ra_state = nrRA_UE_IDLE; + nr_mac->ra.RA_active = false; + } // discard explicitly signalled contention-free Random Access Resources // TODO not sure what needs to be done here diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c index 51a3ad8c9df51823be8939623b5c99d031f08a93..01b33465e75872188a29e8bbd90e97a72566c1e4 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c @@ -38,126 +38,18 @@ #include "LAYER2/NR_MAC_UE/mac_proto.h" #include <executables/softmodem-common.h> #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; int16_t pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm); - int16_t ra_preamble_rx_power = (int16_t)(ra->prach_resources.ra_PREAMBLE_RECEIVED_TARGET_POWER + pathloss); - return min(ra->prach_resources.RA_PCMAX, ra_preamble_rx_power); + int16_t ra_preamble_rx_power = (int16_t)(ra->prach_resources.ra_preamble_rx_target_power + pathloss); + return min(ra->prach_resources.Pc_max, ra_preamble_rx_power); } -// 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) -void init_RA(NR_UE_MAC_INST_t *mac, - NR_PRACH_RESOURCES_t *prach_resources, - NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon, - NR_RACH_ConfigGeneric_t *rach_ConfigGeneric, - NR_RACH_ConfigDedicated_t *rach_ConfigDedicated) +static void set_preambleTransMax(RA_config_t *ra, long preambleTransMax) { - mac->state = UE_PERFORMING_RA; - RA_config_t *ra = &mac->ra; - ra->RA_active = true; - ra->ra_PreambleIndex = -1; - ra->RA_usedGroupA = 1; - ra->RA_RAPID_found = 0; - ra->preambleTransMax = 0; - ra->first_Msg3 = true; - ra->starting_preamble_nb = 0; - ra->RA_backoff_cnt = 0; - ra->RA_window_cnt = -1; - - fapi_nr_config_request_t *cfg = &mac->phy_config.config_req; - - prach_resources->RA_PREAMBLE_BACKOFF = 0; - NR_SubcarrierSpacing_t prach_scs; - int scs_for_pcmax; // for long prach the UL BWP SCS is used for calculating RA_PCMAX - if (nr_rach_ConfigCommon && nr_rach_ConfigCommon->msg1_SubcarrierSpacing) { - prach_scs = *nr_rach_ConfigCommon->msg1_SubcarrierSpacing; - scs_for_pcmax = prach_scs; - } else { - const unsigned int index = rach_ConfigGeneric->prach_ConfigurationIndex; - const unsigned int unpaired = mac->phy_config.config_req.cell_config.frame_duplex_type; - const unsigned int format = get_format0(index, unpaired, mac->frequency_range); - prach_scs = get_delta_f_RA_long(format); - scs_for_pcmax = mac->current_UL_BWP->scs; - } - int n_prbs = get_N_RA_RB(prach_scs, mac->current_UL_BWP->scs); - int start_prb = rach_ConfigGeneric->msg1_FrequencyStart + mac->current_UL_BWP->BWPStart; - // PRACH shall be as specified for QPSK modulated DFT-s-OFDM of equivalent RB allocation (38.101-1) - prach_resources->RA_PCMAX = nr_get_Pcmax(mac->p_Max, - mac->nr_band, - mac->frame_structure.frame_type, - mac->frequency_range, - mac->current_UL_BWP->channel_bandwidth, - 2, - false, - scs_for_pcmax, - cfg->carrier_config.dl_grid_size[scs_for_pcmax], - true, - n_prbs, - start_prb); - 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; - - - // Contention Free - if (rach_ConfigDedicated) { - if (rach_ConfigDedicated->cfra){ - LOG_I(MAC, "Initialization of 4-Step CFRA procedure\n"); - prach_resources->RA_TYPE = RA_4_STEP; - ra->ra_type = RA_4_STEP; - ra->cfra = 1; - } else if (rach_ConfigDedicated->ext1){ - if (rach_ConfigDedicated->ext1->cfra_TwoStep_r16) { - LOG_I(MAC, "Initialization of 2-Step CFRA procedure\n"); - prach_resources->RA_TYPE = RA_2_STEP; - ra->ra_type = RA_2_STEP; - ra->cfra = 1; - } else { - LOG_E(NR_MAC, "Config not handled\n"); - } - } else { - LOG_E(NR_MAC, "Config not handled\n"); - } - // Contention Based - } else if (mac->current_UL_BWP->msgA_ConfigCommon_r16) { - LOG_I(MAC, "Initialization of 2-Step CBRA procedure\n"); - prach_resources->RA_TYPE = RA_2_STEP; - ra->ra_type = RA_2_STEP; - ra->cfra = 0; - } else if (nr_rach_ConfigCommon) { - LOG_I(MAC, "Initialization of 4-Step CBRA procedure\n"); - prach_resources->RA_TYPE = RA_4_STEP; - ra->ra_type = RA_4_STEP; - ra->cfra = 0; - } else { - LOG_E(MAC, "Config not handled\n"); - AssertFatal(false, "In %s: config not handled\n", __FUNCTION__); - } - - switch (rach_ConfigGeneric->powerRampingStep){ // in dB - case 0: - prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP = 0; - break; - case 1: - prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP = 2; - break; - case 2: - prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP = 4; - break; - case 3: - prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP = 6; - break; - } - - switch (rach_ConfigGeneric->preambleTransMax) { + switch (preambleTransMax) { case 0: ra->preambleTransMax = 3; break; @@ -191,404 +83,983 @@ void init_RA(NR_UE_MAC_INST_t *mac, case 10: ra->preambleTransMax = 200; break; + default: + AssertFatal(false, "Invalid preambleTransMax\n"); } +} - if (ra->ra_type == RA_2_STEP) { - if (nr_rach_ConfigCommon->ext1 && nr_rach_ConfigCommon->ext1->ra_PrioritizationForAccessIdentity_r16) { - LOG_D(MAC, "Missing implementation for Access Identity initialization procedures\n"); - } - // Perform initialization of variables specific to Random Access type as specified in clause 5.1.1a of TS 38.321 - NR_RACH_ConfigGenericTwoStepRA_r16_t nr_ra_ConfigGenericTwoStepRA_r16 = - mac->current_UL_BWP->msgA_ConfigCommon_r16->rach_ConfigCommonTwoStepRA_r16.rach_ConfigGenericTwoStepRA_r16; - // Takes the value of 2-Step RA variable - if (nr_ra_ConfigGenericTwoStepRA_r16.msgA_PreamblePowerRampingStep_r16) { - prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP = *nr_ra_ConfigGenericTwoStepRA_r16.msgA_PreamblePowerRampingStep_r16; - } else { - // If 2-Step variable does not exist, it takes the value of 4-Step RA variable - prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP = nr_rach_ConfigCommon->rach_ConfigGeneric.powerRampingStep; - } - prach_resources->RA_SCALING_FACTOR_BI = 1; - // Takes the value of 2-Step RA variable - if (nr_ra_ConfigGenericTwoStepRA_r16.preambleTransMax_r16) { - ra->preambleTransMax = (int)*nr_ra_ConfigGenericTwoStepRA_r16.preambleTransMax_r16; - } else { - // If 2-Step variable does not exist, it takes the value of 4-Step RA variable - ra->preambleTransMax = (int)nr_rach_ConfigCommon->rach_ConfigGeneric.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 } -/* 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 int get_messagePowerOffsetGroupB(long messagePowerOffsetGroupB) { - 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) { - AssertFatal(prach_format < 4, "Illegal PRACH format %d for sequence length 839\n", prach_format); - switch (prach_format) { - - // long preamble formats - case 0: - case 3: - return 0; - - case 1: - return -3; - - case 2: - return -6; - - default: - AssertFatal(1 == 0, "[UE %d] ue_procedures.c: FATAL, Illegal preambleFormat %d, prachConfigIndex %d\n", - mac->ue_id, - prach_format, - prachConfigIndex); - } - } 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; - - case 1: - case 4: - case 8: - return 5 + 3*mu; - - case 2: - case 5: - return 3 + 3*mu; - - case 6: - return 3*mu; - - case 7: - 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); - } + 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 0; + return pow_offset; } -// TS 38.321 subclause 5.1.3 - RA preamble transmission - ra_PREAMBLE_RECEIVED_TARGET_POWER configuration -// Measurement units: -// - preambleReceivedTargetPower dBm (-202..-60, 2 dBm granularity) -// - delta_preamble dB -// - 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 void select_preamble_group(NR_UE_MAC_INST_t *mac) { - 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); - - receivedTargerPower = preambleReceivedTargetPower + - delta_preamble + - (prach_resources->RA_PREAMBLE_POWER_RAMPING_COUNTER - 1) * prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP + - prach_resources->POWER_OFFSET_2STEP_RA; - - LOG_D(MAC, "ReceivedTargerPower is %d dBm \n", receivedTargerPower); - return receivedTargerPower; + 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->msg3_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 } -void ssb_rach_config(RA_config_t *ra, NR_PRACH_RESOURCES_t *prach_resources, NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon) +static ssb_ro_preambles_t get_ssb_ro_preambles_4step(struct NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB *config) { - // 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){ + ssb_ro_preambles_t ret = {0}; + switch (config->present) { 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); + 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: - 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); + 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: - 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); + 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: - 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); + 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: - 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); + 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: - multiple_ssb_per_ro = true; - ssb_rach_ratio = 4; - ra->cb_preambles_per_ssb = nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.four; + ret.ssb_per_ro = 4; + ret.preambles_per_ssb = config->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; + ret.ssb_per_ro = 8; + ret.preambles_per_ssb = config->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; + ret.ssb_per_ro = 16; + ret.preambles_per_ssb = config->choice.sixteen; break; default: - AssertFatal(1 == 0, "Unsupported ssb_perRACH_config %d\n", ssb_perRACH_config); + 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; +} - if (nr_rach_ConfigCommon->totalNumberOfRA_Preambles) - numberOfRA_Preambles = *(nr_rach_ConfigCommon->totalNumberOfRA_Preambles); +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 = 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 = 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 = 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 : + 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; +} - // 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; +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); + } - ssb_nb_in_ro = ra->ssb_nb_in_ro; - ra->starting_preamble_nb = total_preambles_per_ssb * ssb_nb_in_ro; + NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = mac->current_UL_BWP->rach_ConfigCommon; + 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"); + 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 + // 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 { - total_preambles_per_ssb = numberOfRA_Preambles; - ra->starting_preamble_nb = 0; + 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) + ra->ssb_ro_config = get_ssb_ro_preambles_2step(twostep->msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16); + else + 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; + } + + 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) % 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[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", + ra->ra_PreambleIndex, + nb_of_preambles); +} + +static void configure_ra_preamble(NR_UE_MAC_INST_t *mac) +{ + RA_config_t *ra = &mac->ra; + 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 + // 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 + 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"); + 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) { + 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 + 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) { + 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 + ssb = mac->mib_ssb; + config_preamble_index(mac); + } } + AssertFatal(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 + int ssb_idx = mac->ssb_list.nb_ssb_per_index[ssb]; + ra->new_ssb = ssb != ssb_idx ? true : false; + ra->ra_ssb = ssb_idx; + + // TODO not sure how to handle the RO mask when it is limiting the RO occasions + AssertFatal(ra->ro_mask_index <= 0, "Handling of RACH occasion masking indication not implemented\n"); } -// 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){ +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; +} - int messageSizeGroupA = 0; - int sizeOfRA_PreamblesGroupA = 0; - int messagePowerOffsetGroupB = 0; - int PLThreshold = 0; - long deltaPreamble_Msg3 = 0; - uint8_t noGroupB = 0; - // Random seed generation +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); + 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 scs) +{ 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; + 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(ra->ra_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 * ra->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 + // see 5.3.2 in 211 + int temp_format = prach_info.format >> 8; // B1, B2 or B3 if A1/B1, A2/B2 or A3/B3 formats in tables + if (t != prach_info.N_t_slot - 1 || temp_format == 0xff) + temp_format = prach_info.format & 0xff; + 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 < ra->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 = temp_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++; + } + } - 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); + 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); - 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; + select_prach_occasion(ra, mac->ssb_list.nb_tx_ssb, max_num_occasions, ra_occasions_period, num_ra_occasions_period); +} + +/* TS 38.321 subclause 7.3 - return DELTA_PREAMBLE values in dB */ +static int nr_get_delta_preamble(int scs, int prach_format) +{ + int delta = 0; + switch (prach_format) { + case 0: + case 3: + delta = 0; break; - case 1: - messageSizeGroupA = 144; + case 1: + delta = -3; break; - case 2: - messageSizeGroupA = 208; + case 2: + delta = -6; break; - case 3: - messageSizeGroupA = 256; + case 0xa1: + case 0xb1: + delta = 8 + 3 * scs; break; - case 4: - messageSizeGroupA = 282; + case 0xa2: + case 0xb2: + case 0xc2: + delta = 5 + 3 * scs; break; - case 5: - messageSizeGroupA = 480; + case 0xa3: + case 0xb3: + delta = 3 + 3 * scs; break; - case 6: - messageSizeGroupA = 640; + case 0xb4: + delta = 3 * scs; break; - case 7: - messageSizeGroupA = 800; + case 0xc0: + delta = 11 + 3 * scs; break; - case 8: - messageSizeGroupA = 1000; + default: + AssertFatal(false, "Invalid preamble format %x\n", prach_format); + } + return delta; +} + +static int get_ra_preamble_rx_target_power(RA_config_t *ra, int scs) +{ + NR_PRACH_RESOURCES_t *prach_resources = &ra->prach_resources; + int delta_preamble = nr_get_delta_preamble(scs, ra->sched_ro_info.format); + int tp = ra->preambleReceivedTargetPower_config + delta_preamble + prach_resources->power_offset_2step; + tp += (prach_resources->preamble_power_ramping_cnt - 1) * prach_resources->preamble_power_ramping_step; + return tp; +} + +// 38.321 Sections 5.1.3 and .3a +static void ra_preamble_msga_transmission(RA_config_t *ra, int scs) +{ + NR_PRACH_RESOURCES_t *prach_resources = &ra->prach_resources; + if (prach_resources->preamble_tx_counter > 1) { + // TODO if the notification of suspending power ramping counter has not been received from lower layers (not implemented) + // this happens if the L1 does not transmit PRACH of if the spacial filter changed (UE transmitting in another beam) + // TODO if LBT failure indication was not received from lower layers (LBT not implemented) + // if SSB or CSI-RS selected is not changed from the selection in the last Random Access Preamble transmission + if (!ra->new_ssb) + prach_resources->preamble_power_ramping_cnt++; + } + + + prach_resources->ra_preamble_rx_target_power = get_ra_preamble_rx_target_power(ra, scs); + + ra->ra_rnti = nr_get_ra_rnti(ra->sched_ro_info.start_symbol, ra->sched_ro_info.slot, ra->sched_ro_info.fdm, 0); + if (ra->ra_type == RA_2_STEP) + ra->MsgB_rnti = nr_get_MsgB_rnti(ra->sched_ro_info.start_symbol, ra->sched_ro_info.slot, ra->sched_ro_info.fdm, 0); +} + +// 38.321 Section 5.1.2 Random Access Resource selection +void ra_resource_selection(NR_UE_MAC_INST_t *mac) +{ + configure_ra_preamble(mac); + const NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP; + const int ul_mu = mac->current_UL_BWP->scs; + const int mu = nr_get_prach_or_ul_mu(mac->current_UL_BWP->msgA_ConfigCommon_r16, current_UL_BWP->rach_ConfigCommon, ul_mu); + configure_prach_occasions(mac, mu); + ra_preamble_msga_transmission(&mac->ra, mu); +} + +static int nr_get_RA_window_2Step_v17(long msgB_ResponseWindow) +{ + switch (msgB_ResponseWindow) { + case NR_RACH_ConfigGenericTwoStepRA_r16__ext1__msgB_ResponseWindow_v1700_sl240: + return 240; break; - case 9: - messageSizeGroupA = 72; + case NR_RACH_ConfigGenericTwoStepRA_r16__ext1__msgB_ResponseWindow_v1700_sl640: + return 640; break; - default: - AssertFatal(1 == 0, "Unknown ra_Msg3SizeGroupA %lu\n", setup->groupBconfigured->ra_Msg3SizeGroupA); - /* todo cases 10 -15*/ - } + case NR_RACH_ConfigGenericTwoStepRA_r16__ext1__msgB_ResponseWindow_v1700_sl960: + return 960; + break; + case NR_RACH_ConfigGenericTwoStepRA_r16__ext1__msgB_ResponseWindow_v1700_sl1280: + return 1280; + break; + case NR_RACH_ConfigGenericTwoStepRA_r16__ext1__msgB_ResponseWindow_v1700_sl1920: + return 1920; + break; + case NR_RACH_ConfigGenericTwoStepRA_r16__ext1__msgB_ResponseWindow_v1700_sl2560: + return 2590; + default: + AssertFatal(false, "illegal msgB_responseWindow value %ld\n", msgB_ResponseWindow); + break; + } + return 0; +} - /* Power offset for preamble selection in dB */ - messagePowerOffsetGroupB = -9999; - switch (setup->groupBconfigured->messagePowerOffsetGroupB){ - case 0: - messagePowerOffsetGroupB = -9999; +static int nr_get_RA_window_2Step_v16(long msgB_ResponseWindow) +{ + switch (msgB_ResponseWindow) { + case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl1: + return 1; break; - case 1: - messagePowerOffsetGroupB = 0; + case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl2: + return 2; break; - case 2: - messagePowerOffsetGroupB = 5; + case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl4: + return 4; break; - case 3: - messagePowerOffsetGroupB = 8; + case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl8: + return 8; break; - case 4: - messagePowerOffsetGroupB = 10; + case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl10: + return 10; break; - case 5: - messagePowerOffsetGroupB = 12; + case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl20: + return 20; break; - case 6: - messagePowerOffsetGroupB = 15; + case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl40: + return 40; break; - case 7: - messagePowerOffsetGroupB = 18; + case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl80: + return 80; break; - default: - AssertFatal(1 == 0,"Unknown messagePowerOffsetGroupB %lu\n", setup->groupBconfigured->messagePowerOffsetGroupB); - } + case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl160: + return 160; + break; + case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl320: + return 360; + break; + default: + AssertFatal(false, "illegal msgB_responseWindow value %ld\n", msgB_ResponseWindow); + break; + } + return 0; +} - PLThreshold = prach_resources->RA_PCMAX - rach_ConfigGeneric->preambleReceivedTargetPower - deltaPreamble_Msg3 - messagePowerOffsetGroupB; +static int nr_get_RA_window_4Step_v16(long ra_ResponseWindow) +{ + switch (ra_ResponseWindow) { + case NR_RACH_ConfigGeneric__ext1__ra_ResponseWindow_v1610_sl60: + return 60; + case NR_RACH_ConfigGeneric__ext1__ra_ResponseWindow_v1610_sl160: + return 160; + default: + AssertFatal(false, "illegal ra_ResponseWindow value %ld\n", ra_ResponseWindow); + } + return 0; +} +static int nr_get_RA_window_4Step_v17(long ra_ResponseWindow) +{ + switch (ra_ResponseWindow) { + case NR_RACH_ConfigGeneric__ext2__ra_ResponseWindow_v1700_sl240: + return 240; + case NR_RACH_ConfigGeneric__ext2__ra_ResponseWindow_v1700_sl320: + return 320; + case NR_RACH_ConfigGeneric__ext2__ra_ResponseWindow_v1700_sl640: + return 640; + case NR_RACH_ConfigGeneric__ext2__ra_ResponseWindow_v1700_sl960: + return 960; + case NR_RACH_ConfigGeneric__ext2__ra_ResponseWindow_v1700_sl1280: + return 1280; + case NR_RACH_ConfigGeneric__ext2__ra_ResponseWindow_v1700_sl1920: + return 1920; + case NR_RACH_ConfigGeneric__ext2__ra_ResponseWindow_v1700_sl2560: + return 2590; + default: + AssertFatal(false, "illegal msgB_responseWindow value %ld\n", ra_ResponseWindow); } + return 0; +} - /* 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; - } +static int nr_get_RA_window_4Step(long ra_ResponseWindow) +{ + switch (ra_ResponseWindow) { + case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl1: + return 1; + break; + case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl2: + return 2; + break; + case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl4: + return 4; + break; + case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl8: + return 8; + break; + case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl10: + return 10; + break; + case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl20: + return 20; + break; + case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl40: + return 40; + break; + case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl80: + return 80; + break; + default: + AssertFatal(false, "illegal ra_ResponseWindow value %ld\n", ra_ResponseWindow); + break; + } + return 0; +} + +static void setup_ra_response_window(RA_config_t *ra, + int slots_per_frame, + NR_NTN_Config_r17_t *ntn_Config_r17, + NR_RACH_ConfigGeneric_t *configGeneric, + NR_RACH_ConfigGenericTwoStepRA_r16_t *twostep, + ntn_timing_advance_componets_t *ntn_ta) +{ + int respwind_value = 0; + if (ra->ra_type == RA_2_STEP) { + long *msgB_ResponseWindow = twostep->msgB_ResponseWindow_r16; + if (msgB_ResponseWindow) + respwind_value = nr_get_RA_window_2Step_v16(*msgB_ResponseWindow); + if (twostep->ext1 && twostep->ext1->msgB_ResponseWindow_v1700) { + AssertFatal(msgB_ResponseWindow == NULL, + "The network does not configure msgB-ResponseWindow-r16 simultaneously with msgB-ResponseWindow-v1700\n"); + msgB_ResponseWindow = twostep->ext1->msgB_ResponseWindow_v1700; + if (msgB_ResponseWindow) + respwind_value = nr_get_RA_window_2Step_v17(*msgB_ResponseWindow); } - } 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)); + // The network configures a value lower than or equal to 40ms + int slots_40ms = 4 * slots_per_frame; + AssertFatal(respwind_value != 0 && respwind_value <= slots_40ms, "Invalid MSGB response window value\n"); + } else { + AssertFatal(ra->ra_type == RA_4_STEP, "Invalid RA type\n"); + long *response_window = NULL; + if (configGeneric->ext1 && configGeneric->ext1->ra_ResponseWindow_v1610) + respwind_value = nr_get_RA_window_4Step_v16(*configGeneric->ext1->ra_ResponseWindow_v1610); + if (configGeneric->ext2 && configGeneric->ext2->ra_ResponseWindow_v1700) { + AssertFatal(response_window == NULL, "ra_ResponseWindow_v1610 and ra_ResponseWindow_v1700 are mutually exclusive\n"); + respwind_value = nr_get_RA_window_4Step_v17(*configGeneric->ext2->ra_ResponseWindow_v1700); } + if (!response_window) + respwind_value = nr_get_RA_window_4Step(configGeneric->ra_ResponseWindow); + // The network configures a value lower than or equal to 10ms + AssertFatal(respwind_value != 0, "Invalid RAR response window value\n"); + if (respwind_value > slots_per_frame) + LOG_E(NR_MAC, "RA-ResponseWindow need to be configured to a value lower than or equal to 10 ms\n"); + } + + int ta_Common_slots = 0; + if (ntn_Config_r17) { + const double ta_Common_ms = GET_COMPLETE_TIME_ADVANCE_MS(ntn_ta); + ta_Common_slots = (int)ceil(ta_Common_ms * slots_per_frame / 10); } + + ra->response_window_setup_time = respwind_value + ta_Common_slots; } -// 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 -// 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 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 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 -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) +// 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) +bool init_RA(NR_UE_MAC_INST_t *mac, int frame) { RA_config_t *ra = &mac->ra; + LOG_D(NR_MAC, "Initialization of RA\n"); + ra->ra_state = nrRA_GENERATE_PREAMBLE; + + // TODO this piece of code is required to compute MSG3_size that is used by ra_preambles_config function + // Not a good implementation, it needs improvements + int size_sdu = 0; + + // Concerning the C-RNTI MAC CE, + // it has to be included if the UL transmission (Msg3) is not being made for the CCCH logical channel. + // Therefore it has been assumed that this event only occurs only when RA is done and it is not SA mode. + if (get_softmodem_params()->nsa) { + + uint8_t mac_sdus[34 * 1056]; + uint16_t sdu_lengths[NB_RB_MAX] = {0}; + int TBS_bytes = 848; + int mac_ce_len = 0; + unsigned short post_padding = 1; + + // fill ulsch_buffer with random data + for (int i = 0; i < TBS_bytes; i++) { + mac_sdus[i] = (unsigned char)(rand()&0xff); + } + // Sending SDUs with size 1 + // Initialize elements of sdu_lengths + sdu_lengths[0] = TBS_bytes - 3 - post_padding - mac_ce_len; + size_sdu += sdu_lengths[0]; + + if (size_sdu > 0) { + memcpy(ra->cont_res_id, mac_sdus, sizeof(uint8_t) * 6); + ra->Msg3_size = size_sdu + sizeof(NR_MAC_SUBHEADER_SHORT) + sizeof(NR_MAC_SUBHEADER_SHORT); + } - NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = mac->current_UL_BWP->rach_ConfigCommon; - - LOG_D(MAC, "Getting PRACH resources frame (first_Msg3 %d)\n", ra->first_Msg3); + } else if (!IS_SA_MODE(get_softmodem_params())) + ra->Msg3_size = sizeof(uint16_t) + sizeof(NR_MAC_SUBHEADER_FIXED); - 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); + // Random acces procedure initialization + mac->state = UE_PERFORMING_RA; + ra->RA_active = true; + NR_PRACH_RESOURCES_t *prach_resources = &ra->prach_resources; + fapi_nr_config_request_t *cfg = &mac->phy_config.config_req; + // flush MSG3 buffer + free_and_zero(ra->Msg3_buffer); + // set the PREAMBLE_TRANSMISSION_COUNTER to 1 + prach_resources->preamble_tx_counter = 1; + // set the PREAMBLE_POWER_RAMPING_COUNTER to 1 + prach_resources->preamble_power_ramping_cnt = 1; + // set POWER_OFFSET_2STEP_RA to 0 dB + prach_resources->power_offset_2step = 0; + + const NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP; + // perform the BWP operation as specified in clause 5.15 + // if PRACH occasions are not configured for the active UL BWP + if (!current_UL_BWP->rach_ConfigCommon) { + // switch the active UL BWP to BWP indicated by initialUplinkBWP + current_UL_BWP = get_ul_bwp_structure(mac, 0, false); + // if the Serving Cell is an SpCell + // switch the active DL BWP to BWP indicated by initialDownlinkBWP + mac->current_DL_BWP = get_dl_bwp_structure(mac, 0, false); + } else { + // if the active DL BWP does not have the same bwp-Id as the active UL BWP + if (current_UL_BWP->bwp_id != mac->current_DL_BWP->bwp_id) { + // switch the active DL BWP to the DL BWP with the same bwp-Id as the active UL BWP + mac->current_DL_BWP = get_dl_bwp_structure(mac, 0, false); } + } + + NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = current_UL_BWP->rach_ConfigCommon; + AssertFatal(nr_rach_ConfigCommon, "rach-ConfigCommon should be configured here\n"); + // stop the bwp-InactivityTimer associated with the active DL BWP of this Serving Cell, if running + // TODO bwp-InactivityTimer not implemented + + // if the carrier to use for the Random Access procedure is explicitly signalled (always the case for us) + // PRACH shall be as specified for QPSK modulated DFT-s-OFDM of equivalent RB allocation (38.101-1) + NR_SubcarrierSpacing_t prach_scs; + int scs_for_pcmax; // for long prach the UL BWP SCS is used for calculating RA_PCMAX + NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &nr_rach_ConfigCommon->rach_ConfigGeneric; + if (nr_rach_ConfigCommon->msg1_SubcarrierSpacing) { + prach_scs = *nr_rach_ConfigCommon->msg1_SubcarrierSpacing; + scs_for_pcmax = prach_scs; } 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); + const unsigned int index = rach_ConfigGeneric->prach_ConfigurationIndex; + const unsigned int unpaired = mac->phy_config.config_req.cell_config.frame_duplex_type; + const unsigned int format = get_format0(index, unpaired, mac->frequency_range); + prach_scs = get_delta_f_RA_long(format); + scs_for_pcmax = mac->current_UL_BWP->scs; + } + int n_prbs = get_N_RA_RB(prach_scs, current_UL_BWP->scs); + int start_prb = rach_ConfigGeneric->msg1_FrequencyStart + current_UL_BWP->BWPStart; + prach_resources->Pc_max = nr_get_Pcmax(mac->p_Max, + mac->nr_band, + mac->frame_structure.frame_type, + mac->frequency_range, + current_UL_BWP->channel_bandwidth, + 2, + false, + scs_for_pcmax, + cfg->carrier_config.dl_grid_size[scs_for_pcmax], + true, + n_prbs, + start_prb); + + + // TODO if the Random Access procedure was initiated for SI request + // and the Random Access Resources for SI request have been explicitly provided by RRC + + // TODO if the Random Access procedure was initiated for SpCell beam failure recovery + // and if the contention-free Random Access Resources for beam failure recovery request for 4-step RA type + // have been explicitly provided by RRC for the BWP selected for Random Access procedure + + NR_RACH_ConfigCommonTwoStepRA_r16_t *twostep_conf = NULL; + NR_RACH_ConfigDedicated_t *rach_Dedicated = ra->rach_ConfigDedicated; + + // if the Random Access procedure is initiated by PDCCH order + // and if the ra-PreambleIndex explicitly provided by PDCCH is not 0b000000 + bool pdcch_order = (ra->pdcch_order.active && ra->pdcch_order.preamble_index != 0xb000000) ? true : false; + // or if the Random Access procedure was initiated for reconfiguration with sync and + // if the contention-free Random Access Resources for 4-step RA type have been explicitly provided + // in rach-ConfigDedicated for the BWP selected for Random Access procedure + if ((rach_Dedicated && rach_Dedicated->cfra) || pdcch_order) { + LOG_I(MAC, "Initialization of 4-Step CFRA procedure\n"); + ra->ra_type = RA_4_STEP; + ra->cfra = true; + } else { + bool twostep_cfra = (rach_Dedicated && rach_Dedicated->ext1) ? (rach_Dedicated->ext1->cfra_TwoStep_r16 ? true : false) : false; + if (twostep_cfra) { + // if the Random Access procedure was initiated for reconfiguration with sync and + // if the contention-free Random Access Resources for 2-step RA type have been explicitly provided in rach-ConfigDedicated + LOG_I(MAC, "Initialization of 2-Step CFRA procedure\n"); + ra->ra_type = RA_2_STEP; + ra->cfra = true; + } else { + bool twostep = false; + if (current_UL_BWP->msgA_ConfigCommon_r16) { + twostep_conf = ¤t_UL_BWP->msgA_ConfigCommon_r16->rach_ConfigCommonTwoStepRA_r16; + if (nr_rach_ConfigCommon) { + // if the BWP selected for Random Access procedure is configured with both 2- and 4-step RA type Random Access Resources + // and the RSRP of the downlink pathloss reference is above msgA-RSRP-Threshold + AssertFatal(twostep_conf->msgA_RSRP_Threshold_r16, + "msgA_RSRP_Threshold_r16 is mandatory present if both 2-step and 4-step random access types are configured\n"); + // For thresholds the RSRP value is (IE value – 156) dBm except for the IE 127 in which case the actual value is infinity + int rsrp_msga_thr = *twostep_conf->msgA_RSRP_Threshold_r16 - 156; + if (*twostep_conf->msgA_RSRP_Threshold_r16 != 127 && mac->ssb_measurements.ssb_rsrp_dBm > rsrp_msga_thr) + twostep = true; + } else { + // if the BWP selected for Random Access procedure is only configured with 2-step RA type Random Access + twostep = true; + } + } + if (twostep) { + LOG_I(MAC, "Initialization of 2-Step CBRA procedure\n"); + ra->ra_type = RA_2_STEP; + ra->cfra = false; + } else { + LOG_I(MAC, "Initialization of 4-Step CBRA procedure\n"); + ra->ra_type = RA_4_STEP; + ra->cfra = false; + } + } } - if (prach_resources->RA_PREAMBLE_TRANSMISSION_COUNTER > 1) - prach_resources->RA_PREAMBLE_POWER_RAMPING_COUNTER++; - prach_resources->ra_PREAMBLE_RECEIVED_TARGET_POWER = nr_get_Po_NOMINAL_PUSCH(mac, prach_resources, CC_id); + // need to ask RRC to send the MSG3 data to transmit if needed (CBRA originating from upper layers) + if (!mac->msg3_C_RNTI && ra->cfra == false) + nr_mac_rrc_msg3_ind(mac->ue_id, 0, true); -} + NR_RACH_ConfigGenericTwoStepRA_r16_t *twostep_generic = twostep_conf ? &twostep_conf->rach_ConfigGenericTwoStepRA_r16 : NULL; + if (ra->ra_type == RA_2_STEP && twostep_generic && twostep_generic->msgA_PreamblePowerRampingStep_r16) + prach_resources->preamble_power_ramping_step = *twostep_generic->msgA_PreamblePowerRampingStep_r16 << 1; + else + prach_resources->preamble_power_ramping_step = rach_ConfigGeneric->powerRampingStep << 1; -// TbD: RA_attempt_number not used -void nr_Msg1_transmitted(NR_UE_MAC_INST_t *mac) -{ - RA_config_t *ra = &mac->ra; - ra->ra_state = nrRA_WAIT_RAR; - ra->RA_attempt_number++; + ra->scaling_factor_bi = 1; + + if (ra->ra_type == RA_2_STEP && twostep_generic && twostep_generic->msgA_PreambleReceivedTargetPower_r16) + ra->preambleReceivedTargetPower_config = *twostep_generic->msgA_PreambleReceivedTargetPower_r16; + else + ra->preambleReceivedTargetPower_config = rach_ConfigGeneric->preambleReceivedTargetPower; + + if (ra->ra_type == RA_2_STEP && twostep_generic && twostep_generic->preambleTransMax_r16) + set_preambleTransMax(ra, *twostep_generic->preambleTransMax_r16); + else + set_preambleTransMax(ra, rach_ConfigGeneric->preambleTransMax); + + if (ra->ra_type == RA_2_STEP && twostep_generic && twostep_generic->msgA_ZeroCorrelationZoneConfig_r16) + ra->zeroCorrelationZoneConfig = *twostep_generic->msgA_ZeroCorrelationZoneConfig_r16; + else + ra->zeroCorrelationZoneConfig = rach_ConfigGeneric->zeroCorrelationZoneConfig; + if (ra->ra_type == RA_2_STEP && twostep_conf && twostep_conf->msgA_RestrictedSetConfig_r16) + ra->restricted_set_config = *twostep_conf->msgA_RestrictedSetConfig_r16; + else + ra->restricted_set_config = nr_rach_ConfigCommon->restrictedSetConfig; + + // TODO msgA-TransMax not implemented + // TODO ra-Prioritization not implemented + + 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->msg3_deltaPreamble = *current_UL_BWP->msgA_ConfigCommon_r16->msgA_PUSCH_Config_r16->msgA_DeltaPreamble_r16 << 1; + else + ra->msg3_deltaPreamble = mac->current_UL_BWP->msg3_DeltaPreamble ? *mac->current_UL_BWP->msg3_DeltaPreamble << 1 : 0; + + ra->new_ssb = false; + + if (ra->ra_type == RA_2_STEP && twostep_generic && twostep_generic->msgA_PRACH_ConfigurationIndex_r16) + ra->ra_config_index = *twostep_generic->msgA_PRACH_ConfigurationIndex_r16; + else { + if (rach_ConfigGeneric->ext1 && rach_ConfigGeneric->ext1->prach_ConfigurationIndex_v1610) + ra->ra_config_index = *rach_ConfigGeneric->ext1->prach_ConfigurationIndex_v1610; + else + ra->ra_config_index = rach_ConfigGeneric->prach_ConfigurationIndex; + } + + if (ra->ra_type == RA_2_STEP && twostep_generic && twostep_generic->msgA_RO_FDM_r16) + ra->num_fd_occasions = 1 << *twostep_generic->msgA_RO_FDM_r16; + else + ra->num_fd_occasions = 1 << rach_ConfigGeneric->msg1_FDM; + + setup_ra_response_window(ra, + mac->frame_structure.numb_slots_frame, + mac->sc_info.ntn_Config_r17, + rach_ConfigGeneric, + twostep_generic, + &mac->ntn_ta); + return true; } void nr_Msg3_transmitted(NR_UE_MAC_INST_t *mac, uint8_t CC_id, frame_t frameP, slot_t slotP, uint8_t gNB_id) @@ -663,7 +1134,7 @@ void nr_get_Msg3_MsgA_PUSCH_payload(NR_UE_MAC_INST_t *mac, uint8_t *buf, int TBS } uint8_t *pdu = buf; - if (ra->msg3_C_RNTI) + if (mac->msg3_C_RNTI) pdu = fill_msg3_crnti_pdu(ra, pdu, mac->crnti); else pdu = fill_msg3_pdu_from_rlc(mac, pdu, TBS_max); @@ -679,253 +1150,6 @@ void nr_get_Msg3_MsgA_PUSCH_payload(NR_UE_MAC_INST_t *mac, uint8_t *buf, int TBS memcpy(ra->Msg3_buffer, buf, sizeof(uint8_t) * TBS_max); } -/** - * Function: handles Random Access Preamble Initialization (5.1.1 TS 38.321) - * handles Random Access Response reception (5.1.4 TS 38.321) - * Note: In SA mode the Msg3 contains a CCCH SDU, therefore no C-RNTI MAC CE is transmitted. - * - * @prach_resources pointer to PRACH resources - * @prach_pdu pointer to FAPI UL PRACH PDU - * @mod_id module ID - * @CC_id CC ID - * @frame current UL TX frame - * @gNB_id gNB ID - * @nr_slot_tx current UL TX slot - */ -void nr_ue_get_rach(NR_UE_MAC_INST_t *mac, int CC_id, frame_t frame, uint8_t gNB_id, int nr_slot_tx) -{ - RA_config_t *ra = &mac->ra; - NR_RACH_ConfigDedicated_t *rach_ConfigDedicated = ra->rach_ConfigDedicated; - NR_PRACH_RESOURCES_t *prach_resources = &ra->prach_resources; - - // Delay init RA procedure to allow the convergence of the IIR filter on PRACH noise measurements at gNB side - if (ra->ra_state == nrRA_UE_IDLE) { - LOG_D(NR_MAC, - "ra->ra_state %d frame %d mac->first_sync_frame %d xxx %d", - ra->ra_state, - frame, - mac->first_sync_frame, - ((MAX_FRAME_NUMBER + frame - mac->first_sync_frame) % MAX_FRAME_NUMBER) > 10); - if ((mac->first_sync_frame > -1 || get_softmodem_params()->do_ra || get_softmodem_params()->nsa) - && ((MAX_FRAME_NUMBER + frame - mac->first_sync_frame) % MAX_FRAME_NUMBER) > 150) { - ra->ra_state = nrRA_GENERATE_PREAMBLE; - LOG_D(NR_MAC, "PRACH Condition met: ra state %d, frame %d, sync_frame %d\n", ra->ra_state, frame, mac->first_sync_frame); - } else { - LOG_D(NR_MAC, - "PRACH Condition not met: ra state %d, frame %d, sync_frame %d\n", - ra->ra_state, - frame, - mac->first_sync_frame); - return; - } - } - - 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); - - if (ra->ra_state > nrRA_UE_IDLE && ra->ra_state < nrRA_SUCCEEDED) { - if (!ra->RA_active) { - NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon; - NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric; - init_RA(mac, &ra->prach_resources, setup, rach_ConfigGeneric, ra->rach_ConfigDedicated); - - // TODO this piece of code is required to compute MSG3_size that is used by ra_preambles_config function - // Not a good implementation, it needs improvements - int size_sdu = 0; - - // Concerning the C-RNTI MAC CE, it has to be included if the UL transmission (Msg3) is not being made for the CCCH logical channel. - // Therefore it has been assumed that this event only occurs only when RA is done and it is not SA mode. - if (get_softmodem_params()->nsa) { - - uint8_t mac_sdus[34*1056]; - uint16_t sdu_lengths[NB_RB_MAX] = {0}; - int TBS_bytes = 848; - int mac_ce_len = 0; - unsigned short post_padding = 1; - - // fill ulsch_buffer with random data - for (int i = 0; i < TBS_bytes; i++){ - mac_sdus[i] = (unsigned char) (rand()&0xff); - } - //Sending SDUs with size 1 - //Initialize elements of sdu_lengths - sdu_lengths[0] = TBS_bytes - 3 - post_padding - mac_ce_len; - size_sdu += sdu_lengths[0]; - - if (size_sdu > 0) { - memcpy(ra->cont_res_id, mac_sdus, sizeof(uint8_t) * 6); - ra->Msg3_size = size_sdu + sizeof(NR_MAC_SUBHEADER_SHORT) + sizeof(NR_MAC_SUBHEADER_SHORT); - } - - } else if (!IS_SA_MODE(get_softmodem_params())) { - uint8_t temp_pdu[16] = {0}; - size_sdu = nr_write_ce_msg3_pdu(temp_pdu, mac, mac->crnti, temp_pdu + sizeof(temp_pdu)); - ra->Msg3_size = size_sdu; - } - } else if (ra->RA_window_cnt != -1) { // RACH is active - - LOG_D(MAC, "[%d.%d] RA is active: RA window count %d, RA backoff count %d\n", frame, nr_slot_tx, ra->RA_window_cnt, ra->RA_backoff_cnt); - - if (ra->RA_BI_found){ - prach_resources->RA_PREAMBLE_BACKOFF = prach_resources->RA_SCALING_FACTOR_BI * ra->RA_backoff_indicator; - } else { - prach_resources->RA_PREAMBLE_BACKOFF = 0; - } - - if (ra->RA_window_cnt >= 0 && ra->RA_RAPID_found == 1) { - - if(ra->cfra) { - // Reset RA_active flag: it disables Msg3 retransmission (8.3 of TS 38.213) - nr_ra_succeeded(mac, gNB_id, frame, nr_slot_tx); - } - - } else if (ra->RA_window_cnt == 0 && !ra->RA_RAPID_found && ra->ra_state != nrRA_WAIT_MSGB) { - LOG_W(MAC, "[UE %d][%d:%d] RAR reception failed \n", mac->ue_id, frame, nr_slot_tx); - - nr_ra_failed(mac, CC_id, prach_resources, frame, nr_slot_tx); - - } else if (ra->RA_window_cnt > 0) { - - LOG_D(MAC, "[UE %d][%d.%d]: RAR not received yet (RA window count %d) \n", mac->ue_id, frame, nr_slot_tx, ra->RA_window_cnt); - - // 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); - } - } else if (ra->RA_backoff_cnt > 0) { - - LOG_D(MAC, "[UE %d][%d.%d]: RAR not received yet (RA backoff count %d) \n", mac->ue_id, frame, nr_slot_tx, ra->RA_backoff_cnt); - - 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); - } - } - } - } - - if (nr_timer_is_active(&ra->contention_resolution_timer)) { - nr_ue_contention_resolution(mac, CC_id, frame, nr_slot_tx, prach_resources); - } -} - -int16_t nr_get_RA_window_2Step(const NR_MsgA_ConfigCommon_r16_t *msgA_ConfigCommon_r16) -{ - int16_t ra_ResponseWindow = *msgA_ConfigCommon_r16->rach_ConfigCommonTwoStepRA_r16 - .rach_ConfigGenericTwoStepRA_r16.msgB_ResponseWindow_r16; - - switch (ra_ResponseWindow) { - case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl1: - return 1; - break; - case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl2: - return 2; - break; - case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl4: - return 4; - break; - case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl8: - return 8; - break; - case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl10: - return 10; - break; - case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl20: - return 20; - break; - case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl40: - return 40; - break; - case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl80: - return 80; - break; - case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl160: - return 160; - break; - case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl320: - return 360; - break; - default: - AssertFatal(false, "illegal msgB_responseWindow value %d\n", ra_ResponseWindow); - break; - } - return 0; -} - -int16_t nr_get_RA_window_4Step(const NR_RACH_ConfigCommon_t *rach_ConfigCommon) -{ - int16_t ra_ResponseWindow = rach_ConfigCommon->rach_ConfigGeneric.ra_ResponseWindow; - - switch (ra_ResponseWindow) { - case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl1: - return 1; - break; - case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl2: - return 2; - break; - case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl4: - return 4; - break; - case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl8: - return 8; - break; - case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl10: - return 10; - break; - case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl20: - return 20; - break; - case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl40: - return 40; - break; - case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl80: - return 80; - break; - default: - AssertFatal(false, "illegal ra_ResponseWindow value %d\n", ra_ResponseWindow); - break; - } - return 0; -} - -void nr_get_RA_window(NR_UE_MAC_INST_t *mac) -{ - RA_config_t *ra = &mac->ra; - NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon; - AssertFatal(&setup->rach_ConfigGeneric != NULL, "In %s: FATAL! rach_ConfigGeneric is NULL...\n", __FUNCTION__); - const double ta_Common_ms = GET_COMPLETE_TIME_ADVANCE_MS(&mac->ntn_ta); - int slots_per_frame = mac->frame_structure.numb_slots_frame; - const int slots_per_ms = slots_per_frame / 10; - const int ra_Offset_slots = ra->RA_offset * slots_per_frame; - const int ta_Common_slots = (int)ceil(ta_Common_ms * slots_per_ms); - - ra->RA_window_cnt = ra_Offset_slots + ta_Common_slots; // taking into account the 2 frames gap introduced by OAI gNB - - ra->RA_window_cnt += ra->ra_type == RA_2_STEP ? nr_get_RA_window_2Step(mac->current_UL_BWP->msgA_ConfigCommon_r16) - : nr_get_RA_window_4Step(mac->current_UL_BWP->rach_ConfigCommon); -} - -//////////////////////////////////////////////////////////////////////////// -/////////* 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(NR_UE_MAC_INST_t *mac, int cc_id, frame_t frame, int slot, NR_PRACH_RESOURCES_t *prach_resources) -{ - RA_config_t *ra = &mac->ra; - - if (nr_timer_expired(&ra->contention_resolution_timer)) { - ra->t_crnti = 0; - nr_timer_stop(&ra->contention_resolution_timer); - // Signal PHY to quit RA procedure - LOG_E(MAC, "[UE %d] 4-Step CBRA: Contention resolution timer has expired, RA procedure has failed...\n", mac->ue_id); - nr_ra_failed(mac, 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: @@ -936,90 +1160,95 @@ void nr_ra_succeeded(NR_UE_MAC_INST_t *mac, const uint8_t gNB_index, const frame if (ra->cfra) { LOG_I(MAC, "[UE %d][%d.%d][RAPROC] RA procedure succeeded. CFRA: RAR successfully received.\n", mac->ue_id, frame, slot); - ra->RA_window_cnt = -1; - } else if (ra->ra_type == RA_2_STEP) { - LOG_A(MAC, - "[UE %d][%d.%d][RAPROC] 2-Step RA procedure succeeded. CBRA: Contention Resolution is successful.\n", - mac->ue_id, - frame, - slot); - mac->crnti = ra->t_crnti; - ra->t_crnti = 0; - LOG_D(MAC, "[UE %d][%d.%d] CBRA: cleared response window timer...\n", mac->ue_id, frame, slot); } else { LOG_A(MAC, - "[UE %d][%d.%d][RAPROC] 4-Step RA procedure succeeded. CBRA: Contention Resolution is successful.\n", + "[UE %d][%d.%d][RAPROC] %d-Step RA procedure succeeded. CBRA: Contention Resolution is successful.\n", mac->ue_id, frame, - slot); - nr_timer_stop(&ra->contention_resolution_timer); + slot, + ra->ra_type == RA_2_STEP ? 2 : 4); mac->crnti = ra->t_crnti; ra->t_crnti = 0; - LOG_D(MAC, "[UE %d][%d.%d] CBRA: cleared contention resolution timer...\n", mac->ue_id, frame, slot); + nr_timer_stop(&ra->contention_resolution_timer); } - LOG_D(MAC, "[UE %d] clearing RA_active flag...\n", mac->ue_id); ra->RA_active = false; - ra->msg3_C_RNTI = false; + mac->msg3_C_RNTI = false; ra->ra_state = nrRA_SUCCEEDED; mac->state = UE_CONNECTED; free_and_zero(ra->Msg3_buffer); - nr_mac_rrc_ra_ind(mac->ue_id, frame, true); + nr_mac_rrc_ra_ind(mac->ue_id, true); } -// Handling 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 -void nr_ra_failed(NR_UE_MAC_INST_t *mac, uint8_t CC_id, NR_PRACH_RESOURCES_t *prach_resources, frame_t frame, int slot) +void nr_ra_backoff_setting(RA_config_t *ra) { - RA_config_t *ra = &mac->ra; - // Random seed generation - unsigned int seed; + // select a random backoff time according to a uniform distribution + // between 0 and the PREAMBLE_BACKOFF + uint32_t seed = (unsigned int)(rdtsc_oai() & ~0); + uint32_t random_backoff = ra->RA_backoff_limit ? rand_r(&seed) % ra->RA_backoff_limit : 0; // in slots + nr_timer_setup(&ra->RA_backoff_timer, random_backoff, 1); + nr_timer_start(&ra->RA_backoff_timer); +} - if (IS_SOFTMODEM_IQPLAYER || IS_SOFTMODEM_IQRECORDER) { - // Overwrite seed with non-random seed for IQ player/recorder - seed = 1; +void nr_ra_contention_resolution_failed(NR_UE_MAC_INST_t *mac) +{ + LOG_W(MAC, "[UE %d] Contention resolution failed\n", mac->ue_id); + RA_config_t *ra = &mac->ra; + // discard the TEMPORARY_C-RNTI + ra->t_crnti = 0; + // flush MSG3 buffer + free_and_zero(ra->Msg3_buffer); + nr_mac_rrc_msg3_ind(mac->ue_id, 0, true); + NR_PRACH_RESOURCES_t *prach_resources = &ra->prach_resources; + prach_resources->preamble_tx_counter++; + if (prach_resources->preamble_tx_counter == ra->preambleTransMax + 1) { + // indicate a Random Access problem to upper layers + nr_mac_rrc_ra_ind(mac->ue_id, false); } else { - // & to truncate the int64_t and keep only the LSB bits, up to sizeof(int) - seed = (unsigned int) (rdtsc_oai() & ~0); + // TODO handle msgA-TransMax (go back to 4-step if the threshold is reached) + // starting backoff time + nr_ra_backoff_setting(ra); } - - ra->first_Msg3 = true; - ra->ra_PreambleIndex = -1; - ra->ra_state = nrRA_UE_IDLE; - - prach_resources->RA_PREAMBLE_TRANSMISSION_COUNTER++; - - // when the Contention Resolution is considered not successful - // stop timeAlignmentTimer - nr_timer_stop(&mac->time_alignment_timer); - - if (prach_resources->RA_PREAMBLE_TRANSMISSION_COUNTER == ra->preambleTransMax + 1) { - - LOG_D(NR_MAC, - "[UE %d][%d.%d] Maximum number of RACH attempts (%d) reached, selecting backoff time...\n", - mac->ue_id, - frame, - slot, - ra->preambleTransMax); - - ra->RA_backoff_cnt = rand_r(&seed) % (prach_resources->RA_PREAMBLE_BACKOFF + 1); - 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(mac, prach_resources, CC_id); +} - } else { - nr_get_RA_window(mac); +void nr_rar_not_successful(NR_UE_MAC_INST_t *mac) +{ + LOG_W(MAC, "[UE %d] RAR reception failed\n", mac->ue_id); + RA_config_t *ra = &mac->ra; + NR_PRACH_RESOURCES_t *prach_resources = &ra->prach_resources; + prach_resources->preamble_tx_counter++; + bool ra_completed = false; + if (prach_resources->preamble_tx_counter == ra->preambleTransMax + 1) { + // if the Random Access Preamble is transmitted on the SpCell + // TODO to be verified, this means SA if I'm not mistaken + if (IS_SA_MODE(get_softmodem_params())) { + // indicate a Random Access problem to upper layers + nr_mac_rrc_ra_ind(mac->ue_id, false); + } else { + // if the Random Access Preamble is transmitted on an SCell: + // consider the Random Access procedure unsuccessfully completed. + ra_completed = true; + ra->ra_state = nrRA_UE_IDLE; + } + } + if (!ra_completed) { + nr_ra_backoff_setting(ra); } } -void trigger_MAC_UE_RA(NR_UE_MAC_INST_t *mac) +void trigger_MAC_UE_RA(NR_UE_MAC_INST_t *mac, dci_pdu_rel15_t *pdcch_order) { LOG_W(NR_MAC, "Triggering new RA procedure for UE with RNTI %x\n", mac->crnti); mac->state = UE_PERFORMING_RA; reset_ra(mac, false); - mac->ra.msg3_C_RNTI = true; + RA_config_t *ra = &mac->ra; + mac->msg3_C_RNTI = true; + if (pdcch_order) { + ra->pdcch_order.active = true; + ra->pdcch_order.preamble_index = pdcch_order->ra_preamble_index; + ra->pdcch_order.ssb_index = pdcch_order->ss_pbch_index; + ra->pdcch_order.prach_mask = pdcch_order->prach_mask_index; + } } void prepare_msg4_msgb_feedback(NR_UE_MAC_INST_t *mac, int pid, int ack_nack) @@ -1048,16 +1277,6 @@ void prepare_msg4_msgb_feedback(NR_UE_MAC_INST_t *mac, int pid, int ack_nack) release_ul_config(pdu, false); } -void free_rach_structures(NR_UE_MAC_INST_t *nr_mac, int bwp_id) -{ - for (int j = 0; j < MAX_NB_PRACH_CONF_PERIOD_IN_ASSOCIATION_PATTERN_PERIOD; j++) - for (int k = 0; k < MAX_NB_FRAME_IN_PRACH_CONF_PERIOD; k++) - for (int l = 0; l < MAX_NB_SLOT_IN_FRAME; l++) - free(nr_mac->prach_assoc_pattern[bwp_id].prach_conf_period_list[j].prach_occasion_slot_map[k][l].prach_occasion); - - free(nr_mac->ssb_list[bwp_id].tx_ssb); -} - void reset_ra(NR_UE_MAC_INST_t *nr_mac, bool free_prach) { RA_config_t *ra = &nr_mac->ra; @@ -1067,7 +1286,4 @@ void reset_ra(NR_UE_MAC_INST_t *nr_mac, bool free_prach) if (!free_prach) return; - - for (int i = 0; i < MAX_NUM_BWP_UE; i++) - free_rach_structures(nr_mac, i); } diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c index aeeab40b7462f431a5273ddf350e4267ca4e9e88..3817e067593fcc49407761d18b7be15d660498d5 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c @@ -442,8 +442,8 @@ bool search_space_monitoring_ocasion_other_si(NR_UE_MAC_INST_t *mac, get_monitoring_period_offset(ss, &period, &offset); for (int i = 0; i < duration; i++) { if (((frame * slots_per_frame + slot - offset - i) % period) == 0) { - int N = mac->ssb_list[bwp_id].nb_tx_ssb; - int K = mac->ssb_list->nb_ssb_per_index[mac->mib_ssb]; + int N = mac->ssb_list.nb_tx_ssb; + int K = mac->ssb_list.nb_ssb_per_index[mac->mib_ssb]; // numbering current frame and slot in terms of monitoring occasions in window int rel_slot = abs_slot - mac->si_SchedInfo.si_window_start; @@ -560,12 +560,13 @@ void ue_dci_configuration(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_request_t *dl config_dci_pdu(mac, dl_config, TYPE_SI_RNTI_, slot, ss); } } - if (mac->state == UE_PERFORMING_RA && mac->ra.ra_state >= nrRA_WAIT_RAR) { + RA_config_t *ra = &mac->ra; + if (mac->state == UE_PERFORMING_RA && ra->ra_state >= nrRA_WAIT_RAR) { // if RA is ongoing use RA search space if (is_ss_monitor_occasion(frame, slot, slots_per_frame, pdcch_config->ra_SS)) { nr_rnti_type_t rnti_type = 0; - if (mac->ra.ra_type == RA_4_STEP) { - rnti_type = mac->ra.ra_state == nrRA_WAIT_RAR ? TYPE_RA_RNTI_ : TYPE_TC_RNTI_; + if (ra->ra_type == RA_4_STEP) { + rnti_type = ra->ra_state == nrRA_WAIT_RAR ? TYPE_RA_RNTI_ : TYPE_TC_RNTI_; } else { rnti_type = TYPE_MSGB_RNTI_; } diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c index 7083b4a14100464fecb1e16f681207c870a083b0..9db464f0152fbe066618f5f910f356db8bd63ffa 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c @@ -372,8 +372,8 @@ int16_t get_pucch_tx_power_ue(NR_UE_MAC_INST_t *mac, if (mac->pucch_power_control_initialized == false) { // Initialize power control state // Assuming only sending on PCell - NR_PRACH_RESOURCES_t* prach_resources = &mac->ra.prach_resources; - float DELTA_P_rampup_requested = (prach_resources->RA_PREAMBLE_POWER_RAMPING_COUNTER - 1) * prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP; + NR_PRACH_RESOURCES_t *prach_res = &mac->ra.prach_resources; + float DELTA_P_rampup_requested = (prach_res->preamble_power_ramping_cnt - 1) * prach_res->preamble_power_ramping_step; float DELTA_P_rampup = P_CMAX - (P_O_PUCCH + pathloss + delta_F_PUCCH + DELTA_TF + sum_delta_pucch); DELTA_P_rampup = max(min(0, DELTA_P_rampup), DELTA_P_rampup_requested); mac->G_b_f_c = DELTA_P_rampup + sum_delta_pucch; @@ -492,9 +492,7 @@ int get_pusch_tx_power_ue(NR_UE_MAC_INST_t *mac, if (current_UL_BWP->msg3_DeltaPreamble) { DELTA_PREAMBLE_MSG3 = *current_UL_BWP->msg3_DeltaPreamble; } - NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = current_UL_BWP->rach_ConfigCommon; - long preambleReceivedTargetPower = nr_rach_ConfigCommon->rach_ConfigGeneric.preambleReceivedTargetPower; - int P_O_PRE = preambleReceivedTargetPower; + int P_O_PRE = mac->ra.prach_resources.ra_preamble_rx_target_power; P_O_NOMINAL_PUSCH = P_O_PRE + DELTA_PREAMBLE_MSG3; if (has_pusch_power_control_config && pusch_Config->pusch_PowerControl->msg3_Alpha) { @@ -572,8 +570,8 @@ int get_pusch_tx_power_ue(NR_UE_MAC_INST_t *mac, f_b_f_c = delta_pusch; } else { if (!mac->pusch_power_control_initialized && is_rar_tx_retx) { - NR_PRACH_RESOURCES_t* prach_resources = &mac->ra.prach_resources; - float DELTA_P_rampup_requested = (prach_resources->RA_PREAMBLE_POWER_RAMPING_COUNTER - 1) * prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP; + NR_PRACH_RESOURCES_t *prach_res = &mac->ra.prach_resources; + float DELTA_P_rampup_requested = (prach_res->preamble_power_ramping_cnt - 1) * prach_res->preamble_power_ramping_step; float DELTA_P_rampup = P_CMAX - (P_O_PUSCH + M_pusch_component + alpha * pathloss + DELTA_TF + delta_pusch); DELTA_P_rampup = min(DELTA_P_rampup_requested, max(0, DELTA_P_rampup)); mac->f_b_f_c = DELTA_P_rampup + delta_pusch; @@ -654,9 +652,8 @@ int get_srs_tx_power_ue(NR_UE_MAC_INST_t *mac, if (!is_tpc_accumulation_provided && (!is_configured_for_pusch_on_current_bwp || separate_pc_adjustment_state)) { if (!current_UL_BWP->srs_power_control_initialized) { - NR_PRACH_RESOURCES_t *prach_resources = &mac->ra.prach_resources; - float DELTA_P_rampup_requested = - (prach_resources->RA_PREAMBLE_POWER_RAMPING_COUNTER - 1) * prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP; + NR_PRACH_RESOURCES_t *prach = &mac->ra.prach_resources; + float DELTA_P_rampup_requested = (prach->preamble_power_ramping_cnt - 1) * prach->preamble_power_ramping_step; float DELTA_P_rampup = P_CMAX - (P_0_SRS + m_srs_component + alpha * pathloss); DELTA_P_rampup = min(DELTA_P_rampup_requested, max(0, DELTA_P_rampup)); current_UL_BWP->srs_power_control_initialized = true; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index c150cc29cdf67497be2242ba135bcc3fe3fdd06c..83bbcadbe5341068e5146594c1adfecc17eff007 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -59,6 +59,25 @@ // #define DEBUG_MIB // #define ENABLE_MAC_PAYLOAD_DEBUG 1 // #define DEBUG_RAR + +// table 7.2-1 TS 38.321 +const uint16_t table_7_2_1[16] = { + 5, // row index 0 + 10, // row index 1 + 20, // row index 2 + 30, // row index 3 + 40, // row index 4 + 60, // row index 5 + 80, // row index 6 + 120, // row index 7 + 160, // row index 8 + 240, // row index 9 + 320, // row index 10 + 480, // row index 11 + 960, // row index 12 + 1920, // row index 13 +}; + /* TS 36.213 Table 9.2.3-3: Mapping of values for one HARQ-ACK bit to sequences */ static const int sequence_cyclic_shift_1_harq_ack_bit[2] /* HARQ-ACK Value 0 1 */ @@ -219,9 +238,6 @@ void nr_ue_decode_mib(NR_UE_MAC_INST_t *mac, int cc_id) mac->ssb_subcarrier_offset = ssb_subcarrier_offset; mac->dmrs_TypeA_Position = mac->mib->dmrs_TypeA_Position; - if (mac->first_sync_frame == -1) - mac->first_sync_frame = frame; - if (get_softmodem_params()->phy_test) mac->state = UE_CONNECTED; else if (mac->state == UE_NOT_SYNC) { @@ -701,7 +717,7 @@ static int nr_ue_process_dci_dl_10(NR_UE_MAC_INST_t *mac, dlsch_pdu->SubcarrierSpacing = mac->mib->subCarrierSpacingCommon + 2; } else { dlsch_pdu->SubcarrierSpacing = current_DL_BWP->scs; - if (mac->ra.RA_window_cnt >= 0 && rnti_type == TYPE_RA_RNTI_) { + if (nr_timer_is_active(&mac->ra.response_window_timer) && rnti_type == TYPE_RA_RNTI_) { dl_conf_req->pdu_type = FAPI_NR_DL_CONFIG_TYPE_RA_DLSCH; } else { dl_conf_req->pdu_type = FAPI_NR_DL_CONFIG_TYPE_DLSCH; @@ -2929,7 +2945,7 @@ void nr_ue_send_sdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info, in nr_timer_start(mac->data_inactivity_timer); // DL data arrival during RRC_CONNECTED when UL synchronisation status is "non-synchronised" if (!nr_timer_is_active(&mac->time_alignment_timer) && mac->state == UE_CONNECTED && !get_softmodem_params()->phy_test) { - trigger_MAC_UE_RA(mac); + trigger_MAC_UE_RA(mac, NULL); break; } nr_ue_process_mac_pdu(mac, dl_info, pdu_id); @@ -2991,7 +3007,11 @@ static void extract_10_si_rnti(dci_pdu_rel15_t *dci_pdu_rel15, const uint8_t *dc EXTRACT_DCI_ITEM(dci_pdu_rel15->system_info_indicator, 1); } -static void extract_10_c_rnti(dci_pdu_rel15_t *dci_pdu_rel15, const uint8_t *dci_pdu, int pos, const int N_RB) +static bool extract_10_c_rnti(NR_UE_MAC_INST_t *mac, + dci_pdu_rel15_t *dci_pdu_rel15, + const uint8_t *dci_pdu, + int pos, + const int N_RB) { LOG_D(NR_MAC_DCI, "Received dci 1_0 C rnti\n"); @@ -3014,29 +3034,31 @@ static void extract_10_c_rnti(dci_pdu_rel15_t *dci_pdu_rel15, const uint8_t *dci EXTRACT_DCI_ITEM(dci_pdu_rel15->ss_pbch_index, 6); // prach_mask_index 4 bits EXTRACT_DCI_ITEM(dci_pdu_rel15->prach_mask_index, 4); + trigger_MAC_UE_RA(mac, dci_pdu_rel15); + return true; } // end if - else { - // Time domain assignment 4bit - EXTRACT_DCI_ITEM(dci_pdu_rel15->time_domain_assignment.val, 4); - // VRB to PRB mapping 1bit - EXTRACT_DCI_ITEM(dci_pdu_rel15->vrb_to_prb_mapping.val, 1); - // MCS 5bit //bit over 32, so dci_pdu ++ - EXTRACT_DCI_ITEM(dci_pdu_rel15->mcs, 5); - // New data indicator 1bit - EXTRACT_DCI_ITEM(dci_pdu_rel15->ndi, 1); - // Redundancy version 2bit - EXTRACT_DCI_ITEM(dci_pdu_rel15->rv, 2); - // HARQ process number 4/5 bit - EXTRACT_DCI_ITEM(dci_pdu_rel15->harq_pid.val, dci_pdu_rel15->harq_pid.nbits); - // Downlink assignment index 2bit - EXTRACT_DCI_ITEM(dci_pdu_rel15->dai[0].val, 2); - // TPC command for scheduled PUCCH 2bit - EXTRACT_DCI_ITEM(dci_pdu_rel15->tpc, 2); - // PUCCH resource indicator 3bit - EXTRACT_DCI_ITEM(dci_pdu_rel15->pucch_resource_indicator, 3); - // PDSCH-to-HARQ_feedback timing indicator 3bit - EXTRACT_DCI_ITEM(dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.val, 3); - } // end else + + // Time domain assignment 4bit + EXTRACT_DCI_ITEM(dci_pdu_rel15->time_domain_assignment.val, 4); + // VRB to PRB mapping 1bit + EXTRACT_DCI_ITEM(dci_pdu_rel15->vrb_to_prb_mapping.val, 1); + // MCS 5bit //bit over 32, so dci_pdu ++ + EXTRACT_DCI_ITEM(dci_pdu_rel15->mcs, 5); + // New data indicator 1bit + EXTRACT_DCI_ITEM(dci_pdu_rel15->ndi, 1); + // Redundancy version 2bit + EXTRACT_DCI_ITEM(dci_pdu_rel15->rv, 2); + // HARQ process number 4/5 bit + EXTRACT_DCI_ITEM(dci_pdu_rel15->harq_pid.val, dci_pdu_rel15->harq_pid.nbits); + // Downlink assignment index 2bit + EXTRACT_DCI_ITEM(dci_pdu_rel15->dai[0].val, 2); + // TPC command for scheduled PUCCH 2bit + EXTRACT_DCI_ITEM(dci_pdu_rel15->tpc, 2); + // PUCCH resource indicator 3bit + EXTRACT_DCI_ITEM(dci_pdu_rel15->pucch_resource_indicator, 3); + // PDSCH-to-HARQ_feedback timing indicator 3bit + EXTRACT_DCI_ITEM(dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.val, 3); + return false; } static void extract_00_c_rnti(dci_pdu_rel15_t *dci_pdu_rel15, const uint8_t *dci_pdu, int pos) @@ -3297,7 +3319,9 @@ static nr_dci_format_t nr_extract_dci_00_10(NR_UE_MAC_INST_t *mac, int n_RB = get_nrb_for_dci(mac, format, ss_type); if (n_RB == 0) return NR_DCI_NONE; - extract_10_c_rnti(dci_pdu_rel15, dci_pdu, pos, n_RB); + bool pdcch_order = extract_10_c_rnti(mac, dci_pdu_rel15, dci_pdu, pos, n_RB); + if (pdcch_order) + return NR_DCI_NONE; } else { format = NR_UL_DCI_FORMAT_0_0; @@ -3406,11 +3430,11 @@ static bool check_ra_contention_resolution(const uint8_t *pdu, const uint8_t *co } static int nr_ue_validate_successrar(uint8_t *pduP, - int32_t pdu_len, - NR_UE_MAC_INST_t *mac, - uint8_t gNB_index, - frame_t frameP, - int slot) + int32_t pdu_len, + NR_UE_MAC_INST_t *mac, + uint8_t gNB_index, + frame_t frameP, + int slot) { // TS 38.321 - Figure 6.1.5a-1: BI MAC subheader // TS 38.321 - Figure 6.1.5a-3: SuccessRAR MAC subheader @@ -3418,6 +3442,7 @@ static int nr_ue_validate_successrar(uint8_t *pduP, uint8_t E = 1; uint8_t cont_res_id[6]; RA_config_t *ra = &mac->ra; + ra->RA_backoff_limit = 0; while (n < pdu_len && E) { E = (pduP[n] >> 7) & 0x1; @@ -3425,7 +3450,9 @@ static int nr_ue_validate_successrar(uint8_t *pduP, if (SUCESS_RAR_header_T1 == 0) { // T2 exist int SUCESS_RAR_header_T2 = (pduP[n] >> 5) & 0x1; if (SUCESS_RAR_header_T2 == 0) { // BI - ra->RA_backoff_indicator = pduP[n] & 0x0F; + int bi_ms = table_7_2_1[(pduP[n] & 0x0F)] * ra->scaling_factor_bi; + int slots_per_ms = mac->frame_structure.numb_slots_frame / 10; + ra->RA_backoff_limit = bi_ms * slots_per_ms; n++; } else { // S n++; @@ -3468,11 +3495,10 @@ static int nr_ue_validate_successrar(uint8_t *pduP, bool ra_success = check_ra_contention_resolution(cont_res_id, ra->cont_res_id); if (ra->RA_active && ra_success) { + nr_timer_stop(&ra->response_window_timer); nr_ra_succeeded(mac, gNB_index, frameP, slot); } else if (!ra_success) { - // nr_ra_failed(mac, CC_id, &ra->prach_resources, frameP, slot); - ra->ra_state = nrRA_UE_IDLE; - ra->RA_active = 0; + nr_ra_backoff_setting(ra); } } } else { // RAPID @@ -3675,7 +3701,8 @@ void nr_ue_process_mac_pdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_i mac_len = 6; if (ra->ra_state == nrRA_WAIT_CONTENTION_RESOLUTION) { - LOG_I(MAC, "[UE %d]Frame %d Contention resolution identity: 0x%02x%02x%02x%02x%02x%02x Terminating RA procedure\n", + LOG_D(NR_MAC, + "[UE %d]Frame %d Contention resolution identity: 0x%02x%02x%02x%02x%02x%02x Terminating RA procedure\n", mac->ue_id, frameP, pduP[1], @@ -3685,15 +3712,15 @@ void nr_ue_process_mac_pdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_i pduP[5], pduP[6]); + nr_timer_stop(&ra->contention_resolution_timer); bool ra_success = check_ra_contention_resolution(&pduP[1], ra->cont_res_id); if (ra->RA_active && ra_success) { nr_ra_succeeded(mac, gNB_index, frameP, slot); } else if (!ra_success) { - // TODO: Handle failure of RA procedure @ MAC layer - // nr_ra_failed(module_idP, CC_id, prach_resources, frameP, slot); // prach_resources is a PHY structure - ra->ra_state = nrRA_UE_IDLE; - ra->RA_active = false; + // consider this Contention Resolution not successful and discard the successfully decoded MAC PDU + nr_ra_contention_resolution_failed(mac); + return; } } break; @@ -3731,21 +3758,6 @@ void nr_ue_process_mac_pdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_i } } -int nr_write_ce_msg3_pdu(uint8_t *mac_ce, NR_UE_MAC_INST_t *mac, rnti_t crnti, uint8_t *mac_ce_end) -{ - uint8_t *pdu = mac_ce; - if (IS_SA_MODE(get_softmodem_params()) && mac->ra.ra_state != nrRA_SUCCEEDED) { - LOG_D(NR_MAC, "Generating C-RNTI MAC CE with C-RNTI %x\n", crnti); - *(NR_MAC_SUBHEADER_FIXED *)mac_ce = (NR_MAC_SUBHEADER_FIXED){.R = 0, .LCID = UL_SCH_LCID_C_RNTI}; - mac_ce += sizeof(NR_MAC_SUBHEADER_FIXED); - // C-RNTI MAC CE (2 octets) - memcpy(mac_ce, &crnti, sizeof(crnti)); - // update pointer and length - mac_ce += sizeof(crnti); - } - return mac_ce - pdu; -} - /** * Function: generating MAC CEs (MAC CE and subheader) for the ULSCH PDU * Parameters: @@ -3848,6 +3860,117 @@ int nr_write_ce_ulsch_pdu(uint8_t *mac_ce, return mac_ce - pdu; } +static void handle_rar_reception(NR_UE_MAC_INST_t *mac, NR_MAC_RAR *rar, frame_t frame, int slot) +{ + RAR_grant_t rar_grant; + RA_config_t *ra = &mac->ra; +#ifdef DEBUG_RAR + // CSI + unsigned char csi_req = (unsigned char)(rar->UL_GRANT_4 & 0x01); +#endif + + // TPC + unsigned char tpc_command = (unsigned char)((rar->UL_GRANT_4 >> 1) & 0x07); + ra->Msg3_TPC = (tpc_command << 1) - 6; + + // MCS + rar_grant.mcs = (unsigned char)(rar->UL_GRANT_4 >> 4); + // time alloc + rar_grant.Msg3_t_alloc = (unsigned char)(rar->UL_GRANT_3 & 0x0f); + // frequency alloc + rar_grant.Msg3_f_alloc = (uint16_t)((rar->UL_GRANT_3 >> 4) | (rar->UL_GRANT_2 << 4) | ((rar->UL_GRANT_1 & 0x03) << 12)); + // frequency hopping + rar_grant.freq_hopping = (unsigned char)(rar->UL_GRANT_1 >> 2); + + // Schedule Msg3 + const NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP; + const NR_UE_DL_BWP_t *current_DL_BWP = mac->current_DL_BWP; + const NR_BWP_PDCCH_t *pdcch_config = &mac->config_BWP_PDCCH[current_DL_BWP->bwp_id]; + NR_tda_info_t tda_info = get_ul_tda_info(current_UL_BWP, + *pdcch_config->ra_SS->controlResourceSetId, + pdcch_config->ra_SS->searchSpaceType->present, + TYPE_RA_RNTI_, + rar_grant.Msg3_t_alloc); + if (!tda_info.valid_tda || tda_info.nrOfSymbols == 0) { + LOG_E(MAC, "Cannot schedule Msg3. Something wrong in TDA information\n"); + // resume RAR response window timer if MSG2 decoding failed + nr_timer_suspension(&mac->ra.response_window_timer); + return; + } + frame_t frame_tx = 0; + int slot_tx = 0; + const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->ntn_ta, mac->current_UL_BWP->scs); + int ret = nr_ue_pusch_scheduler(mac, 1, frame, slot, &frame_tx, &slot_tx, tda_info.k2 + ntn_ue_koffset); + + // TA command + // if the timeAlignmentTimer associated with this TAG is not running + if (!nr_timer_is_active(&mac->time_alignment_timer)) { + const int ta = rar->TA2 + (rar->TA1 << 5); + set_time_alignment(mac, ta, rar_ta, frame_tx, slot_tx); + LOG_W(MAC, "received TA command %d\n", 31 + ta); + } + // else ignore the received Timing Advance Command + +#ifdef DEBUG_RAR + LOG_I(NR_MAC, "rarh->E = 0x%x\n", rarh->E); + LOG_I(NR_MAC, "rarh->T = 0x%x\n", rarh->T); + LOG_I(NR_MAC, "rarh->RAPID = 0x%x (%i)\n", rarh->RAPID, rarh->RAPID); + + LOG_I(NR_MAC, "rar->R = 0x%x\n", rar->R); + LOG_I(NR_MAC, "rar->TA1 = 0x%x\n", rar->TA1); + + LOG_I(NR_MAC, "rar->TA2 = 0x%x\n", rar->TA2); + LOG_I(NR_MAC, "rar->UL_GRANT_1 = 0x%x\n", rar->UL_GRANT_1); + + LOG_I(NR_MAC, "rar->UL_GRANT_2 = 0x%x\n", rar->UL_GRANT_2); + LOG_I(NR_MAC, "rar->UL_GRANT_3 = 0x%x\n", rar->UL_GRANT_3); + LOG_I(NR_MAC, "rar->UL_GRANT_4 = 0x%x\n", rar->UL_GRANT_4); + + LOG_I(NR_MAC, "rar->TCRNTI_1 = 0x%x\n", rar->TCRNTI_1); + LOG_I(NR_MAC, "rar->TCRNTI_2 = 0x%x\n", rar->TCRNTI_2); + + LOG_I(NR_MAC, + "[%d.%d]: [UE %d] Received RAR with t_alloc %d f_alloc %d ta_command %d mcs %d freq_hopping %d tpc_command %d\n", + frame, + slot, + mac->ue_id, + rar_grant.Msg3_t_alloc, + rar_grant.Msg3_f_alloc, + ta_command, + rar_grant.mcs, + rar_grant.freq_hopping, + tpc_command); +#endif + + if (ret != -1) { + uint16_t rnti = mac->crnti; + // Upon successful reception, set the T-CRNTI to the RAR value + // if the RA preamble is selected among the contention-based RA Preambles + if (!ra->cfra) { + ra->t_crnti = rar->TCRNTI_2 + (rar->TCRNTI_1 << 8); + rnti = ra->t_crnti; + if (!mac->msg3_C_RNTI) + nr_mac_rrc_msg3_ind(mac->ue_id, rnti, false); + } + fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frame_tx, slot_tx, FAPI_NR_UL_CONFIG_TYPE_PUSCH); + if (!pdu) + return; + // Config Msg3 PDU + int ret = nr_config_pusch_pdu(mac, + &tda_info, + &pdu->pusch_config_pdu, + NULL, + NULL, + &rar_grant, + rnti, + NR_SearchSpace__searchSpaceType_PR_common, + NR_DCI_NONE); + if (ret != 0) + remove_ul_config_last_item(pdu); + release_ul_config(pdu, false); + } +} + ///////////////////////////////////// // Random Access Response PDU // // TS 38.213 ch 8.2 // @@ -3892,13 +4015,10 @@ static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *d } RA_config_t *ra = &mac->ra; + ra->t_crnti = 0; uint8_t n_subPDUs = 0; // number of RAR payloads uint8_t n_subheaders = 0; // number of MAC RAR subheaders uint8_t *dlsch_buffer = dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.pdu; - uint8_t is_Msg3 = 1; - frame_t frame_tx = 0; - int slot_tx = 0; - int ret = 0; NR_RA_HEADER_RAPID *rarh = (NR_RA_HEADER_RAPID *) dlsch_buffer; // RAR subheader pointer NR_MAC_RAR *rar = (NR_MAC_RAR *) (dlsch_buffer + 1); // RAR subPDU pointer uint8_t preamble_index = ra->ra_PreambleIndex; @@ -3907,7 +4027,8 @@ static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *d T(T_NRUE_MAC_DL_RAR_PDU_WITH_DATA, T_INT(rnti), T_INT(frame), T_INT(slot), T_BUFFER(dlsch_buffer, dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.pdu_length)); - LOG_D(NR_MAC, "[%d.%d]: [UE %d][RAPROC] invoking MAC for received RAR (current preamble %d)\n", frame, slot, mac->ue_id, preamble_index); + ra->RA_backoff_limit = 0; + LOG_D(NR_MAC, "[%d.%d]: [UE %d][RAPROC] MAC received RAR (current preamble %d)\n", frame, slot, mac->ue_id, preamble_index); while (1) { n_subheaders++; @@ -3915,10 +4036,11 @@ static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *d n_subPDUs++; LOG_I(NR_MAC, "[UE %d][RAPROC][RA-RNTI %04x] Got RAPID RAR subPDU\n", mac->ue_id, rnti); } else { - ra->RA_backoff_indicator = get_backoff_indicator(((NR_RA_HEADER_BI *)rarh)->BI); - ra->RA_BI_found = 1; - LOG_I(NR_MAC, "[UE %d][RAPROC][RA-RNTI %04x] Got BI RAR subPDU %d ms\n", mac->ue_id, ra->RA_backoff_indicator, rnti); - if ( ((NR_RA_HEADER_BI *)rarh)->E == 1) { + int bi_ms = table_7_2_1[((NR_RA_HEADER_BI *)rarh)->BI] * ra->scaling_factor_bi; + int slots_per_ms = mac->frame_structure.numb_slots_frame / 10; + ra->RA_backoff_limit = bi_ms * slots_per_ms; + LOG_I(NR_MAC, "[UE %d][RAPROC][RA-RNTI %04x] Got BI RAR subPDU %d ms\n", mac->ue_id, rnti, bi_ms); + if (((NR_RA_HEADER_BI *)rarh)->E == 1) { rarh += sizeof(NR_RA_HEADER_BI); continue; } else { @@ -3926,9 +4048,15 @@ static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *d } } if (rarh->RAPID == preamble_index) { + // The MAC entity may stop ra-ResponseWindow (and hence monitoring for Random Access Response(s)) after + // successful reception of a Random Access Response containing Random Access Preamble identifiers + // that matches the transmitted PREAMBLE_INDEX. + nr_timer_stop(&ra->response_window_timer); LOG_A(NR_MAC, "[UE %d][RAPROC][%d.%d] Found RAR with the intended RAPID %d\n", mac->ue_id, frame, slot, rarh->RAPID); rar = (NR_MAC_RAR *) (dlsch_buffer + n_subheaders + (n_subPDUs - 1) * sizeof(NR_MAC_RAR)); - ra->RA_RAPID_found = 1; + handle_rar_reception(mac, rar, frame, slot); + if (ra->cfra) + nr_ra_succeeded(mac, dl_info->gNB_index, frame, slot); if (get_softmodem_params()->emulate_l1) { /* When we are emulating L1 with multiple UEs, the rx_indication will have multiple RAR PDUs. The code would previously handle each of these PDUs, @@ -3953,6 +4081,8 @@ static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *d slot, rarh->RAPID, preamble_index); + // resume RAR response window timer if MSG2 decoding failed + nr_timer_suspension(&mac->ra.response_window_timer); break; } else { rarh += sizeof(NR_MAC_RAR) + 1; @@ -3978,142 +4108,6 @@ static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *d rarh->RAPID, preamble_index); #endif - - if (ra->RA_RAPID_found) { - RAR_grant_t rar_grant; - -#ifdef DEBUG_RAR - // CSI - unsigned char csi_req = (unsigned char) (rar->UL_GRANT_4 & 0x01); -#endif - - // TPC - unsigned char tpc_command = (unsigned char) ((rar->UL_GRANT_4 >> 1) & 0x07); - switch (tpc_command){ - case 0: - ra->Msg3_TPC = -6; - break; - case 1: - ra->Msg3_TPC = -4; - break; - case 2: - ra->Msg3_TPC = -2; - break; - case 3: - ra->Msg3_TPC = 0; - break; - case 4: - ra->Msg3_TPC = 2; - break; - case 5: - ra->Msg3_TPC = 4; - break; - case 6: - ra->Msg3_TPC = 6; - break; - case 7: - ra->Msg3_TPC = 8; - break; - default: - LOG_E(NR_PHY, "RAR impossible msg3 TPC\n"); - } - // MCS - rar_grant.mcs = (unsigned char) (rar->UL_GRANT_4 >> 4); - // time alloc - rar_grant.Msg3_t_alloc = (unsigned char) (rar->UL_GRANT_3 & 0x0f); - // frequency alloc - rar_grant.Msg3_f_alloc = (uint16_t) ((rar->UL_GRANT_3 >> 4) | (rar->UL_GRANT_2 << 4) | ((rar->UL_GRANT_1 & 0x03) << 12)); - // frequency hopping - rar_grant.freq_hopping = (unsigned char) (rar->UL_GRANT_1 >> 2); - - // Schedule Msg3 - const NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP; - const NR_UE_DL_BWP_t *current_DL_BWP = mac->current_DL_BWP; - const NR_BWP_PDCCH_t *pdcch_config = &mac->config_BWP_PDCCH[current_DL_BWP->bwp_id]; - NR_tda_info_t tda_info = get_ul_tda_info(current_UL_BWP, - *pdcch_config->ra_SS->controlResourceSetId, - pdcch_config->ra_SS->searchSpaceType->present, - TYPE_RA_RNTI_, - rar_grant.Msg3_t_alloc); - if (!tda_info.valid_tda || tda_info.nrOfSymbols == 0) { - LOG_E(MAC, "Cannot schedule Msg3. Something wrong in TDA information\n"); - return; - } - const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->ntn_ta, mac->current_UL_BWP->scs); - ret = nr_ue_pusch_scheduler(mac, is_Msg3, frame, slot, &frame_tx, &slot_tx, tda_info.k2 + ntn_ue_koffset); - - // TA command - // if the timeAlignmentTimer associated with this TAG is not running - if (!nr_timer_is_active(&mac->time_alignment_timer)) { - const int ta = rar->TA2 + (rar->TA1 << 5); - set_time_alignment(mac, ta, rar_ta, frame_tx, slot_tx); - LOG_W(MAC, "received TA command %d\n", 31 + ta); - } - // else ignore the received Timing Advance Command - -#ifdef DEBUG_RAR - LOG_I(NR_MAC, "rarh->E = 0x%x\n", rarh->E); - LOG_I(NR_MAC, "rarh->T = 0x%x\n", rarh->T); - LOG_I(NR_MAC, "rarh->RAPID = 0x%x (%i)\n", rarh->RAPID, rarh->RAPID); - - LOG_I(NR_MAC, "rar->R = 0x%x\n", rar->R); - LOG_I(NR_MAC, "rar->TA1 = 0x%x\n", rar->TA1); - - LOG_I(NR_MAC, "rar->TA2 = 0x%x\n", rar->TA2); - LOG_I(NR_MAC, "rar->UL_GRANT_1 = 0x%x\n", rar->UL_GRANT_1); - - LOG_I(NR_MAC, "rar->UL_GRANT_2 = 0x%x\n", rar->UL_GRANT_2); - LOG_I(NR_MAC, "rar->UL_GRANT_3 = 0x%x\n", rar->UL_GRANT_3); - LOG_I(NR_MAC, "rar->UL_GRANT_4 = 0x%x\n", rar->UL_GRANT_4); - - LOG_I(NR_MAC, "rar->TCRNTI_1 = 0x%x\n", rar->TCRNTI_1); - LOG_I(NR_MAC, "rar->TCRNTI_2 = 0x%x\n", rar->TCRNTI_2); - - LOG_I(NR_MAC, "[%d.%d]: [UE %d] Received RAR with t_alloc %d f_alloc %d ta_command %d mcs %d freq_hopping %d tpc_command %d\n", - frame, - slot, - mac->ue_id, - rar_grant.Msg3_t_alloc, - rar_grant.Msg3_f_alloc, - ta_command, - rar_grant.mcs, - rar_grant.freq_hopping, - tpc_command); -#endif - - if (ret != -1) { - uint16_t rnti = mac->crnti; - // Upon successful reception, set the T-CRNTI to the RAR value if the RA preamble is selected among the contention-based RA Preambles - if (!ra->cfra) { - ra->t_crnti = rar->TCRNTI_2 + (rar->TCRNTI_1 << 8); - rnti = ra->t_crnti; - if (!ra->msg3_C_RNTI) - nr_mac_rrc_msg3_ind(mac->ue_id, rnti, dl_info->gNB_index); - } - fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frame_tx, slot_tx, FAPI_NR_UL_CONFIG_TYPE_PUSCH); - if (!pdu) - return; - // Config Msg3 PDU - int ret = nr_config_pusch_pdu(mac, - &tda_info, - &pdu->pusch_config_pdu, - NULL, - NULL, - &rar_grant, - rnti, - NR_SearchSpace__searchSpaceType_PR_common, - NR_DCI_NONE); - if (ret != 0) - remove_ul_config_last_item(pdu); - release_ul_config(pdu, false); - } - - } else { - ra->t_crnti = 0; - // TODO if the Random Access Preamble was not selected by the MAC entity - // among the contention-based Random Access Preamble - // apply the Timing Advance Command and start or restart the timeAlignmentTimer - } return; } diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 5300c9ed1f2d15c456aeb81f64107c1ca3a7623b..edd3bc1db72a56418fe9d3057ac3c86ab48997e4 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -182,17 +182,26 @@ void handle_time_alignment_timer_expired(NR_UE_MAC_INST_t *mac) // TODO not sure what to do here } -void update_mac_timers(NR_UE_MAC_INST_t *mac) +void update_mac_dl_timers(NR_UE_MAC_INST_t *mac) +{ + bool ra_window_expired = nr_timer_tick(&mac->ra.response_window_timer); + if (ra_window_expired) // consider the Random Access Response reception not successful + nr_rar_not_successful(mac); + bool alignment_timer_expired = nr_timer_tick(&mac->time_alignment_timer); + if (alignment_timer_expired) + handle_time_alignment_timer_expired(mac); +} + +void update_mac_ul_timers(NR_UE_MAC_INST_t *mac) { if (mac->data_inactivity_timer) { bool inactivity_timer_expired = nr_timer_tick(mac->data_inactivity_timer); if (inactivity_timer_expired) nr_mac_rrc_inactivity_timer_ind(mac->ue_id); } - bool alignment_timer_expired = nr_timer_tick(&mac->time_alignment_timer); - if (alignment_timer_expired) - handle_time_alignment_timer_expired(mac); - nr_timer_tick(&mac->ra.contention_resolution_timer); + bool contention_resolution_expired = nr_timer_tick(&mac->ra.contention_resolution_timer); + if (contention_resolution_expired) + nr_ra_contention_resolution_failed(mac); for (int j = 0; j < NR_MAX_SR_ID; j++) nr_timer_tick(&mac->scheduling_info.sr_info[j].prohibitTimer); nr_timer_tick(&mac->scheduling_info.sr_DelayTimer); @@ -236,6 +245,24 @@ void update_mac_timers(NR_UE_MAC_INST_t *mac) phr_info->phr_reporting |= (1 << phr_cause_periodic_timer); } } + bool ra_backoff_expired = nr_timer_tick(&mac->ra.RA_backoff_timer); + if (ra_backoff_expired) { + // perform the Random Access Resource selection procedure after the backoff time + mac->ra.ra_state = nrRA_GENERATE_PREAMBLE; + ra_resource_selection(mac); + } else { + if (nr_timer_is_active(&mac->ra.RA_backoff_timer)) { + // if the criteria (as defined in clause 5.1.2) to select contention-free Random Access Resources + // is met during the backoff time + // TODO verify what does this mean + if (mac->ra.cfra) { + // perform the Random Access Resource selection procedure + nr_timer_stop(&mac->ra.RA_backoff_timer); + mac->ra.ra_state = nrRA_GENERATE_PREAMBLE; + ra_resource_selection(mac); + } + } + } } void remove_ul_config_last_item(fapi_nr_ul_config_request_pdu_t *pdu) @@ -1144,7 +1171,7 @@ void schedule_RA_after_SR_failure(NR_UE_MAC_INST_t *mac) { if (get_softmodem_params()->phy_test) return; // cannot trigger RA in phytest mode - trigger_MAC_UE_RA(mac); + trigger_MAC_UE_RA(mac, NULL); // release PUCCH for all Serving Cells; // release SRS for all Serving Cells; release_PUCCH_SRS(mac); @@ -1206,7 +1233,9 @@ static void nr_update_sr(NR_UE_MAC_INST_t *mac, bool BSRsent) NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP; NR_PUCCH_Config_t *pucch_Config = current_UL_BWP ? current_UL_BWP->pucch_Config : NULL; - if (!pucch_Config || !pucch_Config->schedulingRequestResourceToAddModList) + if (!pucch_Config + || !pucch_Config->schedulingRequestResourceToAddModList + || pucch_Config->schedulingRequestResourceToAddModList->list.count == 0) return; // cannot schedule SR if there is no schedulingRequestResource configured if (lc_info->sr_id < 0 || lc_info->sr_id >= NR_MAX_SR_ID) @@ -1304,11 +1333,16 @@ void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info) uint32_t gNB_index = ul_info->gNB_index; RA_config_t *ra = &mac->ra; - if (mac->state == UE_PERFORMING_RA) { - nr_ue_get_rach(mac, cc_id, frame_tx, gNB_index, slot_tx); - nr_ue_prach_scheduler(mac, frame_tx, slot_tx); + + if (mac->state == UE_PERFORMING_RA && ra->ra_state == nrRA_UE_IDLE) { + init_RA(mac, frame_tx); + // perform the Random Access Resource selection procedure (see clause 5.1.2 and .2a) + ra_resource_selection(mac); } + if (mac->state == UE_PERFORMING_RA && ra->ra_state == nrRA_GENERATE_PREAMBLE) + nr_ue_prach_scheduler(mac, frame_tx, slot_tx); + bool BSRsent = false; if (mac->state == UE_CONNECTED) { nr_ue_periodic_srs_scheduling(mac, frame_tx, slot_tx); @@ -1352,7 +1386,7 @@ void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info) && (mac->state == UE_CONNECTED || (ra->ra_state == nrRA_WAIT_RAR && ra->cfra))) { if (!nr_timer_is_active(&mac->time_alignment_timer) && mac->state == UE_CONNECTED && !get_softmodem_params()->phy_test) { // UL data arrival during RRC_CONNECTED when UL synchronisation status is "non-synchronised" - trigger_MAC_UE_RA(mac); + trigger_MAC_UE_RA(mac, NULL); return; } // Getting IP traffic to be transmitted @@ -1561,547 +1595,6 @@ int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac, return 0; } -// Build the list of all the valid RACH occasions in the maximum association pattern period according to the PRACH config -static void build_ro_list(NR_UE_MAC_INST_t *mac) -{ - int x,y; // PRACH Configuration Index table variables used to compute the valid frame numbers - int y2; // PRACH Configuration Index table additional variable used to compute the valid frame numbers - uint8_t slot_shift_for_map; - uint8_t map_shift; - bool even_slot_invalid; - int64_t s_map; - uint8_t prach_conf_start_symbol; // Starting symbol of the PRACH occasions in the PRACH slot - uint8_t N_t_slot; // Number of PRACH occasions in a 14-symbols PRACH slot - uint8_t N_dur; // Duration of a PRACH occasion (nb of symbols) - uint16_t format = 0xffff; - uint8_t format2 = 0xff; - int nb_fdm; - - uint8_t config_index; - int msg1_FDM; - - uint8_t nb_of_frames_per_prach_conf_period; - - NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon; - NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric; - - config_index = rach_ConfigGeneric->prach_ConfigurationIndex; - msg1_FDM = rach_ConfigGeneric->msg1_FDM; - - switch (msg1_FDM){ - case 0: - case 1: - case 2: - case 3: - nb_fdm = 1 << msg1_FDM; - break; - default: - AssertFatal(1 == 0, "Unknown msg1_FDM from rach_ConfigGeneric %d\n", msg1_FDM); - } - - // Create the PRACH occasions map - // WIP: For now assume no rejected PRACH occasions because of conflict with SSB or TDD_UL_DL_ConfigurationCommon schedule - - int unpaired = mac->phy_config.config_req.cell_config.frame_duplex_type; - - const int64_t *prach_config_info_p = get_prach_config_info(mac->frequency_range, config_index, unpaired); - const int ul_mu = mac->current_UL_BWP->scs; - const int mu = nr_get_prach_or_ul_mu(mac->current_UL_BWP->msgA_ConfigCommon_r16, setup, ul_mu); - - // Identify the proper PRACH Configuration Index table according to the operating frequency - LOG_D(NR_MAC,"mu = %u, PRACH config index = %u, unpaired = %u\n", mu, config_index, unpaired); - - if (mac->frequency_range == FR2) { //FR2 - - x = prach_config_info_p[2]; - y = prach_config_info_p[3]; - y2 = prach_config_info_p[4]; - - s_map = prach_config_info_p[5]; - - prach_conf_start_symbol = prach_config_info_p[6]; - N_t_slot = prach_config_info_p[8]; - N_dur = prach_config_info_p[9]; - if (prach_config_info_p[1] != -1) - format2 = (uint8_t) prach_config_info_p[1]; - format = ((uint8_t) prach_config_info_p[0]) | (format2<<8); - - slot_shift_for_map = mu-2; - if ( (mu == 3) && (prach_config_info_p[7] == 1) ) - even_slot_invalid = true; - else - even_slot_invalid = false; - } - else { // FR1 - x = prach_config_info_p[2]; - y = prach_config_info_p[3]; - y2 = y; - - s_map = prach_config_info_p[4]; - - prach_conf_start_symbol = prach_config_info_p[5]; - N_t_slot = prach_config_info_p[7]; - N_dur = prach_config_info_p[8]; - LOG_D(NR_MAC,"N_t_slot %d, N_dur %d\n",N_t_slot,N_dur); - if (prach_config_info_p[1] != -1) - format2 = (uint8_t) prach_config_info_p[1]; - format = ((uint8_t) prach_config_info_p[0]) | (format2<<8); - - slot_shift_for_map = mu; - if ( (mu == 1) && (prach_config_info_p[6] == 1) && ((format & 0xff) > 3) ) - // no prach in even slots @ 30kHz for 1 prach per subframe - even_slot_invalid = true; - else - even_slot_invalid = false; - } // FR2 / FR1 - - const int bwp_id = mac->current_UL_BWP->bwp_id; - prach_association_pattern_t *prach_assoc_pattern = &mac->prach_assoc_pattern[bwp_id]; - prach_assoc_pattern->nb_of_prach_conf_period_in_max_period = MAX_NB_PRACH_CONF_PERIOD_IN_ASSOCIATION_PATTERN_PERIOD / x; - nb_of_frames_per_prach_conf_period = x; - int slots_per_frame = mac->frame_structure.numb_slots_frame; - LOG_D(NR_MAC,"nb_of_prach_conf_period_in_max_period %d\n", prach_assoc_pattern->nb_of_prach_conf_period_in_max_period); - - // Fill in the PRACH occasions table for every slot in every frame in every PRACH configuration periods in the maximum association pattern period - // ---------------------------------------------------------------------------------------------------------------------------------------------- - // ---------------------------------------------------------------------------------------------------------------------------------------------- - // For every PRACH configuration periods - // ------------------------------------- - for (int period_idx = 0; period_idx < prach_assoc_pattern->nb_of_prach_conf_period_in_max_period; period_idx++) { - prach_conf_period_t *prach_conf_period_list = &prach_assoc_pattern->prach_conf_period_list[period_idx]; - prach_conf_period_list->nb_of_prach_occasion = 0; - prach_conf_period_list->nb_of_frame = nb_of_frames_per_prach_conf_period; - prach_conf_period_list->nb_of_slot = slots_per_frame; - - LOG_D(NR_MAC,"PRACH Conf Period Idx %d\n", period_idx); - - // For every frames in a PRACH configuration period - // ------------------------------------------------ - for (int frame_idx = 0; frame_idx < nb_of_frames_per_prach_conf_period; frame_idx++) { - int frame_rach = (period_idx * nb_of_frames_per_prach_conf_period) + frame_idx; - - LOG_D(NR_MAC,"PRACH Conf Period Frame Idx %d - Frame %d\n", frame_idx, frame_rach); - // Is it a valid frame for this PRACH configuration index? (n_sfn mod x = y) - if ((frame_rach % x) == y || (frame_rach % x) == y2) { - - // For every slot in a frame - // ------------------------- - for (int slot = 0; slot < slots_per_frame; slot++) { - // Is it a valid slot? - map_shift = slot >> slot_shift_for_map; // in PRACH configuration index table slots are numbered wrt 60kHz - if ((s_map>>map_shift) & 0x01) { - // Valid slot - - // Additionally, for 30kHz/120kHz, we must check for the n_RA_Slot param also - if (even_slot_invalid && (slot%2 == 0)) - continue; // no prach in even slots @ 30kHz/120kHz for 1 prach per 60khz slot/subframe - - // We're good: valid frame and valid slot - // Compute all the PRACH occasions in the slot - - prach_occasion_slot_t *slot_map = &prach_conf_period_list->prach_occasion_slot_map[frame_idx][slot]; - slot_map->nb_of_prach_occasion_in_time = N_t_slot; - slot_map->nb_of_prach_occasion_in_freq = nb_fdm; - slot_map->prach_occasion = malloc(N_t_slot * nb_fdm * sizeof(*slot_map->prach_occasion)); - AssertFatal(slot_map->prach_occasion, "no memory available\n"); - for (int n_prach_occ_in_time = 0; n_prach_occ_in_time < N_t_slot; n_prach_occ_in_time++) { - uint8_t start_symbol = prach_conf_start_symbol + n_prach_occ_in_time * N_dur; - LOG_D(NR_MAC,"PRACH Occ in time %d\n", n_prach_occ_in_time); - - for (int n_prach_occ_in_freq = 0; n_prach_occ_in_freq < nb_fdm; n_prach_occ_in_freq++) { - slot_map->prach_occasion[n_prach_occ_in_time * nb_fdm + n_prach_occ_in_freq] = - (prach_occasion_info_t){.start_symbol = start_symbol, - .fdm = n_prach_occ_in_freq, - .frame = frame_idx, - .slot = slot, - .format = format}; - prach_assoc_pattern->prach_conf_period_list[period_idx].nb_of_prach_occasion++; - - LOG_D(NR_MAC, - "Adding a PRACH occasion: frame %u, slot-symbol %d-%d, occ_in_time-occ_in-freq %d-%d, nb ROs in conf period %d, for this slot: RO# in time %d, RO# in freq %d\n", - frame_rach, - slot, - start_symbol, - n_prach_occ_in_time, - n_prach_occ_in_freq, - prach_conf_period_list->nb_of_prach_occasion, - slot_map->nb_of_prach_occasion_in_time, - slot_map->nb_of_prach_occasion_in_freq); - } // For every freq in the slot - } // For every time occasions in the slot - } // Valid slot? - } // For every slots in a frame - } // Valid frame? - } // For every frames in a prach configuration period - } // For every prach configuration periods in the maximum association pattern period (160ms) -} - -// Build the list of all the valid/transmitted SSBs according to the config -static void build_ssb_list(NR_UE_MAC_INST_t *mac) -{ - // Create the list of transmitted SSBs - const int bwp_id = mac->current_UL_BWP->bwp_id; - ssb_list_info_t *ssb_list = &mac->ssb_list[bwp_id]; - fapi_nr_config_request_t *cfg = &mac->phy_config.config_req; - ssb_list->nb_tx_ssb = 0; - - for (int ssb_index = 0; ssb_index < MAX_NB_SSB; ssb_index++) { - uint32_t curr_mask = cfg->ssb_table.ssb_mask_list[ssb_index / 32].ssb_mask; - // check if if current SSB is transmitted - if ((curr_mask >> (31 - (ssb_index % 32))) & 0x01) { - ssb_list->nb_ssb_per_index[ssb_index] = ssb_list->nb_tx_ssb; - ssb_list->nb_tx_ssb++; - } - else - ssb_list->nb_ssb_per_index[ssb_index] = -1; - } - ssb_list->tx_ssb = calloc(ssb_list->nb_tx_ssb, sizeof(*ssb_list->tx_ssb)); -} - -static int get_ssb_idx_from_list(ssb_list_info_t *ssb_list, int idx) -{ - for (int ssb_index = 0; ssb_index < MAX_NB_SSB; ssb_index++) { - if (ssb_list->nb_ssb_per_index[ssb_index] == idx) - return ssb_index; - } - AssertFatal(false, "Couldn't find SSB index in SSB list\n"); - return 0; -} - -// Map the transmitted SSBs to the ROs and create the association pattern according to the config -static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac) -{ - // Map SSBs to PRACH occasions - // WIP: Assumption: No PRACH occasion is rejected because of a conflict with SSBs or TDD_UL_DL_ConfigurationCommon schedule - NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon; - NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR ssb_perRACH_config = setup->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present; - - const struct { - // true if more than one or exactly one SSB per RACH occasion, false if more than one RO per SSB - bool multiple_ssb_per_ro; - // Nb of SSBs per RACH or RACHs per SSB - int ssb_rach_ratio; - } config[] = {{false, 0}, {false, 8}, {false, 4}, {false, 2}, {true, 1}, {true, 2}, {true, 4}, {true, 8}, {true, 16}}; - AssertFatal(ssb_perRACH_config <= NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_sixteen, - "Unsupported ssb_perRACH_config %d\n", - ssb_perRACH_config); - const bool multiple_ssb_per_ro = config[ssb_perRACH_config].multiple_ssb_per_ro; - const int ssb_rach_ratio = config[ssb_perRACH_config].ssb_rach_ratio; - - LOG_D(NR_MAC,"SSB rach ratio %d, Multiple SSB per RO %d\n", ssb_rach_ratio, multiple_ssb_per_ro); - - const int bwp_id = mac->current_UL_BWP->bwp_id; - ssb_list_info_t *ssb_list = &mac->ssb_list[bwp_id]; - - // Evaluate the number of PRACH configuration periods required to map all the SSBs and set the association period - // WIP: Assumption for now is that all the PRACH configuration periods within a maximum association pattern period have the same - // number of PRACH occasions - // (No PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule) - // There is only one possible association period which can contain up to 16 PRACH configuration periods - LOG_D(NR_MAC,"Evaluate the number of PRACH configuration periods required to map all the SSBs and set the association period\n"); - const int required_nb_of_prach_occasion = - multiple_ssb_per_ro ? ((ssb_list->nb_tx_ssb - 1) + ssb_rach_ratio) / ssb_rach_ratio : ssb_list->nb_tx_ssb * ssb_rach_ratio; - - prach_association_pattern_t *prach_assoc_pattern = &mac->prach_assoc_pattern[bwp_id]; - const prach_conf_period_t *prach_conf_period = &prach_assoc_pattern->prach_conf_period_list[0]; - AssertFatal(prach_conf_period->nb_of_prach_occasion > 0, - "prach_conf_period->nb_of_prach_occasion shouldn't be 0 (nb_tx_ssb %d, ssb_rach_ratio %d)\n", - ssb_list->nb_tx_ssb, - ssb_rach_ratio); - prach_association_period_t *prach_association_period = &prach_assoc_pattern->prach_association_period_list[0]; - const int required_nb_of_prach_conf_period = - ((required_nb_of_prach_occasion - 1) + prach_conf_period->nb_of_prach_occasion) / prach_conf_period->nb_of_prach_occasion; - - if (required_nb_of_prach_conf_period == 1) { - prach_association_period->nb_of_prach_conf_period = 1; - } - else if (required_nb_of_prach_conf_period == 2) { - prach_association_period->nb_of_prach_conf_period = 2; - } - else if (required_nb_of_prach_conf_period <= 4) { - prach_association_period->nb_of_prach_conf_period = 4; - } - else if (required_nb_of_prach_conf_period <= 8) { - prach_association_period->nb_of_prach_conf_period = 8; - } - else if (required_nb_of_prach_conf_period <= 16) { - prach_association_period->nb_of_prach_conf_period = 16; - } - else { - AssertFatal(1 == 0, "Invalid number of PRACH config periods within an association period %d\n", required_nb_of_prach_conf_period); - } - - prach_assoc_pattern->nb_of_assoc_period = 1; // WIP: only one possible association period - prach_association_period->nb_of_frame = prach_association_period->nb_of_prach_conf_period * prach_conf_period->nb_of_frame; - prach_assoc_pattern->nb_of_frame = prach_association_period->nb_of_frame; - - LOG_D(NR_MAC, - "Assoc period %d, Nb of frames in assoc period %d\n", - prach_association_period->nb_of_prach_conf_period, - prach_association_period->nb_of_frame); - - // Set the starting PRACH Configuration period index in the association_pattern map for this particular association period - int prach_configuration_period_idx = - 0; // WIP: only one possible association period so the starting PRACH configuration period is automatically 0 - - // Map all the association periods within the association pattern period - LOG_D(NR_MAC,"Proceed to the SSB to RO mapping\n"); - // Check if we need to map multiple SSBs per RO or multiple ROs per SSB - - if (multiple_ssb_per_ro) { - const prach_association_period_t *end = - prach_assoc_pattern->prach_association_period_list + prach_assoc_pattern->nb_of_assoc_period; - for (prach_association_period_t *prach_period = prach_assoc_pattern->prach_association_period_list; prach_period < end; - prach_period++) { - // Set the starting PRACH Configuration period index in the association_pattern map for this particular association period - // WIP: only one possible association period so the starting PRACH configuration period is automatically 0 - // WIP: For the moment, only map each SSB idx once per association period if configuration is multiple SSBs per RO - // this is true if no PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule - int idx = 0; - bool done = false; - for (int i = 0; i < prach_period->nb_of_prach_conf_period && !done; i++, prach_configuration_period_idx++) { - prach_period->prach_conf_period_list[i] = &prach_assoc_pattern->prach_conf_period_list[prach_configuration_period_idx]; - prach_conf_period_t *prach_conf = prach_period->prach_conf_period_list[i]; - // Build the association period with its association PRACH Configuration indexes - // Go through all the ROs within the PRACH config period - for (int frame = 0; frame < prach_conf->nb_of_frame && !done; frame++) { - for (int slot = 0; slot < prach_conf->nb_of_slot && !done; slot++) { - prach_occasion_slot_t *slot_map = &prach_conf->prach_occasion_slot_map[frame][slot]; - for (int ro_in_time = 0; ro_in_time < slot_map->nb_of_prach_occasion_in_time && !done; ro_in_time++) { - for (int ro_in_freq = 0; ro_in_freq < slot_map->nb_of_prach_occasion_in_freq && !done; ro_in_freq++) { - prach_occasion_info_t *ro_p = - slot_map->prach_occasion + ro_in_time * slot_map->nb_of_prach_occasion_in_freq + ro_in_freq; - // Go through the list of transmitted SSBs and map the required amount of SSBs to this RO - // WIP: For the moment, only map each SSB idx once per association period if configuration is multiple SSBs per RO - // this is true if no PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule - for (; idx < ssb_list->nb_tx_ssb; idx++) { - ssb_info_t *tx_ssb = ssb_list->tx_ssb + idx; - // Map only the transmitted ssb_idx - int ssb_idx = get_ssb_idx_from_list(ssb_list, idx); - ro_p->mapped_ssb_idx[ro_p->nb_mapped_ssb] = ssb_idx; - ro_p->nb_mapped_ssb++; - AssertFatal(MAX_NB_RO_PER_SSB_IN_ASSOCIATION_PATTERN > tx_ssb->nb_mapped_ro + 1, - "Too many mapped ROs (%d) to a single SSB\n", - tx_ssb->nb_mapped_ro); - tx_ssb->mapped_ro[tx_ssb->nb_mapped_ro] = ro_p; - tx_ssb->nb_mapped_ro++; - LOG_D(NR_MAC, - "Mapped ssb_idx %u to RO slot-symbol %u-%u, %u-%u-%u/%u\n" - "Nb mapped ROs for this ssb idx: in the association period only %u\n", - ssb_idx, - ro_p->slot, - ro_p->start_symbol, - slot, - ro_in_time, - ro_in_freq, - slot_map->nb_of_prach_occasion_in_freq, - tx_ssb->nb_mapped_ro); - // If all the required SSBs are mapped to this RO, exit the loop of SSBs - if (ro_p->nb_mapped_ssb == ssb_rach_ratio) { - idx++; - break; - } - } - done = MAX_NB_SSB == idx; - } - } - } - } - } - } - } else { - int frame = 0; - int slot = 0; - int ro_in_time = 0; - int ro_in_freq = 0; - prach_association_period_t *end = prach_assoc_pattern->prach_association_period_list + prach_assoc_pattern->nb_of_assoc_period; - for (prach_association_period_t *prach_period = prach_assoc_pattern->prach_association_period_list; prach_period < end; - prach_period++) { - // Go through the list of transmitted SSBs - for (int idx = 0; idx < ssb_list->nb_tx_ssb; idx++) { - ssb_info_t *tx_ssb = ssb_list->tx_ssb + idx; - uint8_t nb_mapped_ro_in_association_period = 0; // Reset the nb of mapped ROs for the new SSB index - bool done = false; - // Map all the required ROs to this SSB - // Go through the list of PRACH config periods within this association period - for (int i = 0; i < prach_period->nb_of_prach_conf_period && !done; i++, prach_configuration_period_idx++) { - // Build the association period with its association PRACH Configuration indexes - prach_period->prach_conf_period_list[i] = &prach_assoc_pattern->prach_conf_period_list[prach_configuration_period_idx]; - prach_conf_period_t *prach_conf = prach_period->prach_conf_period_list[i]; - for (; frame < prach_conf->nb_of_frame; frame++) { - for (; slot < prach_conf->nb_of_slot; slot++) { - prach_occasion_slot_t *slot_map = &prach_conf->prach_occasion_slot_map[frame][slot]; - for (; ro_in_time < slot_map->nb_of_prach_occasion_in_time; ro_in_time++) { - for (; ro_in_freq < slot_map->nb_of_prach_occasion_in_freq; ro_in_freq++) { - prach_occasion_info_t *ro_p = - slot_map->prach_occasion + ro_in_time * slot_map->nb_of_prach_occasion_in_freq + ro_in_freq; - int ssb_idx = get_ssb_idx_from_list(ssb_list, idx); - ro_p->mapped_ssb_idx[0] = ssb_idx; - ro_p->nb_mapped_ssb = 1; - AssertFatal(MAX_NB_RO_PER_SSB_IN_ASSOCIATION_PATTERN > tx_ssb->nb_mapped_ro + 1, - "Too many mapped ROs (%d) to a single SSB\n", - tx_ssb->nb_mapped_ro); - tx_ssb->mapped_ro[tx_ssb->nb_mapped_ro] = ro_p; - tx_ssb->nb_mapped_ro++; - nb_mapped_ro_in_association_period++; - - LOG_D(NR_MAC, - "Mapped ssb_idx %u to RO slot-symbol %u-%u-%u, %u-%u-%u-%u/%u\n" - "Nb mapped ROs for this ssb idx: in the association period only %u / total %u\n", - ssb_idx, - ro_p->frame, - ro_p->slot, - ro_p->start_symbol, - frame, - slot, - ro_in_time, - ro_in_freq, - slot_map->nb_of_prach_occasion_in_freq, - tx_ssb->nb_mapped_ro, - nb_mapped_ro_in_association_period); - - // Exit the loop if this SSB has been mapped to all the required ROs - // WIP: Assuming that ssb_rach_ratio equals the maximum nb of times a given ssb_idx is mapped within an - // association period: - // this is true if no PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule - if (nb_mapped_ro_in_association_period == ssb_rach_ratio) { - ro_in_freq++; - break; - } - } - if (nb_mapped_ro_in_association_period == ssb_rach_ratio) - break; - else - ro_in_freq = 0; - } - if (nb_mapped_ro_in_association_period == ssb_rach_ratio) - break; - else - ro_in_time = 0; - } - if (nb_mapped_ro_in_association_period == ssb_rach_ratio) - break; - else - slot = 0; - } - if (nb_mapped_ro_in_association_period == ssb_rach_ratio) - break; - else - frame = 0; - } - } - } - } -} - -// Returns a RACH occasion if any matches the SSB idx, the frame and the slot -static int get_nr_prach_info_from_ssb_index(prach_association_pattern_t *prach_assoc_pattern, - int ssb_idx, - int frame, - int slot, - ssb_list_info_t *ssb_list, - prach_occasion_info_t **prach_occasion_info_pp) -{ - prach_occasion_slot_t *prach_occasion_slot_p = NULL; - - *prach_occasion_info_pp = NULL; - - // Search for a matching RO slot in the SSB_to_RO map - // A valid RO slot will match: - // - ssb_idx mapped to one of the ROs in that RO slot - // - exact slot number - // - frame offset - int idx_list = ssb_list->nb_ssb_per_index[ssb_idx]; - ssb_info_t *ssb_info_p = &ssb_list->tx_ssb[idx_list]; - LOG_D(NR_MAC, "checking for prach : ssb_info_p->nb_mapped_ro %d\n", ssb_info_p->nb_mapped_ro); - for (int n_mapped_ro = 0; n_mapped_ro < ssb_info_p->nb_mapped_ro; n_mapped_ro++) { - LOG_D(NR_MAC, - "%d.%d: mapped_ro[%d]->frame.slot %d.%d, prach_assoc_pattern->nb_of_frame %d\n", - frame, - slot, - n_mapped_ro, - ssb_info_p->mapped_ro[n_mapped_ro]->frame, - ssb_info_p->mapped_ro[n_mapped_ro]->slot, - prach_assoc_pattern->nb_of_frame); - if ((slot == ssb_info_p->mapped_ro[n_mapped_ro]->slot) && prach_assoc_pattern->prach_conf_period_list[0].nb_of_frame != 0 && - (ssb_info_p->mapped_ro[n_mapped_ro]->frame == (frame % prach_assoc_pattern->nb_of_frame))) { - uint8_t prach_config_period_nb = ssb_info_p->mapped_ro[n_mapped_ro]->frame / prach_assoc_pattern->prach_conf_period_list[0].nb_of_frame; - uint8_t frame_nb_in_prach_config_period = ssb_info_p->mapped_ro[n_mapped_ro]->frame % prach_assoc_pattern->prach_conf_period_list[0].nb_of_frame; - prach_occasion_slot_p = &prach_assoc_pattern->prach_conf_period_list[prach_config_period_nb].prach_occasion_slot_map[frame_nb_in_prach_config_period][slot]; - } - } - - // If there is a matching RO slot in the SSB_to_RO map - if (NULL != prach_occasion_slot_p) { - // A random RO mapped to the SSB index should be selected in the slot - - // First count the number of times the SSB index is found in that RO - uint8_t nb_mapped_ssb = 0; - - for (int ro_in_time = 0; ro_in_time < prach_occasion_slot_p->nb_of_prach_occasion_in_time; ro_in_time++) { - for (int ro_in_freq = 0; ro_in_freq < prach_occasion_slot_p->nb_of_prach_occasion_in_freq; ro_in_freq++) { - prach_occasion_info_t *ro_p = - prach_occasion_slot_p->prach_occasion + ro_in_time * prach_occasion_slot_p->nb_of_prach_occasion_in_freq + ro_in_freq; - for (uint8_t ssb_nb = 0; ssb_nb < ro_p->nb_mapped_ssb; ssb_nb++) { - if (ro_p->mapped_ssb_idx[ssb_nb] == ssb_idx) { - nb_mapped_ssb++; - } - } - } - } - - // Choose a random SSB nb - uint8_t random_ssb_nb = 0; - - random_ssb_nb = ((taus()) % nb_mapped_ssb); - - // Select the RO according to the chosen random SSB nb - nb_mapped_ssb=0; - for (int ro_in_time=0; ro_in_time < prach_occasion_slot_p->nb_of_prach_occasion_in_time; ro_in_time++) { - for (int ro_in_freq=0; ro_in_freq < prach_occasion_slot_p->nb_of_prach_occasion_in_freq; ro_in_freq++) { - prach_occasion_info_t *ro_p = - prach_occasion_slot_p->prach_occasion + ro_in_time * prach_occasion_slot_p->nb_of_prach_occasion_in_freq + ro_in_freq; - for (uint8_t ssb_nb = 0; ssb_nb < ro_p->nb_mapped_ssb; ssb_nb++) { - if (ro_p->mapped_ssb_idx[ssb_nb] == ssb_idx) { - if (nb_mapped_ssb == random_ssb_nb) { - *prach_occasion_info_pp = ro_p; - return 1; - } - else { - nb_mapped_ssb++; - } - } - } - } - } - } - - return 0; -} - -// Build the SSB to RO mapping upon RRC configuration update -void build_ssb_to_ro_map(NR_UE_MAC_INST_t *mac) -{ - // Clear all the lists and maps - const int bwp_id = mac->current_UL_BWP->bwp_id; - free_rach_structures(mac, bwp_id); - memset(&mac->ssb_list[bwp_id], 0, sizeof(ssb_list_info_t)); - memset(&mac->prach_assoc_pattern[bwp_id], 0, sizeof(prach_association_pattern_t)); - - // Build the list of all the valid RACH occasions in the maximum association pattern period according to the PRACH config - LOG_D(NR_MAC,"Build RO list\n"); - build_ro_list(mac); - - // Build the list of all the valid/transmitted SSBs according to the config - LOG_D(NR_MAC,"Build SSB list\n"); - build_ssb_list(mac); - - // Map the transmitted SSBs to the ROs and create the association pattern according to the config - LOG_D(NR_MAC,"Map SSB to RO\n"); - map_ssb_to_ro(mac); - LOG_D(NR_MAC,"Map SSB to RO done\n"); -} - static bool schedule_uci_on_pusch(NR_UE_MAC_INST_t *mac, frame_t frame_tx, int slot_tx, @@ -2581,6 +2074,23 @@ void nr_schedule_csirs_reception(NR_UE_MAC_INST_t *mac, int frame, int slot) } } +static bool is_prach_frame(frame_t frame, prach_occasion_info_t *prach_occasion_info, int association_periods) +{ + int config_period = prach_occasion_info->frame_info[0]; + int frame_period = config_period * association_periods; + int frame_in_period = frame % frame_period; + if (association_periods > 1) { + int current_assoc_period = frame_in_period / config_period; + if (current_assoc_period != prach_occasion_info->association_period_idx) + return false; + frame_in_period %= config_period; + } + if (frame_in_period == prach_occasion_info->frame_info[1]) // SFN % x == y (see Tables in Table 6.3.3.2 of 38.211) + return true; + else + return false; +} + // This function schedules the PRACH according to prach_ConfigurationIndex and TS 38.211, tables 6.3.3.2.x // PRACH formats 9, 10, 11 are corresponding to dual PRACH format configurations A1/B1, A2/B2, A3/B3. // - todo: @@ -2588,56 +2098,33 @@ void nr_schedule_csirs_reception(NR_UE_MAC_INST_t *mac, int frame, int slot) static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP) { RA_config_t *ra = &mac->ra; - ra->RA_offset = 2; // to compensate the rx frame offset at the gNB - if (ra->ra_state != nrRA_GENERATE_PREAMBLE) - return; - fapi_nr_config_request_t *cfg = &mac->phy_config.config_req; - fapi_nr_prach_config_t *prach_config = &cfg->prach_config; + // Get any valid PRACH occasion in the current slot for the selected SSB index + prach_occasion_info_t *prach_occasion_info = &ra->sched_ro_info; - NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon; - NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric; - const int bwp_id = mac->current_UL_BWP->bwp_id; + if (!is_prach_frame(frameP, prach_occasion_info, ra->association_periods)) + return; if (is_ul_slot(slotP, &mac->frame_structure)) { - // WIP Need to get the proper selected ssb_idx - // Initial beam selection functionality is not available yet - uint8_t selected_gnb_ssb_idx = mac->mib_ssb; - - // Get any valid PRACH occasion in the current slot for the selected SSB index - prach_occasion_info_t *prach_occasion_info_p; - int is_nr_prach_slot = get_nr_prach_info_from_ssb_index(&mac->prach_assoc_pattern[bwp_id], - selected_gnb_ssb_idx, - (int)frameP, - (int)slotP, - &mac->ssb_list[bwp_id], - &prach_occasion_info_p); - - if (is_nr_prach_slot) { - AssertFatal(NULL != prach_occasion_info_p,"PRACH Occasion Info not returned in a valid NR Prach Slot\n"); - - nr_get_RA_window(mac); - - uint16_t format = prach_occasion_info_p->format; - uint16_t format0 = format & 0xff; // single PRACH format - uint16_t format1 = (format >> 8) & 0xff; // dual PRACH format - + if (slotP == prach_occasion_info->slot) { fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frameP, slotP, FAPI_NR_UL_CONFIG_TYPE_PRACH); if (!pdu) { LOG_E(NR_MAC, "Error in PRACH allocation\n"); return; } - uint16_t ncs = get_NCS(rach_ConfigGeneric->zeroCorrelationZoneConfig, format0, setup->restrictedSetConfig); + + int format = prach_occasion_info->format; + fapi_nr_prach_config_t *prach_config = &mac->phy_config.config_req.prach_config; pdu->prach_config_pdu = (fapi_nr_ul_config_prach_pdu){ .phys_cell_id = mac->physCellId, .num_prach_ocas = 1, - .prach_slot = prach_occasion_info_p->slot, - .prach_start_symbol = prach_occasion_info_p->start_symbol, - .num_ra = prach_occasion_info_p->fdm, - .num_cs = ncs, - .root_seq_id = prach_config->num_prach_fd_occasions_list[prach_occasion_info_p->fdm].prach_root_sequence_index, + .prach_slot = prach_occasion_info->slot, + .prach_start_symbol = prach_occasion_info->start_symbol, + .num_ra = prach_occasion_info->fdm, + .num_cs = get_NCS(ra->zeroCorrelationZoneConfig, format, ra->restricted_set_config), + .root_seq_id = prach_config->num_prach_fd_occasions_list[prach_occasion_info->fdm].prach_root_sequence_index, .restricted_set = prach_config->restricted_set_config, - .freq_msg1 = prach_config->num_prach_fd_occasions_list[prach_occasion_info_p->fdm].k1}; + .freq_msg1 = prach_config->num_prach_fd_occasions_list[prach_occasion_info->fdm].k1}; LOG_I(NR_MAC, "PRACH scheduler: Selected RO Frame %u, Slot %u, Symbol %u, Fdm %u\n", @@ -2646,82 +2133,46 @@ static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t pdu->prach_config_pdu.prach_start_symbol, pdu->prach_config_pdu.num_ra); - // Search which SSB is mapped in the RO (among all the SSBs mapped to this RO) - for (int ssb_nb_in_ro=0; ssb_nb_in_ro<prach_occasion_info_p->nb_mapped_ssb; ssb_nb_in_ro++) { - if (prach_occasion_info_p->mapped_ssb_idx[ssb_nb_in_ro] == selected_gnb_ssb_idx) { - ra->ssb_nb_in_ro = ssb_nb_in_ro; + switch (format) { // single PRACH format + case 0: + pdu->prach_config_pdu.prach_format = 0; break; - } + case 1: + pdu->prach_config_pdu.prach_format = 1; + break; + case 2: + pdu->prach_config_pdu.prach_format = 2; + break; + case 3: + pdu->prach_config_pdu.prach_format = 3; + break; + case 0xa1: + pdu->prach_config_pdu.prach_format = 4; + break; + case 0xa2: + pdu->prach_config_pdu.prach_format = 5; + break; + case 0xa3: + pdu->prach_config_pdu.prach_format = 6; + break; + case 0xb1: + pdu->prach_config_pdu.prach_format = 7; + break; + case 0xb4: + pdu->prach_config_pdu.prach_format = 8; + break; + case 0xc0: + pdu->prach_config_pdu.prach_format = 9; + break; + case 0xc2: + pdu->prach_config_pdu.prach_format = 10; + break; + default: + AssertFatal(false, "Invalid PRACH format"); } - AssertFatal(ra->ssb_nb_in_ro<prach_occasion_info_p->nb_mapped_ssb, "%u not found in the mapped SSBs to the PRACH occasion", selected_gnb_ssb_idx); - if (format1 != 0xff) { - switch (format0) { // dual PRACH format - case 0xa1: - pdu->prach_config_pdu.prach_format = 11; - break; - case 0xa2: - pdu->prach_config_pdu.prach_format = 12; - break; - case 0xa3: - pdu->prach_config_pdu.prach_format = 13; - break; - default: - AssertFatal(1 == 0, "Only formats A1/B1 A2/B2 A3/B3 are valid for dual format"); - } - } else { - switch (format0) { // single PRACH format - case 0: - pdu->prach_config_pdu.prach_format = 0; - break; - case 1: - pdu->prach_config_pdu.prach_format = 1; - break; - case 2: - pdu->prach_config_pdu.prach_format = 2; - break; - case 3: - pdu->prach_config_pdu.prach_format = 3; - break; - case 0xa1: - pdu->prach_config_pdu.prach_format = 4; - break; - case 0xa2: - pdu->prach_config_pdu.prach_format = 5; - break; - case 0xa3: - pdu->prach_config_pdu.prach_format = 6; - break; - case 0xb1: - pdu->prach_config_pdu.prach_format = 7; - break; - case 0xb4: - pdu->prach_config_pdu.prach_format = 8; - break; - case 0xc0: - pdu->prach_config_pdu.prach_format = 9; - break; - case 0xc2: - pdu->prach_config_pdu.prach_format = 10; - break; - default: - AssertFatal(1 == 0, "Invalid PRACH format"); - } - } // 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; - // 3GPP TS 38.321 Section 5.1.3 says t_id for RA-RNTI depends on mu as specified in clause 5.3.2 in TS 38.211 - // so mu = 0 for prach format < 4. - if (pdu->prach_config_pdu.prach_format < 4) { - unsigned int slots_per_sf = (1 << mac->current_UL_BWP->scs); - slot_RA = pdu->prach_config_pdu.prach_slot / slots_per_sf; - } else { - slot_RA = pdu->prach_config_pdu.prach_slot; - } - mac->ra.ra_rnti = nr_get_ra_rnti(pdu->prach_config_pdu.prach_start_symbol, slot_RA, pdu->prach_config_pdu.num_ra, 0); release_ul_config(pdu, false); nr_scheduled_response_t scheduled_response = {.ul_config = mac->ul_config_request + slotP, .mac = mac, @@ -2733,12 +2184,31 @@ static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t T(T_UE_PHY_INITIATE_RA_PROCEDURE, T_INT(frameP), T_INT(pdu->prach_config_pdu.prach_slot), T_INT(pdu->prach_config_pdu.ra_PreambleIndex), T_INT(pdu->prach_config_pdu.prach_tx_power)); + const int n_slots_frame = mac->frame_structure.numb_slots_frame; if (ra->ra_type == RA_4_STEP) { - nr_Msg1_transmitted(mac); + ra->ra_state = nrRA_WAIT_RAR; + // we start to monitor DCI for RAR in the first valid occasion after transmitting RACH + // the response window timer should be started at that time + // but for processing reasons it is better to start it here and to add the slot difference + // that also takes into account the rx to tx slot offset + int next_slot = (slotP + 1) % n_slots_frame; + int next_frame = (frameP + (next_slot < slotP)) % MAX_FRAME_NUMBER; + int add_slots = 1; + NR_BWP_PDCCH_t *pdcch_config = &mac->config_BWP_PDCCH[mac->current_DL_BWP->bwp_id]; + while (!is_dl_slot(next_slot, &mac->frame_structure) + || !is_ss_monitor_occasion(next_frame, next_slot, n_slots_frame, pdcch_config->ra_SS)) { + int temp_slot = (next_slot + 1) % n_slots_frame; + next_frame = (next_frame + (temp_slot < next_slot)) % MAX_FRAME_NUMBER; + next_slot = temp_slot; + add_slots++; + } + nr_timer_setup(&ra->response_window_timer, + ra->response_window_setup_time + add_slots + GET_DURATION_RX_TO_TX(&mac->ntn_ta), + 1); + nr_timer_start(&ra->response_window_timer); } else if (ra->ra_type == RA_2_STEP) { NR_MsgA_PUSCH_Resource_r16_t *msgA_PUSCH_Resource = mac->current_UL_BWP->msgA_ConfigCommon_r16->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16; - const int n_slots_frame = mac->frame_structure.numb_slots_frame; slot_t msgA_pusch_slot = (slotP + msgA_PUSCH_Resource->msgA_PUSCH_TimeDomainOffset_r16) % n_slots_frame; frame_t msgA_pusch_frame = (frameP + ((slotP + msgA_PUSCH_Resource->msgA_PUSCH_TimeDomainOffset_r16) / n_slots_frame)) % 1024; @@ -2767,9 +2237,6 @@ static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t remove_ul_config_last_item(pdu); release_ul_config(pdu, false); - // Compute MsgB RNTI - ra->MsgB_rnti = - nr_get_MsgB_rnti(prach_occasion_info_p->start_symbol, slot_RA, prach_occasion_info_p->fdm, 0); LOG_D(NR_MAC, "ra->ra_state %s\n", nrra_ue_text[ra->ra_state]); ra->ra_state = nrRA_WAIT_MSGB; ra->t_crnti = 0; @@ -2778,8 +2245,6 @@ static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t } else { AssertFatal(false, "RA type %d not implemented!\n", ra->ra_type); } - - // rnti = ra->t_crnti; } // is_nr_prach_slot } // if is_nr_UL_slot } @@ -3382,7 +2847,6 @@ static void schedule_ta_command(fapi_nr_dl_config_request_t *dl_config, NR_UE_MA fapi_nr_ta_command_pdu *ta = &dl_config->dl_config_list[dl_config->number_pdus].ta_command_pdu; ta->ta_frame = ul_time_alignment->frame; ta->ta_slot = ul_time_alignment->slot; - ta->ta_offset = mac->n_ta_offset; ta->is_rar = ul_time_alignment->ta_apply == rar_ta; ta->ta_command = ul_time_alignment->ta_command; dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_CONFIG_TA_COMMAND; diff --git a/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_power_procedures.cpp b/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_power_procedures.cpp index bcbec989c2240438583d4a1735fc891992c9bcda..7dc0b43ec3abea48e4141717d16fe4e5007f2846 100644 --- a/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_power_procedures.cpp +++ b/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_power_procedures.cpp @@ -192,8 +192,6 @@ TEST(pusch_power_control, pusch_power_control_msg3) current_UL_BWP.BWPSize = 106; current_UL_BWP.channel_bandwidth = 40; mac.current_UL_BWP = ¤t_UL_BWP; - NR_RACH_ConfigCommon_t nr_rach_ConfigCommon = {0}; - current_UL_BWP.rach_ConfigCommon = &nr_rach_ConfigCommon; mac.nr_band = 78; NR_PUSCH_Config_t pusch_Config = {0}; current_UL_BWP.pusch_Config = &pusch_Config; @@ -229,8 +227,8 @@ TEST(pusch_power_control, pusch_power_control_msg3) num_rb, start_prb); - long preambleReceivedTargetPower = -96; - nr_rach_ConfigCommon.rach_ConfigGeneric.preambleReceivedTargetPower = preambleReceivedTargetPower; + int preambleReceivedTargetPower = -96; + mac.ra.prach_resources.ra_preamble_rx_target_power = preambleReceivedTargetPower; int power = get_pusch_tx_power_ue(&mac, num_rb, @@ -247,7 +245,7 @@ TEST(pusch_power_control, pusch_power_control_msg3) false); EXPECT_EQ(power, -84); EXPECT_LT(power, P_CMAX); - nr_rach_ConfigCommon.rach_ConfigGeneric.preambleReceivedTargetPower -= 2; + mac.ra.prach_resources.ra_preamble_rx_target_power -= 2; int reduced_power = get_pusch_tx_power_ue(&mac, num_rb, @@ -372,8 +370,6 @@ TEST(pusch_power_control, pusch_power_control_state_initialization) current_UL_BWP.BWPSize = 106; current_UL_BWP.channel_bandwidth = 40; mac.current_UL_BWP = ¤t_UL_BWP; - NR_RACH_ConfigCommon_t nr_rach_ConfigCommon = {0}; - current_UL_BWP.rach_ConfigCommon = &nr_rach_ConfigCommon; mac.nr_band = 78; NR_PUSCH_Config_t pusch_Config = {0}; current_UL_BWP.pusch_Config = &pusch_Config; @@ -393,8 +389,8 @@ TEST(pusch_power_control, pusch_power_control_state_initialization) uint32_t sum_bits_in_codeblocks = 56; int delta_pusch = 0; bool is_rar_tx_retx = true; - long preambleReceivedTargetPower = -96; - nr_rach_ConfigCommon.rach_ConfigGeneric.preambleReceivedTargetPower = preambleReceivedTargetPower; + int preambleReceivedTargetPower = -96; + mac.ra.prach_resources.ra_preamble_rx_target_power = preambleReceivedTargetPower; get_pusch_tx_power_ue(&mac, num_rb, 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 f5a402c467032e037f29fc4f4d0f99a7a8937105..25ea5edcd0c0f318b3e61203fcb2022c484ebcf7 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 @@ -29,20 +29,11 @@ softmodem_params_t *get_softmodem_params(void) { return &softmodem_params; } -void nr_mac_rrc_ra_ind(const module_id_t mod_id, int frame, bool success) +void nr_mac_rrc_ra_ind(const module_id_t mod_id, bool success) { } -int nr_write_ce_ulsch_pdu(uint8_t *mac_ce, - NR_UE_MAC_INST_t *mac, - NR_SINGLE_ENTRY_PHR_MAC_CE *power_headroom, - const type_bsr_t *bsr, - uint8_t *mac_ce_end) +void nr_mac_rrc_msg3_ind(const module_id_t mod_id, const int rnti, bool prepare_payload) { - return 0; -} -int nr_write_ce_msg3_pdu(uint8_t *mac_ce, NR_UE_MAC_INST_t *mac, rnti_t crnti, uint8_t *mac_ce_end) -{ - return 0; } tbs_size_t mac_rlc_data_req(const module_id_t module_idP, const rnti_t rntiP, @@ -77,6 +68,14 @@ int nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac, { return 0; } +NR_UE_DL_BWP_t *get_dl_bwp_structure(NR_UE_MAC_INST_t *mac, int bwp_id, bool setup) +{ + return NULL; +} +NR_UE_UL_BWP_t *get_ul_bwp_structure(NR_UE_MAC_INST_t *mac, int bwp_id, bool setup) +{ + return NULL; +} } #include <cstdio> #include "common/utils/LOG/log.h" @@ -84,22 +83,32 @@ int nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac, TEST(test_init_ra, four_step_cbra) { NR_UE_MAC_INST_t mac = {0}; - NR_PRACH_RESOURCES_t prach_resources = {0}; + RA_config_t *ra = &mac.ra; NR_RACH_ConfigCommon_t nr_rach_ConfigCommon = {0}; NR_RACH_ConfigGeneric_t rach_ConfigGeneric = {0}; - NR_RACH_ConfigDedicated_t *rach_ConfigDedicated = nullptr; + NR_RACH_ConfigDedicated_t rach_ConfigDedicated = {0}; NR_UE_UL_BWP_t current_bwp; + 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; + dl_bwp.bwp_id = 0; current_bwp.channel_bandwidth = 40; nr_rach_ConfigCommon.msg1_SubcarrierSpacing = &scs; + nr_rach_ConfigCommon.rach_ConfigGeneric = rach_ConfigGeneric; + current_bwp.rach_ConfigCommon = &nr_rach_ConfigCommon; + ra->rach_ConfigDedicated = &rach_ConfigDedicated; mac.p_Max = 23; mac.nr_band = 78; mac.frame_structure.frame_type = TDD; + mac.frame_structure.numb_slots_frame = 20; mac.frequency_range = FR1; + int frame = 151; - init_RA(&mac, &prach_resources, &nr_rach_ConfigCommon, &rach_ConfigGeneric, rach_ConfigDedicated); + init_RA(&mac, frame); EXPECT_EQ(mac.ra.ra_type, RA_4_STEP); EXPECT_EQ(mac.state, UE_PERFORMING_RA); @@ -110,25 +119,35 @@ TEST(test_init_ra, four_step_cbra) TEST(test_init_ra, four_step_cfra) { NR_UE_MAC_INST_t mac = {0}; - NR_PRACH_RESOURCES_t prach_resources = {0}; + RA_config_t *ra = &mac.ra; NR_RACH_ConfigCommon_t nr_rach_ConfigCommon = {0}; NR_RACH_ConfigGeneric_t rach_ConfigGeneric = {0}; NR_UE_UL_BWP_t current_bwp; + 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; + dl_bwp.bwp_id = 0; current_bwp.channel_bandwidth = 40; nr_rach_ConfigCommon.msg1_SubcarrierSpacing = &scs; + nr_rach_ConfigCommon.rach_ConfigGeneric = rach_ConfigGeneric; + current_bwp.rach_ConfigCommon = &nr_rach_ConfigCommon; mac.p_Max = 23; mac.nr_band = 78; mac.frame_structure.frame_type = TDD; + mac.frame_structure.numb_slots_frame = 20; mac.frequency_range = FR1; + 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; - init_RA(&mac, &prach_resources, &nr_rach_ConfigCommon, &rach_ConfigGeneric, &rach_ConfigDedicated); + init_RA(&mac, frame); EXPECT_EQ(mac.ra.ra_type, RA_4_STEP); EXPECT_EQ(mac.state, UE_PERFORMING_RA); diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index d7b9b5e12912748c72a589b44ab89312da5f809f..0abe35b80db0f62afa6459cd980c4869e2911af0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -521,8 +521,7 @@ static void config_common(gNB_MAC_INST *nrmac, // If absent, use SCS as derived from the prach-ConfigurationIndex (for 839) int config_index = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex; int frame_type = get_frame_type(band, frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing); - const int64_t *prach_config_info_p = get_prach_config_info(frequency_range, config_index, frame_type); - int format = prach_config_info_p[0]; + int format = get_nr_prach_format_from_index(config_index, UL_pointA, frame_type) & 0xff; cfg->prach_config.prach_sub_c_spacing.value = get_delta_f_RA_long(format); } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index cc0317cf5133cb36d9e0d8c24f3e9355387d6757..9bf8b739bfa4cce889eccb2183cf3c0555dcb8ec 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -83,9 +83,8 @@ static int16_t ssb_index_from_prach(module_id_t module_idP, float num_ssb_per_RO = ssb_per_rach_occasion[cfg->prach_config.ssb_per_rach.value]; uint16_t start_symbol_index = 0; - uint8_t N_dur=0,N_t_slot=0,start_symbol = 0, temp_start_symbol = 0, N_RA_slot=0; - uint16_t format,RA_sfn_index = -1; - uint8_t config_period = 1; + uint8_t temp_start_symbol = 0; + uint16_t RA_sfn_index = -1; uint16_t prach_occasion_id = -1; uint8_t num_active_ssb = cc->num_active_ssb; NR_MsgA_ConfigCommon_r16_t *msgacc = NULL; @@ -93,42 +92,32 @@ static int16_t ssb_index_from_prach(module_id_t module_idP, msgacc = scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup; const int ul_mu = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing; const int mu = nr_get_prach_or_ul_mu(msgacc, rach_ConfigCommon, ul_mu); + frequency_range_t freq_range = scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA > 2016666 ? FR2 : FR1; + get_nr_prach_sched_from_info(cc->prach_info, config_index, frameP, slotP, mu, freq_range, &RA_sfn_index, cc->frame_type); - get_nr_prach_info_from_index(config_index, - (int)frameP, - (int)slotP, - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA, - mu, - cc->frame_type, - &format, - &start_symbol, - &N_t_slot, - &N_dur, - &RA_sfn_index, - &N_RA_slot, - &config_period); uint8_t index = 0, slot_index = 0; - for (slot_index = 0; slot_index < N_RA_slot; slot_index++) { - if (N_RA_slot <= 1) { //1 PRACH slot in a subframe + for (slot_index = 0; slot_index < cc->prach_info.N_RA_slot; slot_index++) { + if (cc->prach_info.N_RA_slot <= 1) { // 1 PRACH slot in a subframe if((mu == 1) || (mu == 3)) - slot_index = 1; //For scs = 30khz and 120khz + slot_index = 1; // For scs = 30khz and 120khz } - for (int i = 0; i < N_t_slot; i++) { - temp_start_symbol = (start_symbol + i * N_dur + 14 * slot_index) % 14; + for (int i = 0; i < cc->prach_info.N_t_slot; i++) { + temp_start_symbol = (cc->prach_info.start_symbol + i * cc->prach_info.N_dur + 14 * slot_index) % 14; if(symbol == temp_start_symbol) { start_symbol_index = i; break; } } } - if (N_RA_slot <= 1) { //1 PRACH slot in a subframe + if (cc->prach_info.N_RA_slot <= 1) { // 1 PRACH slot in a subframe if((mu == 1) || (mu == 3)) - slot_index = 0; //For scs = 30khz and 120khz + slot_index = 0; // For scs = 30khz and 120khz } - + int config_period = cc->prach_info.x; // prach_occasion_id = subframe_index * N_t_slot * N_RA_slot * fdm + N_RA_slot_index * N_t_slot * fdm + freq_index + fdm * start_symbol_index; - prach_occasion_id = (((frameP % (cc->max_association_period * config_period)) / config_period) * cc->total_prach_occasions_per_config_period) + - (RA_sfn_index + slot_index) * N_t_slot * fdm + start_symbol_index * fdm + freq_index; + prach_occasion_id = + (((frameP % (cc->max_association_period * config_period)) / config_period) * cc->total_prach_occasions_per_config_period) + + (RA_sfn_index + slot_index) * cc->prach_info.N_t_slot * fdm + start_symbol_index * fdm + freq_index; //one SSB have more than one continuous RO if(num_ssb_per_RO <= 1) @@ -159,14 +148,12 @@ void find_SSB_and_RO_available(gNB_MAC_INST *nrmac) nfapi_nr_config_request_scf_t *cfg = &nrmac->config[0]; NR_RACH_ConfigCommon_t *rach_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup; uint8_t config_index = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex; - uint8_t N_dur=0,N_t_slot=0,start_symbol=0,N_RA_slot = 0; - uint16_t format,N_RA_sfn = 0,unused_RA_occasion,repetition = 0; + uint16_t unused_RA_occasion, repetition = 0; uint8_t num_active_ssb = 0; - uint8_t max_association_period = 1; struct NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB *ssb_perRACH_OccasionAndCB_PreamblesPerSSB = rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB; - switch (ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present){ + switch (ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present) { case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_oneEighth: cc->cb_preambles_per_ssb = 4 * (ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.oneEighth + 1); break; @@ -194,31 +181,16 @@ void find_SSB_and_RO_available(gNB_MAC_INST *nrmac) default: AssertFatal(1 == 0, "Unsupported ssb_perRACH_config %d\n", ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present); break; - } - - NR_MsgA_ConfigCommon_r16_t *msgacc = NULL; - if (scc->uplinkConfigCommon->initialUplinkBWP->ext1 && scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16) - msgacc = scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup; - const int ul_mu = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing; - const int mu = nr_get_prach_or_ul_mu(msgacc, rach_ConfigCommon, ul_mu); + } // prach is scheduled according to configuration index and tables 6.3.3.2.2 to 6.3.3.2.4 - get_nr_prach_occasion_info_from_index(config_index, - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA, - mu, - cc->frame_type, - &format, - &start_symbol, - &N_t_slot, - &N_dur, - &N_RA_slot, - &N_RA_sfn, - &max_association_period); + frequency_range_t freq_range = scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA > 2016666 ? FR2 : FR1; + nr_prach_info_t prach_info = get_nr_prach_occasion_info_from_index(config_index, freq_range, cc->frame_type); float num_ssb_per_RO = ssb_per_rach_occasion[cfg->prach_config.ssb_per_rach.value]; uint8_t fdm = cfg->prach_config.num_prach_fd_occasions.value; uint64_t L_ssb = (((uint64_t) cfg->ssb_table.ssb_mask_list[0].ssb_mask.value) << 32) | cfg->ssb_table.ssb_mask_list[1].ssb_mask.value; - uint32_t total_RA_occasions = N_RA_sfn * N_t_slot * N_RA_slot * fdm; + uint32_t total_RA_occasions = prach_info.N_RA_sfn * prach_info.N_t_slot * prach_info.N_RA_slot * fdm; for(int i = 0; i < 64; i++) { if ((L_ssb >> (63 - i)) & 0x01) { // only if the bit of L_ssb at current ssb index is 1 @@ -228,7 +200,7 @@ void find_SSB_and_RO_available(gNB_MAC_INST *nrmac) } cc->total_prach_occasions_per_config_period = total_RA_occasions; - for(int i = 1; (1 << (i-1)) <= max_association_period; i++) { + for (int i = 1; (1 << (i - 1)) <= prach_info.max_association_period; i++) { cc->max_association_period = (1 << (i - 1)); total_RA_occasions = total_RA_occasions * cc->max_association_period; if(total_RA_occasions >= (int) (num_active_ssb / num_ssb_per_RO)) { @@ -240,14 +212,16 @@ void find_SSB_and_RO_available(gNB_MAC_INST *nrmac) unused_RA_occasion = total_RA_occasions - (int)((num_active_ssb * repetition) / num_ssb_per_RO); cc->total_prach_occasions = total_RA_occasions - unused_RA_occasion; cc->num_active_ssb = num_active_ssb; + cc->prach_info = prach_info; LOG_D(NR_MAC, - "Total available RO %d, num of active SSB %d: unused RO = %d association_period %u N_RA_sfn %u total_prach_occasions_per_config_period %u\n", + "Total available RO %d, num of active SSB %d: unused RO = %d association_period %u N_RA_sfn %u " + "total_prach_occasions_per_config_period %u\n", cc->total_prach_occasions, cc->num_active_ssb, unused_RA_occasion, cc->max_association_period, - N_RA_sfn, + prach_info.N_RA_sfn, cc->total_prach_occasions_per_config_period); } @@ -396,10 +370,6 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) if (is_ul_slot(slotP, &RC.nrmac[module_idP]->frame_structure)) { const NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &rach_ConfigCommon->rach_ConfigGeneric; uint8_t config_index = rach_ConfigGeneric->prach_ConfigurationIndex; - uint8_t N_dur, N_t_slot, start_symbol = 0, N_RA_slot; - uint16_t RA_sfn_index = -1; - uint8_t config_period = 1; - uint16_t format; int slot_index = 0; uint16_t prach_occasion_id = -1; @@ -409,29 +379,18 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) const int ul_mu = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing; const int mu = nr_get_prach_or_ul_mu(msgacc, rach_ConfigCommon, ul_mu); // prach is scheduled according to configuration index and tables 6.3.3.2.2 to 6.3.3.2.4 - if (get_nr_prach_info_from_index(config_index, - (int)frameP, - (int)slotP, - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA, - mu, - cc->frame_type, - &format, - &start_symbol, - &N_t_slot, - &N_dur, - &RA_sfn_index, - &N_RA_slot, - &config_period)) { - - uint16_t format0 = format & 0xff; // first column of format from table - uint16_t format1 = (format >> 8) & 0xff; // second column of format from table - - if (N_RA_slot > 1) { //more than 1 PRACH slot in a subframe + uint16_t RA_sfn_index = -1; + frequency_range_t freq_range = scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA > 2016666 ? FR2 : FR1; + if (get_nr_prach_sched_from_info(cc->prach_info, config_index, frameP, slotP, mu, freq_range, &RA_sfn_index, cc->frame_type)) { + uint16_t format0 = cc->prach_info.format & 0xff; // first column of format from table + uint16_t format1 = (cc->prach_info.format >> 8) & 0xff; // second column of format from table + + if (cc->prach_info.N_RA_slot > 1) { // more than 1 PRACH slot in a subframe if (slotP % 2 == 1) slot_index = 1; else slot_index = 0; - } else if (N_RA_slot <= 1) { //1 PRACH slot in a subframe + } else if (cc->prach_info.N_RA_slot <= 1) { // 1 PRACH slot in a subframe slot_index = 0; } @@ -439,9 +398,11 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) UL_tti_req->Slot = slotP; UL_tti_req->rach_present = 1; NR_beam_alloc_t beam = {0}; + uint32_t N_t_slot = cc->prach_info.N_t_slot; + uint32_t start_symb = cc->prach_info.start_symbol; for (int fdm_index = 0; fdm_index < fdm; fdm_index++) { // one structure per frequency domain occasion for (int td_index = 0; td_index < N_t_slot; td_index++) { - + uint32_t config_period = cc->prach_info.x; prach_occasion_id = (((frameP % (cc->max_association_period * config_period))/config_period) * cc->total_prach_occasions_per_config_period) + (RA_sfn_index + slot_index) * N_t_slot * fdm + td_index * fdm + fdm_index; @@ -482,7 +443,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) // filling the prach fapi structure prach_pdu->phys_cell_id = *scc->physCellId; prach_pdu->num_prach_ocas = N_t_slot; - prach_pdu->prach_start_symbol = start_symbol; + prach_pdu->prach_start_symbol = start_symb; prach_pdu->num_ra = fdm_index; prach_pdu->num_cs = get_NCS(rach_ConfigGeneric->zeroCorrelationZoneConfig, format0, @@ -499,7 +460,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) slotP, prach_occasion_id, prach_pdu->num_ra, - prach_pdu->prach_start_symbol, + start_symb, slot_index, RA_sfn_index); // SCF PRACH PDU format field does not consider A1/B1 etc. possibilities @@ -579,13 +540,12 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) const int16_t n_ra_rb = get_N_RA_RB(cfg->prach_config.prach_sub_c_spacing.value, mu_pusch); // mark PRBs as occupied for current and future slots if prach extends beyond current slot int total_prach_slots; + uint32_t N_dur = cc->prach_info.N_dur; if (format0 < 4) { N_dur = 14; // number of PRACH symbols in PRACH slot total_prach_slots = get_long_prach_dur(format0, mu_pusch); AssertFatal(slotP + total_prach_slots - 1 < slots_frame, "PRACH cannot extend across frames\n"); } else { - // TODO: to be revisited for format B4 (also extends beyond current slot for FR1 30kHz SCS and FR2) - AssertFatal((format != 0xb4) || (mu_pusch < 1), "Format B4 not supported for this PUSCH SCS\n"); total_prach_slots = 1; } // reserve PRBs occupied by PRACH in all PRACH slot. @@ -597,7 +557,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) gNB->vrb_map_UL_size, slots_frame, bwp_start + rach_ConfigGeneric->msg1_FrequencyStart, - start_symbol, + start_symb, N_t_slot * N_dur, cc); } @@ -1413,6 +1373,8 @@ static bool msg2_in_response_window(int rach_frame, int current_slot) { int window_slots = get_response_window(rrc_ra_ResponseWindow); + if (window_slots > n_slots_frame) + LOG_E(NR_MAC, "RA-ResponseWindow need to be configured to a value lower than or equal to 10 ms\n"); int abs_rach = n_slots_frame * rach_frame + rach_slot; int abs_now = n_slots_frame * current_frame + current_slot; int diff = (n_slots_frame * 1024 + abs_now - abs_rach) % (n_slots_frame * 1024); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 3f992f04095a8abdb10fb79fcfd466c1b5054c86..8b1bb3ec5c547faa4edd322f40c34142a4aa8a22 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -302,6 +302,7 @@ typedef struct { int cb_preambles_per_ssb; /// Max prach length in slots int prach_len; + nr_prach_info_t prach_info; } NR_COMMON_channels_t; // SP ZP CSI-RS Resource Set Activation/Deactivation MAC CE diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c index 9e7310cf40818b29a70fa0c0fd43024abab7f816..64de7b4560de477f7d39db09930cdb3f038c0443 100644 --- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c @@ -390,8 +390,7 @@ static bool is_my_dci(NR_UE_MAC_INST_t *mac, nfapi_nr_dl_dci_pdu_t *received_pdu already. Only once the RA procedure succeeds is the CRNTI value updated to the TC_RNTI. */ if (get_softmodem_params()->nsa) { - if (received_pdu->RNTI != mac->crnti && - (received_pdu->RNTI != mac->ra.ra_rnti || mac->ra.RA_RAPID_found)) + if (received_pdu->RNTI != mac->crnti && (received_pdu->RNTI != mac->ra.ra_rnti)) return false; } if (IS_SA_MODE(get_softmodem_params())) { @@ -1122,9 +1121,14 @@ static nr_dci_format_t handle_dci(NR_UE_MAC_INST_t *mac, // if notification of a reception of a PDCCH transmission of the SpCell is received from lower layers // if the C-RNTI MAC CE was included in Msg3 // consider this Contention Resolution successful - if (mac->ra.msg3_C_RNTI && mac->ra.ra_state == nrRA_WAIT_CONTENTION_RESOLUTION) + if (mac->msg3_C_RNTI && mac->ra.ra_state == nrRA_WAIT_CONTENTION_RESOLUTION) nr_ra_succeeded(mac, gNB_index, frame, slot); + // suspend RAR response window timer + // (in RFsim running multiple slot in parallel it might expire while decoding MSG2) + if (mac->ra.ra_state == nrRA_WAIT_RAR) + nr_timer_suspension(&mac->ra.response_window_timer); + return nr_ue_process_dci_indication_pdu(mac, frame, slot, dci); } @@ -1292,11 +1296,14 @@ static uint32_t nr_ue_dl_processing(NR_UE_MAC_INST_t *mac, nr_downlink_indicatio ret_mask |= (handle_dlsch(mac, dl_info, i)) << FAPI_NR_RX_PDU_TYPE_DLSCH; break; case FAPI_NR_RX_PDU_TYPE_RAR: - ret_mask |= (handle_dlsch(mac, dl_info, i)) << FAPI_NR_RX_PDU_TYPE_RAR; - if (!dl_info->rx_ind->rx_indication_body[i].pdsch_pdu.ack_nack) + if (!dl_info->rx_ind->rx_indication_body[i].pdsch_pdu.ack_nack) { LOG_W(PHY, "Received a RAR-Msg2 but LDPC decode failed\n"); - else + // resume RAR response window timer if MSG2 decoding failed + nr_timer_suspension(&mac->ra.response_window_timer); + } else { LOG_I(PHY, "RAR-Msg2 decoded\n"); + } + ret_mask |= (handle_dlsch(mac, dl_info, i)) << FAPI_NR_RX_PDU_TYPE_RAR; break; case FAPI_NR_CSIRS_IND: ret_mask |= (handle_csirs_measurements(mac, @@ -1330,12 +1337,15 @@ int nr_ue_dl_indication(nr_downlink_indication_t *dl_info) return ret2; } -void nr_ue_slot_indication(uint8_t mod_id) +void nr_ue_slot_indication(uint8_t mod_id, bool is_tx) { NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id); int ret = pthread_mutex_lock(&mac->if_mutex); AssertFatal(!ret, "mutex failed %d\n", ret); - update_mac_timers(mac); + if (is_tx) + update_mac_ul_timers(mac); + else + update_mac_dl_timers(mac); ret = pthread_mutex_unlock(&mac->if_mutex); AssertFatal(!ret, "mutex failed %d\n", ret); } diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h index e6a4bfa80b136bfb03e0ac7ad9b14f4b519b71ff..2bbd97db843d2c9cb40824a6ebdd96b5cc008ac2 100644 --- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h +++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h @@ -260,7 +260,7 @@ typedef int (nr_ue_dl_indication_f)(nr_downlink_indication_t *dl_info); */ typedef int (nr_ue_ul_indication_f)(nr_uplink_indication_t *ul_info); -typedef void (nr_ue_slot_indication_f)(uint8_t mod_id); +typedef void (nr_ue_slot_indication_f)(uint8_t mod_id, bool is_tx); /* * Generic type of an application-defined callback to return various diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index f6dead1213369ef0ca5f4cd7298d65a827501799..a6c2ae1c9cac47ed4e32350c399133aea7d97501 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; diff --git a/openair2/RRC/NR_UE/L2_interface_ue.c b/openair2/RRC/NR_UE/L2_interface_ue.c index 7fd34ff91c5d3b72b086b75f95e3cd8ff8ae6c0e..3bfe1d34e02b0bd2efcc5dae5688bd443aabfb4b 100644 --- a/openair2/RRC/NR_UE/L2_interface_ue.c +++ b/openair2/RRC/NR_UE/L2_interface_ue.c @@ -159,11 +159,11 @@ void nr_mac_rrc_inactivity_timer_ind(const module_id_t mod_id) itti_send_msg_to_task(TASK_RRC_NRUE, GNB_MODULE_ID_TO_INSTANCE(mod_id), message_p); } -void nr_mac_rrc_msg3_ind(const module_id_t mod_id, const int rnti, int gnb_id) +void nr_mac_rrc_msg3_ind(const module_id_t mod_id, const int rnti, bool prepare_payload) { MessageDef *message_p = itti_alloc_new_message(TASK_MAC_UE, 0, NR_RRC_MAC_MSG3_IND); NR_RRC_MAC_MSG3_IND (message_p).rnti = rnti; - NR_RRC_MAC_MSG3_IND (message_p).gnb_id = gnb_id; + NR_RRC_MAC_MSG3_IND (message_p).prepare_payload = prepare_payload; itti_send_msg_to_task(TASK_RRC_NRUE, GNB_MODULE_ID_TO_INSTANCE(mod_id), message_p); } @@ -177,10 +177,9 @@ void nr_ue_rrc_timer_trigger(int instance, int frame, int gnb_id) itti_send_msg_to_task(TASK_RRC_NRUE, instance, message_p); } -void nr_mac_rrc_ra_ind(const module_id_t mod_id, int frame, bool success) +void nr_mac_rrc_ra_ind(const module_id_t mod_id, bool success) { MessageDef *message_p = itti_alloc_new_message(TASK_MAC_UE, 0, NR_RRC_MAC_RA_IND); - NR_RRC_MAC_RA_IND (message_p).frame = frame; NR_RRC_MAC_RA_IND (message_p).RA_succeeded = success; itti_send_msg_to_task(TASK_RRC_NRUE, GNB_MODULE_ID_TO_INSTANCE(mod_id), message_p); } diff --git a/openair2/RRC/NR_UE/L2_interface_ue.h b/openair2/RRC/NR_UE/L2_interface_ue.h index 05888cbc0e8f0ab360426dc4278e52711ad0e8e4..f394e5e33372da54d0972c5a8458432df9f00d44 100644 --- a/openair2/RRC/NR_UE/L2_interface_ue.h +++ b/openair2/RRC/NR_UE/L2_interface_ue.h @@ -37,9 +37,9 @@ void nr_mac_rrc_data_ind_ue(const module_id_t module_id, const uint8_t* pduP, const sdu_size_t pdu_len); void nr_mac_rrc_inactivity_timer_ind(const module_id_t mod_id); -void nr_mac_rrc_msg3_ind(const module_id_t mod_id, const int rnti, int gnb_id); +void nr_mac_rrc_msg3_ind(const module_id_t mod_id, const int rnti, bool prepare_payload); void nr_ue_rrc_timer_trigger(int instance, int frame, int gnb_id); -void nr_mac_rrc_ra_ind(const module_id_t mod_id, int frame, bool success); +void nr_mac_rrc_ra_ind(const module_id_t mod_id, bool success); void nsa_sendmsg_to_lte_ue(const void *message, size_t msg_len, Rrc_Msg_Type_t msg_type); void process_msg_rcc_to_mac(MessageDef *msg); #endif diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index f61ce49494fadfff7e0053e9cc34fa8f5b399636..d0d127377634516a81c2156568d5e5de65197a98 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -335,8 +335,6 @@ static void nr_rrc_process_sib1(NR_UE_RRC_INST_t *rrc, NR_UE_RRC_SI_INFO *SI_inf SI_info->sib1_validity = SIB_VALID; if (rrc->nrRrcState == RRC_STATE_IDLE_NR) { rrc->ra_trigger = RRC_CONNECTION_SETUP; - // preparing RRC setup request payload in advance - nr_rrc_ue_prepare_RRCSetupRequest(rrc); } NR_SIB1_v1700_IEs_t *sib1_v1700 = NULL; @@ -856,15 +854,6 @@ static void nr_rrc_ue_decode_NR_BCCH_BCH_Message(NR_UE_RRC_INST_t *rrc, nr_timer_stop(&timers->T311); rrc->ra_trigger = RRC_CONNECTION_REESTABLISHMENT; - // preparing MSG3 for re-establishment in advance - uint8_t buffer[1024]; - int buf_size = do_RRCReestablishmentRequest(buffer, - rrc->reestablishment_cause, - rrc->phyCellID, - rrc->rnti); // old rnti - - nr_rlc_srb_recv_sdu(rrc->ue_id, 0, buffer, buf_size); - // apply the default MAC Cell Group configuration // (done at MAC by calling nr_ue_mac_default_configs) @@ -892,6 +881,31 @@ static void nr_rrc_ue_decode_NR_BCCH_BCH_Message(NR_UE_RRC_INST_t *rrc, return; } +static void nr_rrc_ue_prepare_RRCReestablishmentRequest(NR_UE_RRC_INST_t *rrc) +{ + uint8_t buffer[1024]; + int buf_size = do_RRCReestablishmentRequest(buffer, rrc->reestablishment_cause, rrc->phyCellID, rrc->rnti); // old rnti + nr_rlc_srb_recv_sdu(rrc->ue_id, 0, buffer, buf_size); +} + +static void nr_rrc_prepare_msg3_payload(NR_UE_RRC_INST_t *rrc) +{ + if (!IS_SA_MODE(get_softmodem_params())) + return; + switch (rrc->ra_trigger) { + case RRC_CONNECTION_SETUP: + // preparing RRC setup request payload in advance + nr_rrc_ue_prepare_RRCSetupRequest(rrc); + break; + case RRC_CONNECTION_REESTABLISHMENT: + // preparing MSG3 for re-establishment in advance + nr_rrc_ue_prepare_RRCReestablishmentRequest(rrc); + break; + default: + AssertFatal(false, "RA trigger not implemented\n"); + } +} + static void nr_rrc_handle_msg3_indication(NR_UE_RRC_INST_t *rrc, rnti_t rnti) { NR_UE_Timers_Constants_t *tac = &rrc->timers_and_constants; @@ -1975,6 +1989,16 @@ void nr_rrc_handle_ra_indication(NR_UE_RRC_INST_t *rrc, bool ra_succeeded) nr_timer_stop(&timers->T304); // TODO handle the rest of procedures as described in 5.3.5.3 for when // reconfigurationWithSync is included in spCellConfig + } else if (!ra_succeeded) { + // upon random access problem indication from MCG MAC + // while neither T300, T301, T304, T311 nor T319 are running + // consider radio link failure to be detected + if (!nr_timer_is_active(&timers->T300) + && !nr_timer_is_active(&timers->T301) + && !nr_timer_is_active(&timers->T304) + && !nr_timer_is_active(&timers->T311) + && !nr_timer_is_active(&timers->T319)) + handle_rlf_detection(rrc); } } @@ -2035,16 +2059,18 @@ void *rrc_nrue(void *notUsed) break; case NR_RRC_MAC_MSG3_IND: - nr_rrc_handle_msg3_indication(rrc, NR_RRC_MAC_MSG3_IND(msg_p).rnti); + if (NR_RRC_MAC_MSG3_IND(msg_p).prepare_payload) + nr_rrc_prepare_msg3_payload(rrc); + else + nr_rrc_handle_msg3_indication(rrc, NR_RRC_MAC_MSG3_IND(msg_p).rnti); break; case NR_RRC_MAC_RA_IND: LOG_D(NR_RRC, - "[UE %ld] Received %s: frame %d RA %s\n", - rrc->ue_id, - ITTI_MSG_NAME(msg_p), - NR_RRC_MAC_RA_IND(msg_p).frame, - NR_RRC_MAC_RA_IND(msg_p).RA_succeeded ? "successful" : "failed"); + "[UE %ld] Received %s: RA %s\n", + rrc->ue_id, + ITTI_MSG_NAME(msg_p), + NR_RRC_MAC_RA_IND(msg_p).RA_succeeded ? "successful" : "failed"); nr_rrc_handle_ra_indication(rrc, NR_RRC_MAC_RA_IND(msg_p).RA_succeeded); break;