Merge branch 'integration_2025_w11' into 'develop'

Integration: `2025.w11`

Closes #848

See merge request oai/openairinterface5g!3309

* !3306 Add a new CI label: nrUE
* !3303 remove wrong assertion for B4 PRACH format
* !3296 fix(nrLDPC_decoder): fix numIter increment
* !3150 Rework of NR UE RA procedures
* !3305 CI: Fix timeout for OC Deployments
* !3307 Add CI UE test for RA with C-RNTI
* !3271 Handle changing N_TA_offset correctly
* !3313 Small fix for jenkins message formatting
This commit is contained in:
Jaroslava Fiedlerova
2025-03-18 15:21:56 +00:00
52 changed files with 1988 additions and 2516 deletions
+2 -2
View File
@@ -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')
+7 -7
View File
@@ -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
@@ -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>
@@ -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:
+9 -2
View File
@@ -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;
}
+7
View File
@@ -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
+9
View File
@@ -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},
};
+35 -6
View File
@@ -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)
+4
View File
@@ -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();
@@ -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
@@ -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 {
@@ -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 {
@@ -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};
-18
View File
@@ -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);
-1
View File
@@ -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);
@@ -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;
}
@@ -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
@@ -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.
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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
}
}
-9
View File
@@ -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,
+4 -9
View File
@@ -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)
+9 -10
View File
@@ -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
+1 -1
View File
@@ -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;
@@ -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) {}
+19 -22
View File
@@ -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;
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);
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
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) {
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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 {
-30
View File
@@ -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
//=========
+135 -263
View File
@@ -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 ((info.N_RA_slot == 1) && (slot % 2 == 0))
return false; // 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);
}
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
return false; // 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 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
}
}
}
+24 -27
View File
@@ -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);
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 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);
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);
+56 -40
View File
@@ -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);
+63 -98
View File
@@ -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;
+14 -58
View File
@@ -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);
-24
View File
@@ -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;
+8 -6
View File
@@ -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
File diff suppressed because it is too large Load Diff
@@ -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_;
}
@@ -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;
+198 -204
View File
@@ -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;
}
+133 -669
View File
@@ -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)
// 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;
if (!is_prach_frame(frameP, prach_occasion_info, ra->association_periods))
return;
fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
fapi_nr_prach_config_t *prach_config = &cfg->prach_config;
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_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;
@@ -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 = &current_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 = &current_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,
@@ -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 = &current_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 = &current_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);
+1 -2
View File
@@ -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);
}
+42 -80
View File
@@ -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 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
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
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);
+1
View File
@@ -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
+18 -8
View File
@@ -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);
}
+1 -1
View File
@@ -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
+1 -5
View File
@@ -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;
+3 -4
View File
@@ -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);
}
+2 -2
View File
@@ -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
+43 -17
View File
@@ -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;