Commit 10060982 authored by francescomani's avatar francescomani

Merge remote-tracking branch 'origin/ue-long-prach' into integration_2025_w09

parents f0fce7c1 591e0093
...@@ -70,7 +70,7 @@ gNBs = ...@@ -70,7 +70,7 @@ gNBs =
initialULBWPsubcarrierSpacing = 0; initialULBWPsubcarrierSpacing = 0;
#rach-ConfigCommon #rach-ConfigCommon
#rach-ConfigGeneric #rach-ConfigGeneric
prach_ConfigurationIndex = 98; prach_ConfigurationIndex = 7;
#prach_msg1_FDM #prach_msg1_FDM
#0 = one, 1=two, 2=four, 3=eight #0 = one, 1=two, 2=four, 3=eight
prach_msg1_FDM = 0; prach_msg1_FDM = 0;
...@@ -96,11 +96,11 @@ gNBs = ...@@ -96,11 +96,11 @@ gNBs =
rsrp_ThresholdSSB = 19; rsrp_ThresholdSSB = 19;
#prach-RootSequenceIndex_PR #prach-RootSequenceIndex_PR
#1 = 839, 2 = 139 #1 = 839, 2 = 139
prach_RootSequenceIndex_PR = 2; prach_RootSequenceIndex_PR = 1;
prach_RootSequenceIndex = 1; prach_RootSequenceIndex = 1;
# SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
# # not allowed when format < 4
msg1_SubcarrierSpacing = 0; # msg1_SubcarrierSpacing = 0;
# restrictedSetConfig # restrictedSetConfig
# 0=unrestricted, 1=restricted type A, 2=restricted type B # 0=unrestricted, 1=restricted type A, 2=restricted type B
restrictedSetConfig = 0; restrictedSetConfig = 0;
......
...@@ -1287,6 +1287,58 @@ int get_scan_ssb_first_sc(const double fc, const int nbRB, const int nrBand, con ...@@ -1287,6 +1287,58 @@ int get_scan_ssb_first_sc(const double fc, const int nbRB, const int nrBand, con
return numGscn; return numGscn;
} }
// Table 38.211 6.3.3.1-1
static uint8_t long_prach_dur[4] = {1, 3, 4, 1}; // 0.9, 2.28, 3.35, 0.9 ms
uint8_t get_long_prach_dur(unsigned int format, unsigned int mu)
{
AssertFatal(format < 4, "Invalid long PRACH format %d\n", format);
const int num_slots_subframe = (1 << mu);
const int prach_dur_subframes = long_prach_dur[format];
return (prach_dur_subframes * num_slots_subframe);
}
// Table 38.211 6.3.3.2-1
uint8_t get_PRACH_k_bar(unsigned int delta_f_RA_PRACH, unsigned int delta_f_PUSCH)
{
uint8_t k_bar = 0;
if (delta_f_RA_PRACH > 3) { // Rel 15 max PRACH SCS is 120 kHz, 4 and 5 are 1.25 and 5 kHz
// long formats
DevAssert(delta_f_PUSCH < 3);
DevAssert(delta_f_RA_PRACH < 6);
const uint8_t k_bar_table[3][2] = {{7, 12},
{1, 10},
{133, 7}};
k_bar = k_bar_table[delta_f_PUSCH][delta_f_RA_PRACH - 4];
} else {
if (delta_f_RA_PRACH == 3 && delta_f_PUSCH == 4) // \delta f_RA == 120 kHz AND \delta f == 480 kHz
k_bar = 1;
else if (delta_f_RA_PRACH == 3 && delta_f_PUSCH == 5) // \delta f_RA == 120 kHz AND \delta f == 960 kHz
k_bar = 23;
else
k_bar = 2;
}
return k_bar;
}
// K according to 38.211 5.3.2
unsigned int get_prach_K(int prach_sequence_length, int prach_fmt_id, int pusch_mu, int prach_mu)
{
unsigned int K = 1;
if (prach_sequence_length == 0) {
if (prach_fmt_id == 3)
K = (15 << pusch_mu) / 5;
else
K = (15 << pusch_mu) / 1.25;
} else if (prach_sequence_length == 1) {
K = (15 << pusch_mu) / (15 << prach_mu);
} else {
AssertFatal(0, "Invalid PRACH sequence length %d\n", prach_sequence_length);
}
return K;
}
int get_delay_idx(int delay, int max_delay_comp) int get_delay_idx(int delay, int max_delay_comp)
{ {
int delay_idx = max_delay_comp + delay; int delay_idx = max_delay_comp + delay;
......
...@@ -287,6 +287,9 @@ void check_ssb_raster(uint64_t freq, int band, int scs); ...@@ -287,6 +287,9 @@ void check_ssb_raster(uint64_t freq, int band, int scs);
int get_smallest_supported_bandwidth_index(int scs, frequency_range_t frequency_range, int n_rbs); int get_smallest_supported_bandwidth_index(int scs, frequency_range_t frequency_range, int n_rbs);
unsigned short get_m_srs(int c_srs, int b_srs); unsigned short get_m_srs(int c_srs, int b_srs);
unsigned short get_N_b_srs(int c_srs, int b_srs); unsigned short get_N_b_srs(int c_srs, int b_srs);
uint8_t get_long_prach_dur(unsigned int format, unsigned int num_slots_subframe);
uint8_t get_PRACH_k_bar(unsigned int delta_f_RA_PRACH, unsigned int delta_f_PUSCH);
unsigned int get_prach_K(int prach_sequence_length, int prach_fmt_id, int pusch_mu, int prach_mu);
int get_slot_idx_in_period(const int slot, const frame_structure_t *fs); int get_slot_idx_in_period(const int slot, const frame_structure_t *fs);
......
...@@ -1308,24 +1308,30 @@ void *ru_thread(void *param) ...@@ -1308,24 +1308,30 @@ void *ru_thread(void *param)
if (prach_id >= 0) { if (prach_id >= 0) {
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 1 ); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 1 );
T(T_GNB_PHY_PRACH_INPUT_SIGNAL, T_INT(proc->frame_rx), T_INT(proc->tti_rx), T_INT(0), T(T_GNB_PHY_PRACH_INPUT_SIGNAL,
T_BUFFER(&ru->common.rxdata[0][fp->get_samples_slot_timestamp(proc->tti_rx-1,fp,0)]/*-ru->N_TA_offset*/, fp->get_samples_per_slot(proc->tti_rx,fp)*4*2)); T_INT(proc->frame_rx),
int N_dur = get_nr_prach_duration(ru->prach_list[prach_id].fmt); T_INT(proc->tti_rx),
T_INT(0),
for (int prach_oc = 0; prach_oc<ru->prach_list[prach_id].num_prach_ocas; prach_oc++) { T_BUFFER(&ru->common.rxdata[0][fp->get_samples_slot_timestamp(proc->tti_rx - 1, fp, 0) /*-ru->N_TA_offset*/],
int prachStartSymbol = ru->prach_list[prach_id].prachStartSymbol + prach_oc * N_dur; (fp->get_samples_per_slot(proc->tti_rx - 1, fp) + fp->get_samples_per_slot(proc->tti_rx, fp)) * 4));
RU_PRACH_list_t *p = ru->prach_list + prach_id;
int N_dur = get_nr_prach_duration(p->fmt);
for (int prach_oc = 0; prach_oc < p->num_prach_ocas; prach_oc++) {
int prachStartSymbol = p->prachStartSymbol + prach_oc * N_dur;
//comment FK: the standard 38.211 section 5.3.2 has one extra term +14*N_RA_slot. This is because there prachStartSymbol is given wrt to start of the 15kHz slot or 60kHz slot. Here we work slot based, so this function is anyway only called in slots where there is PRACH. Its up to the MAC to schedule another PRACH PDU in the case there are there N_RA_slot \in {0,1}. //comment FK: the standard 38.211 section 5.3.2 has one extra term +14*N_RA_slot. This is because there prachStartSymbol is given wrt to start of the 15kHz slot or 60kHz slot. Here we work slot based, so this function is anyway only called in slots where there is PRACH. Its up to the MAC to schedule another PRACH PDU in the case there are there N_RA_slot \in {0,1}.
rx_nr_prach_ru(ru, rx_nr_prach_ru(ru,
ru->prach_list[prach_id].fmt, //could also use format p->fmt, // could also use format
ru->prach_list[prach_id].numRA, p->numRA,
prachStartSymbol, prachStartSymbol,
p->slot,
prach_oc, prach_oc,
proc->frame_rx, proc->frame_rx,
proc->tti_rx); proc->tti_rx);
} }
free_nr_ru_prach_entry(ru,prach_id); free_nr_ru_prach_entry(ru,prach_id);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 0); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 0);
} // end if (prach_id > 0) } // end if (prach_id >= 0)
} // end if (ru->feprx) } // end if (ru->feprx)
} // end if (slot_type == NR_UPLINK_SLOT || slot_type == NR_MIXED_SLOT) { } // end if (slot_type == NR_UPLINK_SLOT || slot_type == NR_MIXED_SLOT) {
......
...@@ -691,6 +691,7 @@ typedef struct ...@@ -691,6 +691,7 @@ typedef struct
fapi_nr_num_prach_fd_occasions_t* num_prach_fd_occasions_list; fapi_nr_num_prach_fd_occasions_t* num_prach_fd_occasions_list;
uint8_t ssb_per_rach;//SSB-per-RACH-occasion Value: 0: 1/8 1:1/4, 2:1/2 3:1 4:2 5:4, 6:8 7:16 uint8_t ssb_per_rach;//SSB-per-RACH-occasion Value: 0: 1/8 1:1/4, 2:1/2 3:1 4:2 5:4, 6:8 7:16
uint8_t prach_multiple_carriers_in_a_band;//0 = disabled 1 = enabled uint8_t prach_multiple_carriers_in_a_band;//0 = disabled 1 = enabled
uint8_t root_seq_computed; // flag set and used only in PHY to indicate if table is computed with this config
} fapi_nr_prach_config_t; } fapi_nr_prach_config_t;
......
...@@ -271,7 +271,6 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) ...@@ -271,7 +271,6 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB)
} }
ue->init_averaging = 1; ue->init_averaging = 1;
init_nr_prach_tables(839);
init_symbol_rotation(fp); init_symbol_rotation(fp);
init_timeshift_rotation(fp); init_timeshift_rotation(fp);
......
...@@ -43,6 +43,7 @@ void init_prach_list(PHY_VARS_gNB *gNB) ...@@ -43,6 +43,7 @@ void init_prach_list(PHY_VARS_gNB *gNB)
gNB->prach_vars.list[i].frame = -1; gNB->prach_vars.list[i].frame = -1;
gNB->prach_vars.list[i].slot = -1; gNB->prach_vars.list[i].slot = -1;
gNB->prach_vars.list[i].beam_nb = -1; gNB->prach_vars.list[i].beam_nb = -1;
gNB->prach_vars.list[i].num_slots = -1;
} }
} }
...@@ -51,24 +52,20 @@ void free_nr_prach_entry(PHY_VARS_gNB *gNB, int prach_id) ...@@ -51,24 +52,20 @@ void free_nr_prach_entry(PHY_VARS_gNB *gNB, int prach_id)
gNB->prach_vars.list[prach_id].frame = -1; gNB->prach_vars.list[prach_id].frame = -1;
gNB->prach_vars.list[prach_id].slot = -1; gNB->prach_vars.list[prach_id].slot = -1;
gNB->prach_vars.list[prach_id].beam_nb = -1; gNB->prach_vars.list[prach_id].beam_nb = -1;
gNB->prach_vars.list[prach_id].num_slots = -1;
} }
int16_t find_nr_prach(PHY_VARS_gNB *gNB,int frame, int slot, find_type_t type) { int16_t find_nr_prach(PHY_VARS_gNB *gNB,int frame, int slot, find_type_t type) {
AssertFatal(gNB!=NULL,"gNB is null\n"); AssertFatal(gNB!=NULL,"gNB is null\n");
for (uint16_t i=0; i<NUMBER_OF_NR_PRACH_MAX; i++) { for (uint16_t i=0; i<NUMBER_OF_NR_PRACH_MAX; i++) {
LOG_D(PHY,"searching for PRACH in %d.%d prach_index %d=> %d.%d\n", frame,slot,i, gNB_PRACH_list_t *p = gNB->prach_vars.list + i;
gNB->prach_vars.list[i].frame,gNB->prach_vars.list[i].slot); LOG_D(PHY, "searching for PRACH in %d.%d prach_index %d=> %d.%d\n", frame, slot, i, p->frame, p->slot);
if((type == SEARCH_EXIST_OR_FREE) && if ((type == SEARCH_EXIST_OR_FREE) && (p->frame == -1) && (p->slot == -1)) {
(gNB->prach_vars.list[i].frame == -1) && return i;
(gNB->prach_vars.list[i].slot == -1)) { } else if ((type == SEARCH_EXIST) && (p->frame == frame) && (p->slot + p->num_slots - 1 == slot)) {
return i; return i;
} }
else if ((type == SEARCH_EXIST) &&
(gNB->prach_vars.list[i].frame == frame) &&
(gNB->prach_vars.list[i].slot == slot)) {
return i;
}
} }
return -1; return -1;
} }
...@@ -80,6 +77,8 @@ void nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *p ...@@ -80,6 +77,8 @@ void nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *p
gNB_PRACH_list_t *prach = &gNB->prach_vars.list[prach_id]; gNB_PRACH_list_t *prach = &gNB->prach_vars.list[prach_id];
prach->frame = SFN; prach->frame = SFN;
prach->slot = Slot; prach->slot = Slot;
const int format = prach_pdu->prach_format;
prach->num_slots = (format < 4) ? get_long_prach_dur(format, gNB->frame_parms.numerology_index) : 1;
prach->beam_nb = 0; prach->beam_nb = 0;
if (gNB->common_vars.beam_id) { if (gNB->common_vars.beam_id) {
int fapi_beam_idx = prach_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; int fapi_beam_idx = prach_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx;
...@@ -98,6 +97,7 @@ void init_prach_ru_list(RU_t *ru) ...@@ -98,6 +97,7 @@ void init_prach_ru_list(RU_t *ru)
for (int i = 0; i < NUMBER_OF_NR_RU_PRACH_MAX; i++) { for (int i = 0; i < NUMBER_OF_NR_RU_PRACH_MAX; i++) {
ru->prach_list[i].frame = -1; ru->prach_list[i].frame = -1;
ru->prach_list[i].slot = -1; ru->prach_list[i].slot = -1;
ru->prach_list[i].num_slots = -1;
} }
pthread_mutex_init(&ru->prach_list_mutex, NULL); pthread_mutex_init(&ru->prach_list_mutex, NULL);
} }
...@@ -107,16 +107,12 @@ int16_t find_nr_prach_ru(RU_t *ru,int frame,int slot, find_type_t type) ...@@ -107,16 +107,12 @@ int16_t find_nr_prach_ru(RU_t *ru,int frame,int slot, find_type_t type)
AssertFatal(ru != NULL, "ru is null\n"); AssertFatal(ru != NULL, "ru is null\n");
pthread_mutex_lock(&ru->prach_list_mutex); pthread_mutex_lock(&ru->prach_list_mutex);
for (int i = 0; i < NUMBER_OF_NR_RU_PRACH_MAX; i++) { for (int i = 0; i < NUMBER_OF_NR_RU_PRACH_MAX; i++) {
LOG_D(PHY,"searching for PRACH in %d.%d : prach_index %d=> %d.%d\n", RU_PRACH_list_t *p = ru->prach_list + i;
frame, LOG_D(PHY, "searching for PRACH in %d.%d : prach_index %d=> %d.%d\n", frame, slot, i, p->frame, p->slot);
slot, if ((type == SEARCH_EXIST_OR_FREE) && (p->frame == -1) && (p->slot == -1)) {
i,
ru->prach_list[i].frame,ru->prach_list[i].slot);
if((type == SEARCH_EXIST_OR_FREE) && (ru->prach_list[i].frame == -1) && (ru->prach_list[i].slot == -1)) {
pthread_mutex_unlock(&ru->prach_list_mutex); pthread_mutex_unlock(&ru->prach_list_mutex);
return i; return i;
} } else if ((type == SEARCH_EXIST) && (p->frame == frame) && (p->slot + p->num_slots - 1 == slot)) {
else if ((type == SEARCH_EXIST) && (ru->prach_list[i].frame == frame) && (ru->prach_list[i].slot == slot)) {
pthread_mutex_unlock(&ru->prach_list_mutex); pthread_mutex_unlock(&ru->prach_list_mutex);
return i; return i;
} }
...@@ -135,7 +131,9 @@ void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_p ...@@ -135,7 +131,9 @@ void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_p
pthread_mutex_lock(&ru->prach_list_mutex); pthread_mutex_lock(&ru->prach_list_mutex);
ru->prach_list[prach_id].frame = SFN; ru->prach_list[prach_id].frame = SFN;
ru->prach_list[prach_id].slot = Slot; ru->prach_list[prach_id].slot = Slot;
ru->prach_list[prach_id].fmt = prach_pdu->prach_format; const int fmt = prach_pdu->prach_format;
ru->prach_list[prach_id].num_slots = (fmt < 4) ? get_long_prach_dur(fmt, ru->nr_frame_parms->numerology_index) : 1;
ru->prach_list[prach_id].fmt = fmt;
ru->prach_list[prach_id].numRA = prach_pdu->num_ra; ru->prach_list[prach_id].numRA = prach_pdu->num_ra;
ru->prach_list[prach_id].prachStartSymbol = prach_pdu->prach_start_symbol; ru->prach_list[prach_id].prachStartSymbol = prach_pdu->prach_start_symbol;
ru->prach_list[prach_id].num_prach_ocas = prach_pdu->num_prach_ocas; ru->prach_list[prach_id].num_prach_ocas = prach_pdu->num_prach_ocas;
...@@ -150,8 +148,14 @@ void free_nr_ru_prach_entry(RU_t *ru, int prach_id) ...@@ -150,8 +148,14 @@ void free_nr_ru_prach_entry(RU_t *ru, int prach_id)
pthread_mutex_unlock(&ru->prach_list_mutex); pthread_mutex_unlock(&ru->prach_list_mutex);
} }
void rx_nr_prach_ru(RU_t *ru,
void rx_nr_prach_ru(RU_t *ru, int prachFormat, int numRA, int prachStartSymbol, int prachOccasion, int frame, int slot) int prachFormat,
int numRA,
int prachStartSymbol,
int prachStartSlot,
int prachOccasion,
int frame,
int slot)
{ {
AssertFatal(ru != NULL,"ru is null\n"); AssertFatal(ru != NULL,"ru is null\n");
...@@ -161,6 +165,7 @@ void rx_nr_prach_ru(RU_t *ru, int prachFormat, int numRA, int prachStartSymbol, ...@@ -161,6 +165,7 @@ void rx_nr_prach_ru(RU_t *ru, int prachFormat, int numRA, int prachStartSymbol,
int16_t *prach[ru->nb_rx]; int16_t *prach[ru->nb_rx];
int prach_sequence_length = ru->config.prach_config.prach_sequence_length.value; int prach_sequence_length = ru->config.prach_config.prach_sequence_length.value;
int msg1_frequencystart = ru->config.prach_config.num_prach_fd_occasions_list[numRA].k1.value; int msg1_frequencystart = ru->config.prach_config.num_prach_fd_occasions_list[numRA].k1.value;
const uint8_t prach_mu = ru->config.prach_config.prach_sub_c_spacing.value;
int sample_offset_slot; int sample_offset_slot;
if (prachStartSymbol == 0) { if (prachStartSymbol == 0) {
...@@ -193,7 +198,7 @@ void rx_nr_prach_ru(RU_t *ru, int prachFormat, int numRA, int prachStartSymbol, ...@@ -193,7 +198,7 @@ void rx_nr_prach_ru(RU_t *ru, int prachFormat, int numRA, int prachStartSymbol,
for (int aa=0; aa<ru->nb_rx; aa++){ for (int aa=0; aa<ru->nb_rx; aa++){
if (prach_sequence_length == 0) if (prach_sequence_length == 0)
slot2 = (slot / fp->slots_per_subframe) * fp->slots_per_subframe; slot2 = prachStartSlot;
prach[aa] = (int16_t*)&ru->common.rxdata[aa][fp->get_samples_slot_timestamp(slot2, fp, 0) + sample_offset_slot - ru->N_TA_offset]; prach[aa] = (int16_t*)&ru->common.rxdata[aa][fp->get_samples_slot_timestamp(slot2, fp, 0) + sample_offset_slot - ru->N_TA_offset];
} }
...@@ -387,18 +392,9 @@ void rx_nr_prach_ru(RU_t *ru, int prachFormat, int numRA, int prachStartSymbol, ...@@ -387,18 +392,9 @@ void rx_nr_prach_ru(RU_t *ru, int prachFormat, int numRA, int prachStartSymbol,
LOG_D(PHY, "rx_prach: Doing PRACH FFT for nb_rx:%d Ncp:%d dftlen:%d\n", ru->nb_rx, Ncp, dftlen); LOG_D(PHY, "rx_prach: Doing PRACH FFT for nb_rx:%d Ncp:%d dftlen:%d\n", ru->nb_rx, Ncp, dftlen);
} }
// Note: Assumes PUSCH SCS @ 30 kHz, take values for formats 0-2 and adjust for others below const unsigned int K = get_prach_K(prach_sequence_length, prachFormat, fp->numerology_index, prach_mu);
int kbar = 1; const uint8_t kbar = get_PRACH_k_bar(prach_mu, fp->numerology_index);
int K = 24;
if (prach_sequence_length == 0 && prachFormat == 3) {
K=4;
kbar=10;
}
else if (prach_sequence_length == 1) {
// Note: Assumes that PRACH SCS is same as PUSCH SCS
K=1;
kbar=2;
}
int n_ra_prb = msg1_frequencystart; int n_ra_prb = msg1_frequencystart;
int k = (12*n_ra_prb) - 6*fp->N_RB_UL; int k = (12*n_ra_prb) - 6*fp->N_RB_UL;
...@@ -433,7 +429,6 @@ void rx_nr_prach_ru(RU_t *ru, int prachFormat, int numRA, int prachStartSymbol, ...@@ -433,7 +429,6 @@ void rx_nr_prach_ru(RU_t *ru, int prachFormat, int numRA, int prachStartSymbol,
} }
memcpy((void*)rxsigF2,(void *)rxsigF_tmp,N_ZC<<2); memcpy((void*)rxsigF2,(void *)rxsigF_tmp,N_ZC<<2);
} }
} }
void rx_nr_prach(PHY_VARS_gNB *gNB, void rx_nr_prach(PHY_VARS_gNB *gNB,
...@@ -542,7 +537,8 @@ void rx_nr_prach(PHY_VARS_gNB *gNB, ...@@ -542,7 +537,8 @@ void rx_nr_prach(PHY_VARS_gNB *gNB,
} }
} else { // This is the high-speed case } else { // This is the high-speed case
new_dft = 0; new_dft = 0;
nr_fill_du(N_ZC,prach_root_sequence_map); uint16_t nr_du[NR_PRACH_SEQ_LEN_L - 1];
nr_fill_du(N_ZC, prach_root_sequence_map, nr_du);
// set preamble_offset to initial rootSequenceIndex and look if we need more root sequences for this // set preamble_offset to initial rootSequenceIndex and look if we need more root sequences for this
// preamble index and find the corresponding cyclic shift // preamble index and find the corresponding cyclic shift
// Check if all shifts for that root have been processed // Check if all shifts for that root have been processed
......
...@@ -30,9 +30,6 @@ ...@@ -30,9 +30,6 @@
* \warning * \warning
*/ */
extern c16_t nr_ru[839]; // quantized roots of unity
extern uint16_t nr_du[838];
static const char* const prachfmt[] = {"0", "1", "2", "3", "A1", "A2", "A3", "B1", "B4", "C0", "C2", "A1/B1", "A2/B2", "A3/B3"}; static const char* const prachfmt[] = {"0", "1", "2", "3", "A1", "A2", "A3", "B1", "B4", "C0", "C2", "A1/B1", "A2/B2", "A3/B3"};
/************************************* /*************************************
......
...@@ -38,12 +38,34 @@ ...@@ -38,12 +38,34 @@
#include "common/utils/LOG/log.h" #include "common/utils/LOG/log.h"
#include "common/utils/LOG/vcd_signal_dumper.h" #include "common/utils/LOG/vcd_signal_dumper.h"
#include "T.h" #include "T.h"
c16_t nr_ru[839]; // quantized roots of unity
static uint32_t nr_ZC_inv[839]; // multiplicative inverse for roots u /* Extended Euclidean Algorithm to compute modulo inverse */
uint16_t nr_du[838]; static int modulo_multiplicative_inverse(const int a, const int m)
{
DevAssert(a < m);
int t = 0;
int newt = 1;
int r = m;
int newr = a;
while (newr != 0) {
const int q = r / newr;
int tmp = t;
t = newt;
newt = tmp - q * newt;
tmp = r;
r = newr;
newr = tmp - q * newr;
}
AssertFatal(r <= 1, "Modulo inverse doesn't exist for a %d, m %d\n", a, m);
t = (t < 0) ? t + m : t;
LOG_D(PHY, "Modulo %d inverse of %d is %d\n", m, a, t);
return t;
}
// This function computes the du // This function computes the du
void nr_fill_du(uint16_t N_ZC, const uint16_t *prach_root_sequence_map) void nr_fill_du(uint16_t N_ZC, const uint16_t* prach_root_sequence_map, uint16_t nr_du[NR_PRACH_SEQ_LEN_L - 1])
{ {
uint16_t iu,u,p; uint16_t iu,u,p;
...@@ -64,19 +86,15 @@ void nr_fill_du(uint16_t N_ZC, const uint16_t *prach_root_sequence_map) ...@@ -64,19 +86,15 @@ void nr_fill_du(uint16_t N_ZC, const uint16_t *prach_root_sequence_map)
void compute_nr_prach_seq(uint8_t short_sequence, uint8_t num_sequences, uint8_t rootSequenceIndex, c16_t X_u[64][839]) void compute_nr_prach_seq(uint8_t short_sequence, uint8_t num_sequences, uint8_t rootSequenceIndex, c16_t X_u[64][839])
{ {
// Compute DFT of x_u => X_u[k] = x_u(inv(u)*k)^* X_u[k] = exp(j\pi u*inv(u)*k*(inv(u)*k+1)/N_ZC) // Compute DFT of x_u => X_u[k] = x_u(inv(u)*k)^* X_u[k] = exp(j\pi u*inv(u)*k*(inv(u)*k+1)/N_ZC)
unsigned int k,inv_u,i;
int N_ZC; int N_ZC;
const uint16_t *prach_root_sequence_map; const uint16_t* prach_root_sequence_map;
uint16_t u;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_UE_COMPUTE_PRACH, VCD_FUNCTION_IN); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_UE_COMPUTE_PRACH, VCD_FUNCTION_IN);
LOG_D(PHY,"compute_prach_seq: prach short sequence %x, num_sequences %d, rootSequenceIndex %d\n", short_sequence, num_sequences, rootSequenceIndex); LOG_D(PHY,"compute_prach_seq: prach short sequence %x, num_sequences %d, rootSequenceIndex %d\n", short_sequence, num_sequences, rootSequenceIndex);
N_ZC = (short_sequence) ? 139 : 839; N_ZC = (short_sequence) ? NR_PRACH_SEQ_LEN_S : NR_PRACH_SEQ_LEN_L;
init_nr_prach_tables(N_ZC);
if (short_sequence) { if (short_sequence) {
// FIXME cannot be reached // FIXME cannot be reached
...@@ -87,7 +105,7 @@ void compute_nr_prach_seq(uint8_t short_sequence, uint8_t num_sequences, uint8_t ...@@ -87,7 +105,7 @@ void compute_nr_prach_seq(uint8_t short_sequence, uint8_t num_sequences, uint8_t
LOG_D( PHY, "compute_prach_seq: done init prach_tables\n" ); LOG_D( PHY, "compute_prach_seq: done init prach_tables\n" );
for (i=0; i<num_sequences; i++) { for (int i = 0; i < num_sequences; i++) {
int index = (rootSequenceIndex+i) % (N_ZC-1); int index = (rootSequenceIndex+i) % (N_ZC-1);
if (short_sequence) { if (short_sequence) {
...@@ -98,58 +116,22 @@ void compute_nr_prach_seq(uint8_t short_sequence, uint8_t num_sequences, uint8_t ...@@ -98,58 +116,22 @@ void compute_nr_prach_seq(uint8_t short_sequence, uint8_t num_sequences, uint8_t
DevAssert( index < sizeof(prach_root_sequence_map_0_3) / sizeof(prach_root_sequence_map_0_3[0]) ); DevAssert( index < sizeof(prach_root_sequence_map_0_3) / sizeof(prach_root_sequence_map_0_3[0]) );
} }
u = prach_root_sequence_map[index]; const uint16_t u = prach_root_sequence_map[index];
LOG_D(PHY,"prach index %d => u=%d\n",index,u); LOG_D(PHY,"prach index %d => u=%d\n",index,u);
inv_u = nr_ZC_inv[u]; // multiplicative inverse of u const int inv_u = modulo_multiplicative_inverse(u, N_ZC); // multiplicative inverse of u
// X_u[0] stores the first ZC sequence where the root u has a non-zero number of shifts // X_u[0] stores the first ZC sequence where the root u has a non-zero number of shifts
// for the unrestricted case X_u[0] is the first root indicated by the rootSequenceIndex // for the unrestricted case X_u[0] is the first root indicated by the rootSequenceIndex
for (k=0; k<N_ZC; k++) { const int zc_inv_2 = modulo_multiplicative_inverse(2, N_ZC);
for (int k = 0; k < N_ZC; k++) {
const unsigned int j = (((k * (1 + (inv_u * k))) % N_ZC) * zc_inv_2) % N_ZC;
const double w = 2 * M_PI * (double)j / N_ZC;
const c16_t ru = {.r = (int16_t)(floor(32767.0 * cos(w))), .i = (int16_t)(floor(32767.0 * sin(w)))};
// multiply by inverse of 2 (required since ru is exp[j 2\pi n]) // multiply by inverse of 2 (required since ru is exp[j 2\pi n])
X_u[i][k] = nr_ru[(((k * (1 + (inv_u * k))) % N_ZC) * nr_ZC_inv[2]) % N_ZC]; X_u[i][k] = ru;
} }
} }
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_UE_COMPUTE_PRACH, VCD_FUNCTION_OUT); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_UE_COMPUTE_PRACH, VCD_FUNCTION_OUT);
}
void init_nr_prach_tables(int N_ZC)
{
int i,m;
// Compute the modular multiplicative inverse 'iu' of u s.t. iu*u = 1 mod N_ZC
nr_ZC_inv[0] = 0;
nr_ZC_inv[1] = 1;
for (i=2; i<N_ZC; i++) {
for (m=2; m<N_ZC; m++)
if (((i*m)%N_ZC) == 1) {
nr_ZC_inv[i] = m;
break;
}
#ifdef PRACH_DEBUG
if (i<16)
printf("i %d : inv %d\n",i,nr_ZC_inv[i]);
#endif
}
// Compute quantized roots of unity
for (i=0; i<N_ZC; i++) {
nr_ru[i].r = (int16_t)(floor(32767.0 * cos(2 * M_PI * (double)i / N_ZC)));
nr_ru[i].i = (int16_t)(floor(32767.0 * sin(2 * M_PI * (double)i / N_ZC)));
#ifdef PRACH_DEBUG
if (i<16)
printf("i %d : runity %d,%d\n", i, nr_ru[i].r, nr_ru[i].i);
#endif
}
} }
...@@ -67,9 +67,7 @@ uint32_t nr_get_E(uint32_t G, uint8_t C, uint8_t Qm, uint8_t Nl, uint8_t r); ...@@ -67,9 +67,7 @@ uint32_t nr_get_E(uint32_t G, uint8_t C, uint8_t Qm, uint8_t Nl, uint8_t r);
void compute_nr_prach_seq(uint8_t short_sequence, uint8_t num_sequences, uint8_t rootSequenceIndex, c16_t X_u[64][839]); void compute_nr_prach_seq(uint8_t short_sequence, uint8_t num_sequences, uint8_t rootSequenceIndex, c16_t X_u[64][839]);
void nr_fill_du(uint16_t N_ZC, const uint16_t *prach_root_sequence_map); void nr_fill_du(uint16_t N_ZC, const uint16_t *prach_root_sequence_map, uint16_t nr_du[NR_PRACH_SEQ_LEN_L - 1]);
void init_nr_prach_tables(int N_ZC);
void nr_codeword_scrambling(uint8_t *in, void nr_codeword_scrambling(uint8_t *in,
uint32_t size, uint32_t size,
...@@ -84,4 +82,5 @@ void nr_codeword_unscrambling_init(int16_t *s, uint32_t size, uint8_t q, uint32_ ...@@ -84,4 +82,5 @@ void nr_codeword_unscrambling_init(int16_t *s, uint32_t size, uint8_t q, uint32_
/**@}*/ /**@}*/
void init_pucch2_luts(void); void init_pucch2_luts(void);
void set_prach_tables(int N_ZC, c16_t** ru, uint32_t** zc_inv);
#endif #endif
...@@ -275,7 +275,8 @@ void rx_nr_prach_ru(RU_t *ru, ...@@ -275,7 +275,8 @@ void rx_nr_prach_ru(RU_t *ru,
int prach_fmt, int prach_fmt,
int numRA, int numRA,
int prachStartSymbol, int prachStartSymbol,
int prachOccasion, int prachStartSlot,
int prachOccasion,
int frame, int frame,
int subframe); int subframe);
......
...@@ -63,17 +63,17 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t ...@@ -63,17 +63,17 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t
const uint16_t *prach_root_sequence_map; const uint16_t *prach_root_sequence_map;
uint16_t preamble_shift = 0, preamble_index0, n_shift_ra, n_shift_ra_bar, d_start=INT16_MAX, numshift, N_ZC, u, offset, offset2, first_nonzero_root_idx; uint16_t preamble_shift = 0, preamble_index0, n_shift_ra, n_shift_ra_bar, d_start=INT16_MAX, numshift, N_ZC, u, offset, offset2, first_nonzero_root_idx;
c16_t prach[(4688 + 4 * 24576) * 2] __attribute__((aligned(32))) = {0}; c16_t prach[(4688 + 4 * 24576) * 2] __attribute__((aligned(32))) = {0};
int16_t prachF_tmp[(4688+4*24576)*4*2] __attribute__((aligned(32))) = {0}; c16_t prachF_tmp[(4688 + 4 * 24576) * 4] __attribute__((aligned(32))) = {0};
int Ncp = 0; int Ncp = 0;
int prach_start, prach_sequence_length, i, prach_len, dftlen, mu, kbar, K, n_ra_prb, k, prachStartSymbol, sample_offset_slot; int prach_start, prach_sequence_length, prach_len, dftlen, mu, n_ra_prb, k, prachStartSymbol, sample_offset_slot;
fd_occasion = 0; fd_occasion = 0;
prach_len = 0; prach_len = 0;
dftlen = 0; dftlen = 0;
first_nonzero_root_idx = 0; first_nonzero_root_idx = 0;
int16_t amp = ue->prach_vars[gNB_id]->amp; int16_t amp = prach_pdu->prach_tx_power;
int16_t *prachF = prachF_tmp; c16_t *prachF = prachF_tmp;
Mod_id = ue->Mod_id; Mod_id = ue->Mod_id;
prach_sequence_length = nrUE_config->prach_config.prach_sequence_length; prach_sequence_length = nrUE_config->prach_config.prach_sequence_length;
N_ZC = (prach_sequence_length == 0) ? 839:139; N_ZC = (prach_sequence_length == 0) ? 839:139;
...@@ -83,18 +83,19 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t ...@@ -83,18 +83,19 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t
n_ra_prb = nrUE_config->prach_config.num_prach_fd_occasions_list[fd_occasion].k1,//prach_pdu->freq_msg1; n_ra_prb = nrUE_config->prach_config.num_prach_fd_occasions_list[fd_occasion].k1,//prach_pdu->freq_msg1;
NCS = prach_pdu->num_cs; NCS = prach_pdu->num_cs;
prach_fmt_id = prach_pdu->prach_format; prach_fmt_id = prach_pdu->prach_format;
preamble_index = prach_pdu->ra_PreambleIndex; preamble_index = prach_pdu->ra_PreambleIndex;
kbar = 1;
K = 24;
k = 12*n_ra_prb - 6*fp->N_RB_UL; k = 12*n_ra_prb - 6*fp->N_RB_UL;
prachStartSymbol = prach_pdu->prach_start_symbol; prachStartSymbol = prach_pdu->prach_start_symbol;
LOG_D(PHY,"Generate NR PRACH %d.%d\n", frame, slot); LOG_D(PHY,"Generate NR PRACH %d.%d\n", frame, slot);
compute_nr_prach_seq(nrUE_config->prach_config.prach_sequence_length, if (nrUE_config->prach_config.root_seq_computed == 0) {
nrUE_config->prach_config.num_prach_fd_occasions_list[fd_occasion].num_root_sequences, compute_nr_prach_seq(nrUE_config->prach_config.prach_sequence_length,
nrUE_config->prach_config.num_prach_fd_occasions_list[fd_occasion].prach_root_sequence_index, nrUE_config->prach_config.num_prach_fd_occasions_list[fd_occasion].num_root_sequences,
ue->X_u); nrUE_config->prach_config.num_prach_fd_occasions_list[fd_occasion].prach_root_sequence_index,
ue->X_u);
nrUE_config->prach_config.root_seq_computed = 1;
}
if (prachStartSymbol == 0) { if (prachStartSymbol == 0) {
sample_offset_slot = 0; sample_offset_slot = 0;
...@@ -137,7 +138,8 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t ...@@ -137,7 +138,8 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t
#endif #endif
not_found = 1; not_found = 1;
nr_fill_du(N_ZC,prach_root_sequence_map); uint16_t nr_du[NR_PRACH_SEQ_LEN_L - 1];
nr_fill_du(N_ZC, prach_root_sequence_map, nr_du);
preamble_index0 = preamble_index; preamble_index0 = preamble_index;
// set preamble_offset to initial rootSequenceIndex and look if we need more root sequences for this // set preamble_offset to initial rootSequenceIndex and look if we need more root sequences for this
// preamble index and find the corresponding cyclic shift // preamble index and find the corresponding cyclic shift
...@@ -210,20 +212,14 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t ...@@ -210,20 +212,14 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t
// nsymb = (frame_parms->Ncp==0) ? 14:12; // nsymb = (frame_parms->Ncp==0) ? 14:12;
// subframe_offset = (unsigned int)frame_parms->ofdm_symbol_size*slot*nsymb; // subframe_offset = (unsigned int)frame_parms->ofdm_symbol_size*slot*nsymb;
if (prach_sequence_length == 0 && prach_fmt_id == 3) { const unsigned int K = get_prach_K(prach_sequence_length, prach_fmt_id, fp->numerology_index, mu);
K = 4; const uint8_t kbar = get_PRACH_k_bar(mu, fp->numerology_index);
kbar = 10;
} else if (prach_sequence_length == 1) {
K = 1;
kbar = 2;
}
if (k<0) if (k < 0)
k += fp->ofdm_symbol_size; k += fp->ofdm_symbol_size;
k *= K; k *= K;
k += kbar; k += kbar;
k *= 2;
LOG_I(PHY, LOG_I(PHY,
"PRACH [UE %d] in frame.slot %d.%d, placing PRACH in position %d, Msg1/MsgA-Preamble frequency start %d (k1 %d), " "PRACH [UE %d] in frame.slot %d.%d, placing PRACH in position %d, Msg1/MsgA-Preamble frequency start %d (k1 %d), "
...@@ -231,7 +227,7 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t ...@@ -231,7 +227,7 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t
Mod_id, Mod_id,
frame, frame,
slot, slot,
k, k * 2,
n_ra_prb, n_ra_prb,
nrUE_config->prach_config.num_prach_fd_occasions_list[fd_occasion].k1, nrUE_config->prach_config.num_prach_fd_occasions_list[fd_occasion].k1,
preamble_offset, preamble_offset,
...@@ -262,7 +258,7 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t ...@@ -262,7 +258,7 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t
break; break;
default: default:
AssertFatal(1==0, "Illegal PRACH format %d for sequence length 839\n", prach_fmt_id); AssertFatal(1 == 0, "Illegal PRACH format %d for sequence length 839\n", prach_fmt_id);
break; break;
} }
} else { } else {
...@@ -413,12 +409,14 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t ...@@ -413,12 +409,14 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t
if (offset2 >= N_ZC) if (offset2 >= N_ZC)
offset2 -= N_ZC; offset2 -= N_ZC;
const int32_t Xu_re = (Xu[offset].r * amp) >> 15; const c16_t Xu_t = c16xmulConstShift(Xu[offset], amp, 15);
const int32_t Xu_im = (Xu[offset].i * amp) >> 15; const double w = 2 * M_PI * (double)offset2 / N_ZC;
prachF[k++] = (Xu_re * nr_ru[offset2].r - Xu_im * nr_ru[offset2].i) >> 15; const c16_t ru = {.r = (int16_t)(floor(32767.0 * cos(w))), .i = (int16_t)(floor(32767.0 * sin(w)))};
prachF[k++] = (Xu_im * nr_ru[offset2].r + Xu_re * nr_ru[offset2].i) >> 15; const c16_t p = c16mulShift(Xu_t, ru, 15);
prachF[k++] = p;
if (k==dftlen) k=0;
if (k * 2 == dftlen)
k = 0;
} }
#if defined (PRACH_WRITE_OUTPUT_DEBUG) #if defined (PRACH_WRITE_OUTPUT_DEBUG)
...@@ -429,7 +427,7 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t ...@@ -429,7 +427,7 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t
// This is after cyclic prefix // This is after cyclic prefix
c16_t *prach2 = prach + Ncp; c16_t *prach2 = prach + Ncp;
const idft_size_idx_t idft_size = get_idft(dftlen); const idft_size_idx_t idft_size = get_idft(dftlen);
idft(idft_size, prachF, (int16_t *)prach, 1); idft(idft_size, (int16_t *)prachF, (int16_t *)prach, 1);
memmove(prach2, prach, (dftlen << 2)); memmove(prach2, prach, (dftlen << 2));
if (prach_sequence_length == 0) { if (prach_sequence_length == 0) {
...@@ -504,21 +502,17 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t ...@@ -504,21 +502,17 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t
} }
} }
#ifdef NR_PRACH_DEBUG #ifdef NR_PRACH_DEBUG
LOG_I(PHY, "PRACH [UE %d] N_RB_UL %d prach_start %d, prach_len %d\n", Mod_id, LOG_I(PHY, "PRACH [UE %d] N_RB_UL %d prach_start %d, prach_len %d\n", Mod_id, fp->N_RB_UL, prach_start, prach_len);
fp->N_RB_UL, #endif
prach_start,
prach_len);
#endif
for (i = 0; i < prach_len; i++) memcpy(ue->common_vars.txData[0] + prach_start, prach, sizeof(c16_t) * prach_len);
ue->common_vars.txData[0][prach_start + i] = prach[i];
#ifdef PRACH_WRITE_OUTPUT_DEBUG #ifdef PRACH_WRITE_OUTPUT_DEBUG
LOG_M("prach_tx0.m", "prachtx0", prach+(Ncp<<1), prach_len-Ncp, 1, 1); LOG_M("prach_tx0.m", "prachtx0", prach + (Ncp << 1), prach_len - Ncp, 1, 1);
LOG_M("Prach_txsig.m","txs",(int16_t*)(&ue->common_vars.txdata[0][prach_start]), 2*(prach_start+prach_len), 1, 1) LOG_M("Prach_txsig.m", "txs", (int16_t *)(&ue->common_vars.txdata[0][prach_start]), 2 * (prach_start + prach_len), 1, 1)
#endif #endif
return signal_energy((int*)prach, 256); return signal_energy((int *)prach, 256);
} }
...@@ -195,6 +195,7 @@ typedef struct { ...@@ -195,6 +195,7 @@ typedef struct {
int numRA; int numRA;
int prachStartSymbol; int prachStartSymbol;
int num_prach_ocas; int num_prach_ocas;
int num_slots;
} RU_PRACH_list_t; } RU_PRACH_list_t;
#define NUMBER_OF_NR_RU_PRACH_MAX 8 #define NUMBER_OF_NR_RU_PRACH_MAX 8
...@@ -426,7 +427,6 @@ typedef enum { ...@@ -426,7 +427,6 @@ typedef enum {
WAIT_RESYNCH = 3 WAIT_RESYNCH = 3
} rru_cmd_t; } rru_cmd_t;
typedef struct RU_t_s { typedef struct RU_t_s {
/// ThreadPool for RU /// ThreadPool for RU
tpool_t *threadPool; tpool_t *threadPool;
......
...@@ -141,6 +141,8 @@ typedef struct { ...@@ -141,6 +141,8 @@ typedef struct {
int slot; int slot;
// identifier for concurrent beams // identifier for concurrent beams
int beam_nb; int beam_nb;
// prach duration in slots
int num_slots;
nfapi_nr_prach_pdu_t pdu; nfapi_nr_prach_pdu_t pdu;
} gNB_PRACH_list_t; } gNB_PRACH_list_t;
......
...@@ -298,6 +298,7 @@ typedef struct { ...@@ -298,6 +298,7 @@ typedef struct {
typedef struct { typedef struct {
int16_t amp; int16_t amp;
bool active; bool active;
int num_prach_slots;
fapi_nr_ul_config_prach_pdu prach_pdu; fapi_nr_ul_config_prach_pdu prach_pdu;
} NR_UE_PRACH; } NR_UE_PRACH;
......
...@@ -56,6 +56,8 @@ static const uint8_t N_slot_subframe[MU_NUMBER] = {1, 2, 4, 8, 16}; ...@@ -56,6 +56,8 @@ static const uint8_t N_slot_subframe[MU_NUMBER] = {1, 2, 4, 8, 16};
#define NB_DL_DATA_TO_UL_ACK (8) /* size of table TS 38.213 Table 9.2.3-1 */ #define NB_DL_DATA_TO_UL_ACK (8) /* size of table TS 38.213 Table 9.2.3-1 */
#define NR_PRACH_SEQ_LEN_L 839
#define NR_PRACH_SEQ_LEN_S 139
/*********************************************************************** /***********************************************************************
* *
......
...@@ -51,7 +51,8 @@ ...@@ -51,7 +51,8 @@
FN(ULSCH_RATE_MATCHING_STATS),\ FN(ULSCH_RATE_MATCHING_STATS),\
FN(ULSCH_INTERLEAVING_STATS),\ FN(ULSCH_INTERLEAVING_STATS),\
FN(ULSCH_ENCODING_STATS),\ FN(ULSCH_ENCODING_STATS),\
FN(OFDM_MOD_STATS) FN(OFDM_MOD_STATS),\
FN(PRACH_GEN_STATS)
typedef enum { typedef enum {
FOREACH_NR_PHY_CPU_MEAS(NOOP), FOREACH_NR_PHY_CPU_MEAS(NOOP),
......
...@@ -111,11 +111,11 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac ...@@ -111,11 +111,11 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac
ru=gNB->RU_list[0]; ru=gNB->RU_list[0];
int prach_id=find_nr_prach(gNB,frame,slot,SEARCH_EXIST); int prach_id = find_nr_prach(gNB, frame, slot, SEARCH_EXIST);
if (prach_id >= 0) {
if (prach_id>=0) {
LOG_D(NR_PHY,"%d.%d Got prach entry id %d\n",frame,slot,prach_id); LOG_D(NR_PHY,"%d.%d Got prach entry id %d\n",frame,slot,prach_id);
nfapi_nr_prach_pdu_t *prach_pdu = &gNB->prach_vars.list[prach_id].pdu; nfapi_nr_prach_pdu_t *prach_pdu = &gNB->prach_vars.list[prach_id].pdu;
const int prach_start_slot = gNB->prach_vars.list[prach_id].slot;
uint8_t prachStartSymbol; uint8_t prachStartSymbol;
uint8_t N_dur = get_nr_prach_duration(prach_pdu->prach_format); uint8_t N_dur = get_nr_prach_duration(prach_pdu->prach_format);
...@@ -151,7 +151,7 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac ...@@ -151,7 +151,7 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac
"[RAPROC] %d.%d Initiating RA procedure with preamble %d, energy %d.%d dB (I0 %d, thres %d), delay %d start symbol " "[RAPROC] %d.%d Initiating RA procedure with preamble %d, energy %d.%d dB (I0 %d, thres %d), delay %d start symbol "
"%u freq index %u\n", "%u freq index %u\n",
frame, frame,
slot, prach_start_slot,
max_preamble[0], max_preamble[0],
max_preamble_energy[0] / 10, max_preamble_energy[0] / 10,
max_preamble_energy[0] % 10, max_preamble_energy[0] % 10,
...@@ -187,6 +187,7 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac ...@@ -187,6 +187,7 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac
if (frame==0) LOG_I(PHY,"prach_I0 = %d.%d dB\n",gNB->measurements.prach_I0/10,gNB->measurements.prach_I0%10); if (frame==0) LOG_I(PHY,"prach_I0 = %d.%d dB\n",gNB->measurements.prach_I0/10,gNB->measurements.prach_I0%10);
if (gNB->prach_energy_counter < 100) gNB->prach_energy_counter++; if (gNB->prach_energy_counter < 100) gNB->prach_energy_counter++;
} //if prach_id>0 } //if prach_id>0
} //for NUMBER_OF_NR_PRACH_OCCASION_MAX rach_ind->slot = prach_start_slot;
} // for NUMBER_OF_NR_PRACH_OCCASION_MAX
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,0); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,0);
} }
...@@ -294,14 +294,19 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, n ...@@ -294,14 +294,19 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, n
pucch_procedures_ue_nr(ue, proc, phy_data, (c16_t **)&txdataF); pucch_procedures_ue_nr(ue, proc, phy_data, (c16_t **)&txdataF);
LOG_D(PHY, "Sending Uplink data \n"); LOG_D(PHY, "Sending Uplink data \n");
start_meas_nr_ue_phy(ue, OFDM_MOD_STATS);
nr_ue_pusch_common_procedures(ue, // Don't do OFDM Mod if txdata contains prach
proc->nr_slot_tx, const NR_UE_PRACH *prach_var = ue->prach_vars[proc->gNB_id];
&ue->frame_parms, if (!prach_var->active) {
ue->frame_parms.nb_antennas_tx, start_meas_nr_ue_phy(ue, OFDM_MOD_STATS);
(c16_t **)txdataF, nr_ue_pusch_common_procedures(ue,
link_type_ul); proc->nr_slot_tx,
stop_meas_nr_ue_phy(ue, OFDM_MOD_STATS); &ue->frame_parms,
ue->frame_parms.nb_antennas_tx,
(c16_t **)txdataF,
link_type_ul);
stop_meas_nr_ue_phy(ue, OFDM_MOD_STATS);
}
nr_ue_prach_procedures(ue, proc); nr_ue_prach_procedures(ue, proc);
...@@ -1168,36 +1173,57 @@ void nr_ue_prach_procedures(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc) ...@@ -1168,36 +1173,57 @@ void nr_ue_prach_procedures(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc)
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_PRACH, VCD_FUNCTION_IN); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_PRACH, VCD_FUNCTION_IN);
if (ue->prach_vars[gNB_id]->active) { NR_UE_PRACH *prach_var = ue->prach_vars[gNB_id];
fapi_nr_ul_config_prach_pdu *prach_pdu = &ue->prach_vars[gNB_id]->prach_pdu; if (prach_var->active) {
ue->tx_power_dBm[nr_slot_tx] = prach_pdu->prach_tx_power; fapi_nr_ul_config_prach_pdu *prach_pdu = &prach_var->prach_pdu;
// Generate PRACH in first slot. For L839, the following slots are also filled in this slot.
LOG_D(PHY, "In %s: [UE %d][RAPROC][%d.%d]: Generating PRACH Msg1 (preamble %d, P0_PRACH %d)\n", if (prach_pdu->prach_slot == nr_slot_tx) {
__FUNCTION__, ue->tx_power_dBm[nr_slot_tx] = prach_pdu->prach_tx_power;
mod_id,
frame_tx, LOG_D(PHY,
nr_slot_tx, "In %s: [UE %d][RAPROC][%d.%d]: Generating PRACH Msg1 (preamble %d, P0_PRACH %d)\n",
prach_pdu->ra_PreambleIndex, __FUNCTION__,
ue->tx_power_dBm[nr_slot_tx]); mod_id,
frame_tx,
ue->prach_vars[gNB_id]->amp = AMP; nr_slot_tx,
prach_pdu->ra_PreambleIndex,
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GENERATE_PRACH, VCD_FUNCTION_IN); ue->tx_power_dBm[nr_slot_tx]);
prach_power = generate_nr_prach(ue, gNB_id, frame_tx, nr_slot_tx); prach_var->amp = AMP;
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GENERATE_PRACH, VCD_FUNCTION_OUT); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GENERATE_PRACH, VCD_FUNCTION_IN);
start_meas_nr_ue_phy(ue, PRACH_GEN_STATS);
prach_power = generate_nr_prach(ue, gNB_id, frame_tx, nr_slot_tx);
stop_meas_nr_ue_phy(ue, PRACH_GEN_STATS);
if (cpumeas(CPUMEAS_GETSTATE)) {
LOG_D(PHY,
"[SFN %d.%d] PRACH Proc %5.2f\n",
proc->frame_tx,
proc->nr_slot_tx,
ue->phy_cpu_stats.cpu_time_stats[PRACH_GEN_STATS].p_time / (cpuf * 1000.0));
}
LOG_D(PHY, "In %s: [UE %d][RAPROC][%d.%d]: Generated PRACH Msg1 (TX power PRACH %d dBm, digital power %d dBW (amp %d)\n", VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_GENERATE_PRACH, VCD_FUNCTION_OUT);
__FUNCTION__,
mod_id, LOG_D(PHY,
frame_tx, "In %s: [UE %d][RAPROC][%d.%d]: Generated PRACH Msg1 (TX power PRACH %d dBm, digital power %d dBW (amp %d)\n",
nr_slot_tx, __FUNCTION__,
ue->tx_power_dBm[nr_slot_tx], mod_id,
dB_fixed(prach_power), frame_tx,
ue->prach_vars[gNB_id]->amp); nr_slot_tx,
ue->tx_power_dBm[nr_slot_tx],
dB_fixed(prach_power),
ue->prach_vars[gNB_id]->amp);
// set duration of prach slots so we know when to skip OFDM modulation
const int prach_format = ue->prach_vars[gNB_id]->prach_pdu.prach_format;
const int prach_slots = (prach_format < 4) ? get_long_prach_dur(prach_format, ue->frame_parms.numerology_index) : 1;
prach_var->num_prach_slots = prach_slots;
}
ue->prach_vars[gNB_id]->active = false; // set as inactive in the last slot
prach_var->active = !(nr_slot_tx == (prach_pdu->prach_slot + prach_var->num_prach_slots - 1));
} }
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_PRACH, VCD_FUNCTION_OUT); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_TX_PRACH, VCD_FUNCTION_OUT);
......
...@@ -562,6 +562,7 @@ int main(int argc, char **argv){ ...@@ -562,6 +562,7 @@ int main(int argc, char **argv){
prach_config->num_prach_fd_occasions_list[fd_occasion].k1.value = msg1_frequencystart; prach_config->num_prach_fd_occasions_list[fd_occasion].k1.value = msg1_frequencystart;
prach_config->restricted_set_config.value = restrictedSetConfig; prach_config->restricted_set_config.value = restrictedSetConfig;
prach_config->prach_sequence_length.value = prach_sequence_length; prach_config->prach_sequence_length.value = prach_sequence_length;
prach_config->prach_sub_c_spacing.value = mu;
prach_pdu->num_cs = get_NCS(NCS_config, format0, restrictedSetConfig); prach_pdu->num_cs = get_NCS(NCS_config, format0, restrictedSetConfig);
prach_config->num_prach_fd_occasions_list[fd_occasion].num_root_sequences.value = 1+(64/(N_ZC/prach_pdu->num_cs)); prach_config->num_prach_fd_occasions_list[fd_occasion].num_root_sequences.value = 1+(64/(N_ZC/prach_pdu->num_cs));
prach_pdu->prach_format = prach_format; prach_pdu->prach_format = prach_format;
...@@ -593,7 +594,7 @@ int main(int argc, char **argv){ ...@@ -593,7 +594,7 @@ int main(int argc, char **argv){
ue_prach_config = &UE->nrUE_config.prach_config; ue_prach_config = &UE->nrUE_config.prach_config;
txdata = UE->common_vars.txData; txdata = UE->common_vars.txData;
UE->prach_vars[0]->amp = AMP; ue_prach_pdu->prach_tx_power = AMP;
ue_prach_pdu->root_seq_id = rootSequenceIndex; ue_prach_pdu->root_seq_id = rootSequenceIndex;
ue_prach_pdu->num_cs = get_NCS(NCS_config, format0, restrictedSetConfig); ue_prach_pdu->num_cs = get_NCS(NCS_config, format0, restrictedSetConfig);
ue_prach_pdu->restricted_set = restrictedSetConfig; ue_prach_pdu->restricted_set = restrictedSetConfig;
...@@ -774,7 +775,7 @@ int main(int argc, char **argv){ ...@@ -774,7 +775,7 @@ int main(int argc, char **argv){
} }
} }
rx_nr_prach_ru(ru, prach_format, numRA, prachStartSymbol, prachOccasion, frame, slot); rx_nr_prach_ru(ru, prach_format, numRA, prachStartSymbol, slot, prachOccasion, frame, slot);
for (int i = 0; i < ru->nb_rx; ++i) for (int i = 0; i < ru->nb_rx; ++i)
gNB->prach_vars.rxsigF[i] = ru->prach_rxsigF[prachOccasion][i]; gNB->prach_vars.rxsigF[i] = ru->prach_rxsigF[prachOccasion][i];
......
...@@ -701,51 +701,33 @@ uint16_t get_NCS(uint8_t index, uint16_t format0, uint8_t restricted_set_config) ...@@ -701,51 +701,33 @@ uint16_t get_NCS(uint8_t index, uint16_t format0, uint8_t restricted_set_config)
} }
} }
//from 38.211 Table 6.3.3.2-1 //from 38.211 Table 6.3.3.2-1 // 15 30 60 120 240 480
static const int16_t N_RA_RB[16] = {6, 3, 2, 24, 12, 6, 12, 6, 3, 24, 12, 6, 12, 6, 24, 12}; static const unsigned int N_RA_RB[6][6] = {{12, 6, 3, -1, -1, -1},
{24, 12, 6, -1, -1, -1},
{-1, -1, 12, 6, -1, -1},
{-1, -1, 24, 12, 3, 2},
// L839
{6, 3, 2, -1, -1, -1},
{24, 12, 6, -1, -1, -1}};
/* Function to get number of RBs required for prach occasion based on /* Function to get number of RBs required for prach occasion based on
* 38.211 Table 6.3.3.2-1 */ * 38.211 Table 6.3.3.2-1 */
int16_t get_N_RA_RB (int delta_f_RA_PRACH, int delta_f_PUSCH) unsigned int get_N_RA_RB(const unsigned int delta_f_RA_PRACH, const unsigned int delta_f_PUSCH)
{ {
int8_t index = 0; DevAssert(delta_f_PUSCH < 6);
switch(delta_f_RA_PRACH) { DevAssert(delta_f_RA_PRACH < 6);
case 0 : unsigned int n_rb;
index = 6; n_rb = N_RA_RB[delta_f_RA_PRACH][delta_f_PUSCH];
if (delta_f_PUSCH == 0) DevAssert(n_rb != -1);
index += 0; return n_rb;
else if(delta_f_PUSCH == 1) }
index += 1;
else // frome Table 6.3.3.1-1
index += 2; unsigned int get_delta_f_RA_long(const unsigned int format)
break; {
case 1 : DevAssert(format < 4);
index = 9; return (format == 3) ? 5 : 4;
if (delta_f_PUSCH == 0) }
index += 0;
else if(delta_f_PUSCH == 1)
index += 1;
else
index += 2;
break;
case 2 :
index = 11;
if (delta_f_PUSCH == 2)
index += 0;
else
index += 1;
break;
case 3:
index = 13;
if (delta_f_PUSCH == 2)
index += 0;
else
index += 1;
break;
default : index = 10;/*30khz prach scs and 30khz pusch scs*/
}
return N_RA_RB[index];
}
// Table 6.3.3.2-2: Random access configurations for FR1 and paired spectrum/supplementary uplink // Table 6.3.3.2-2: Random access configurations for FR1 and paired spectrum/supplementary uplink
// the column 5, (SFN_nbr is a bitmap where we set bit to '1' in the position of the subframe where the RACH can be sent. // the column 5, (SFN_nbr is a bitmap where we set bit to '1' in the position of the subframe where the RACH can be sent.
// E.g. in row 4, and column 5 we have set value 512 ('1000000000') which means RACH can be sent at subframe 9. // E.g. in row 4, and column 5 we have set value 512 ('1000000000') which means RACH can be sent at subframe 9.
...@@ -1773,6 +1755,27 @@ int get_nr_prach_occasion_info_from_index(uint8_t index, ...@@ -1773,6 +1755,27 @@ int get_nr_prach_occasion_info_from_index(uint8_t index,
} }
} }
uint16_t get_nr_prach_format_from_index(uint8_t index, uint32_t pointa, uint8_t unpaired)
{
uint8_t format2 = 0xff;
uint16_t format;
if (pointa > 2016666) { // FR2
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);
} else {
if (unpaired) {
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);
} else {
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);
}
}
return format;
}
int get_nr_prach_info_from_index(uint8_t index, int get_nr_prach_info_from_index(uint8_t index,
int frame, int frame,
...@@ -1861,10 +1864,13 @@ int get_nr_prach_info_from_index(uint8_t index, ...@@ -1861,10 +1864,13 @@ int get_nr_prach_info_from_index(uint8_t index,
} }
if ((s_map >> subframe) & 0x01 ) { 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 *N_RA_slot = table_6_3_3_2_3_prachConfig_Index[index][6]; // Number of RACH slots within a subframe
if (mu == 1 && index >= 67) { if (index >= 67) {
if ((*N_RA_slot <= 1) && (slot % 2 == 0)) if ((mu == 1) && (*N_RA_slot <= 1) && (slot % 2 == 0))
return 0; // no prach in even slots @ 30kHz for 1 prach per subframe return 0; // no prach in even slots @ 30kHz for 1 prach per subframe
} } else {
if ((slot % 2) && (mu > 0))
return 0; // slot does not contain start symbol of this prach time resource
}
if (start_symbol != NULL && N_t_slot != NULL && N_dur != NULL && format != NULL) { if (start_symbol != NULL && N_t_slot != NULL && N_dur != NULL && format != NULL) {
*config_period = x; *config_period = x;
*start_symbol = table_6_3_3_2_3_prachConfig_Index[index][5]; *start_symbol = table_6_3_3_2_3_prachConfig_Index[index][5];
...@@ -5266,7 +5272,9 @@ int get_FeedbackDisabled(NR_DownlinkHARQ_FeedbackDisabled_r17_t *downlinkHARQ_Fe ...@@ -5266,7 +5272,9 @@ int get_FeedbackDisabled(NR_DownlinkHARQ_FeedbackDisabled_r17_t *downlinkHARQ_Fe
return (downlinkHARQ_FeedbackDisabled_r17->buf[byte_index] >> (7 - bit_index)) & 1; return (downlinkHARQ_FeedbackDisabled_r17->buf[byte_index] >> (7 - bit_index)) & 1;
} }
int nr_get_prach_mu(const NR_MsgA_ConfigCommon_r16_t *msgacc, const NR_RACH_ConfigCommon_t *rach_ConfigCommon) int nr_get_prach_or_ul_mu(const NR_MsgA_ConfigCommon_r16_t *msgacc,
const NR_RACH_ConfigCommon_t *rach_ConfigCommon,
const int ul_mu)
{ {
int mu; int mu;
...@@ -5278,7 +5286,8 @@ int nr_get_prach_mu(const NR_MsgA_ConfigCommon_r16_t *msgacc, const NR_RACH_Conf ...@@ -5278,7 +5286,8 @@ int nr_get_prach_mu(const NR_MsgA_ConfigCommon_r16_t *msgacc, const NR_RACH_Conf
// Choose Subcarrier Spacing of configuration file of 4-Step // Choose Subcarrier Spacing of configuration file of 4-Step
mu = *rach_ConfigCommon->msg1_SubcarrierSpacing; mu = *rach_ConfigCommon->msg1_SubcarrierSpacing;
} else } else
AssertFatal(false, "PRACH subcarrier spacing mandatory present for L139, not supported otherwise\n"); // Return invalid UL mu
mu = ul_mu;
return mu; return mu;
} }
...@@ -141,6 +141,8 @@ void find_aggregation_candidates(uint8_t *aggregation_level, ...@@ -141,6 +141,8 @@ void find_aggregation_candidates(uint8_t *aggregation_level,
const NR_SearchSpace_t *ss, const NR_SearchSpace_t *ss,
int maxL); int maxL);
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 get_nr_prach_info_from_index(uint8_t index,
int frame, int frame,
int slot, int slot,
...@@ -262,7 +264,8 @@ uint16_t compute_pucch_prb_size(uint8_t format, ...@@ -262,7 +264,8 @@ uint16_t compute_pucch_prb_size(uint8_t format,
float get_max_code_rate(NR_PUCCH_MaxCodeRate_t *maxCodeRate); float get_max_code_rate(NR_PUCCH_MaxCodeRate_t *maxCodeRate);
int get_f3_dmrs_symbols(NR_PUCCH_Resource_t *pucchres, NR_PUCCH_Config_t *pucch_Config); int get_f3_dmrs_symbols(NR_PUCCH_Resource_t *pucchres, NR_PUCCH_Config_t *pucch_Config);
int16_t get_N_RA_RB (int delta_f_RA_PRACH,int delta_f_PUSCH); unsigned int get_delta_f_RA_long(const unsigned int format);
unsigned int get_N_RA_RB(const unsigned int delta_f_RA_PRACH, const unsigned int delta_f_PUSCH);
void find_period_offset_SR(const NR_SchedulingRequestResourceConfig_t *SchedulingReqRec, int *period, int *offset); void find_period_offset_SR(const NR_SchedulingRequestResourceConfig_t *SchedulingReqRec, int *period, int *offset);
...@@ -334,6 +337,6 @@ int get_nrofHARQ_ProcessesForPDSCH(const NR_UE_ServingCell_Info_t *sc_info); ...@@ -334,6 +337,6 @@ int get_nrofHARQ_ProcessesForPDSCH(const NR_UE_ServingCell_Info_t *sc_info);
int get_nrofHARQ_ProcessesForPUSCH(const NR_UE_ServingCell_Info_t *sc_info); int get_nrofHARQ_ProcessesForPUSCH(const NR_UE_ServingCell_Info_t *sc_info);
int nr_get_prach_mu(const NR_MsgA_ConfigCommon_r16_t *msgacc, const NR_RACH_ConfigCommon_t *rach_ConfigCommon); int nr_get_prach_or_ul_mu(const NR_MsgA_ConfigCommon_r16_t *msgacc, const NR_RACH_ConfigCommon_t *rach_ConfigCommon, const int ul_mu);
#endif #endif
...@@ -190,7 +190,7 @@ static void config_common_ue_sa(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommo ...@@ -190,7 +190,7 @@ static void config_common_ue_sa(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommo
int config_index = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex; 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); 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 = prach_config_info_p[0];
cfg->prach_config.prach_sub_c_spacing = format == 3 ? 5 : 4; cfg->prach_config.prach_sub_c_spacing = get_delta_f_RA_long(format);
} }
cfg->prach_config.restricted_set_config = rach_ConfigCommon->restrictedSetConfig; cfg->prach_config.restricted_set_config = rach_ConfigCommon->restrictedSetConfig;
......
...@@ -76,9 +76,18 @@ void init_RA(NR_UE_MAC_INST_t *mac, ...@@ -76,9 +76,18 @@ void init_RA(NR_UE_MAC_INST_t *mac,
fapi_nr_config_request_t *cfg = &mac->phy_config.config_req; fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
prach_resources->RA_PREAMBLE_BACKOFF = 0; prach_resources->RA_PREAMBLE_BACKOFF = 0;
AssertFatal(nr_rach_ConfigCommon && nr_rach_ConfigCommon->msg1_SubcarrierSpacing, NR_SubcarrierSpacing_t prach_scs;
"Cannot handle yet the scenario without msg1_SubcarrierSpacing (L839)\n"); int scs_for_pcmax; // for long prach the UL BWP SCS is used for calculating RA_PCMAX
NR_SubcarrierSpacing_t prach_scs = *nr_rach_ConfigCommon->msg1_SubcarrierSpacing; if (nr_rach_ConfigCommon && nr_rach_ConfigCommon->msg1_SubcarrierSpacing) {
prach_scs = *nr_rach_ConfigCommon->msg1_SubcarrierSpacing;
scs_for_pcmax = prach_scs;
} else {
const unsigned int index = rach_ConfigGeneric->prach_ConfigurationIndex;
const unsigned int unpaired = mac->phy_config.config_req.cell_config.frame_duplex_type;
const unsigned int format = get_format0(index, unpaired, mac->frequency_range);
prach_scs = get_delta_f_RA_long(format);
scs_for_pcmax = mac->current_UL_BWP->scs;
}
int n_prbs = get_N_RA_RB(prach_scs, mac->current_UL_BWP->scs); int n_prbs = get_N_RA_RB(prach_scs, mac->current_UL_BWP->scs);
int start_prb = rach_ConfigGeneric->msg1_FrequencyStart + mac->current_UL_BWP->BWPStart; int start_prb = rach_ConfigGeneric->msg1_FrequencyStart + mac->current_UL_BWP->BWPStart;
// PRACH shall be as specified for QPSK modulated DFT-s-OFDM of equivalent RB allocation (38.101-1) // PRACH shall be as specified for QPSK modulated DFT-s-OFDM of equivalent RB allocation (38.101-1)
...@@ -89,8 +98,8 @@ void init_RA(NR_UE_MAC_INST_t *mac, ...@@ -89,8 +98,8 @@ void init_RA(NR_UE_MAC_INST_t *mac,
mac->current_UL_BWP->channel_bandwidth, mac->current_UL_BWP->channel_bandwidth,
2, 2,
false, false,
prach_scs, scs_for_pcmax,
cfg->carrier_config.dl_grid_size[prach_scs], cfg->carrier_config.dl_grid_size[scs_for_pcmax],
true, true,
n_prbs, n_prbs,
start_prb); start_prb);
...@@ -212,57 +221,16 @@ void init_RA(NR_UE_MAC_INST_t *mac, ...@@ -212,57 +221,16 @@ void init_RA(NR_UE_MAC_INST_t *mac,
} }
/* TS 38.321 subclause 7.3 - return DELTA_PREAMBLE values in dB */ /* TS 38.321 subclause 7.3 - return DELTA_PREAMBLE values in dB */
static int8_t nr_get_DELTA_PREAMBLE(NR_UE_MAC_INST_t *mac, int CC_id, uint16_t prach_format) static int8_t nr_get_DELTA_PREAMBLE(const NR_UE_MAC_INST_t *mac, int CC_id, uint16_t prach_format)
{ {
NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = mac->current_UL_BWP->rach_ConfigCommon; const NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = mac->current_UL_BWP->rach_ConfigCommon;
NR_SubcarrierSpacing_t scs = *nr_rach_ConfigCommon->msg1_SubcarrierSpacing;
int prach_sequence_length = nr_rach_ConfigCommon->prach_RootSequenceIndex.present - 1; int prach_sequence_length = nr_rach_ConfigCommon->prach_RootSequenceIndex.present - 1;
uint8_t prachConfigIndex, mu;
AssertFatal(CC_id == 0, "Transmission on secondary CCs is not supported yet\n"); AssertFatal(CC_id == 0, "Transmission on secondary CCs is not supported yet\n");
// SCS configuration from msg1_SubcarrierSpacing and table 4.2-1 in TS 38.211
switch (scs){
case NR_SubcarrierSpacing_kHz15:
mu = 0;
break;
case NR_SubcarrierSpacing_kHz30:
mu = 1;
break;
case NR_SubcarrierSpacing_kHz60:
mu = 2;
break;
case NR_SubcarrierSpacing_kHz120:
mu = 3;
break;
case NR_SubcarrierSpacing_kHz240:
mu = 4;
break;
case NR_SubcarrierSpacing_kHz480_v1700:
mu = 5;
break;
case NR_SubcarrierSpacing_kHz960_v1700:
mu = 6;
break;
case NR_SubcarrierSpacing_spare1:
mu = 7;
break;
default:
AssertFatal(1 == 0,"Unknown msg1_SubcarrierSpacing %lu\n", scs);
}
// Preamble formats given by prach_ConfigurationIndex and tables 6.3.3.2-2 and 6.3.3.2-2 in TS 38.211 // Preamble formats given by prach_ConfigurationIndex and tables 6.3.3.2-2 and 6.3.3.2-2 in TS 38.211
prachConfigIndex = nr_rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex; unsigned int prachConfigIndex = nr_rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex;
if (prach_sequence_length == 0) { if (prach_sequence_length == 0) {
AssertFatal(prach_format < 4, "Illegal PRACH format %d for sequence length 839\n", prach_format); AssertFatal(prach_format < 4, "Illegal PRACH format %d for sequence length 839\n", prach_format);
...@@ -278,8 +246,21 @@ static int8_t nr_get_DELTA_PREAMBLE(NR_UE_MAC_INST_t *mac, int CC_id, uint16_t p ...@@ -278,8 +246,21 @@ static int8_t nr_get_DELTA_PREAMBLE(NR_UE_MAC_INST_t *mac, int CC_id, uint16_t p
case 2: case 2:
return -6; return -6;
default:
AssertFatal(1 == 0, "[UE %d] ue_procedures.c: FATAL, Illegal preambleFormat %d, prachConfigIndex %d\n",
mac->ue_id,
prach_format,
prachConfigIndex);
} }
} else { } else {
// SCS configuration from msg1_SubcarrierSpacing and table 4.2-1 in TS 38.211
AssertFatal(nr_rach_ConfigCommon->msg1_SubcarrierSpacing, "msg1_SubcarrierSpacing required but missing\n");
NR_SubcarrierSpacing_t scs = *nr_rach_ConfigCommon->msg1_SubcarrierSpacing;
AssertFatal(scs >= NR_SubcarrierSpacing_kHz15 && scs <= NR_SubcarrierSpacing_spare1, "Unknown msg1_SubcarrierSpacing %lu\n", scs);
const unsigned int mu = scs;
switch (prach_format) { // short preamble formats switch (prach_format) { // short preamble formats
case 0: case 0:
case 3: case 3:
......
...@@ -1849,7 +1849,8 @@ static void build_ro_list(NR_UE_MAC_INST_t *mac) ...@@ -1849,7 +1849,8 @@ static void build_ro_list(NR_UE_MAC_INST_t *mac)
int unpaired = mac->phy_config.config_req.cell_config.frame_duplex_type; 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 int64_t *prach_config_info_p = get_prach_config_info(mac->frequency_range, config_index, unpaired);
int mu = nr_get_prach_mu(mac->current_UL_BWP->msgA_ConfigCommon_r16, setup); 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 // 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); LOG_D(NR_MAC,"mu = %u, PRACH config index = %u, unpaired = %u\n", mu, config_index, unpaired);
...@@ -1891,7 +1892,7 @@ static void build_ro_list(NR_UE_MAC_INST_t *mac) ...@@ -1891,7 +1892,7 @@ static void build_ro_list(NR_UE_MAC_INST_t *mac)
format = ((uint8_t) prach_config_info_p[0]) | (format2<<8); format = ((uint8_t) prach_config_info_p[0]) | (format2<<8);
slot_shift_for_map = mu; slot_shift_for_map = mu;
if ( (mu == 1) && (prach_config_info_p[6] <= 1) ) if ( (mu == 1) && (prach_config_info_p[6] == 1) && ((format & 0xff) > 3) )
// no prach in even slots @ 30kHz for 1 prach per subframe // no prach in even slots @ 30kHz for 1 prach per subframe
even_slot_invalid = true; even_slot_invalid = true;
else else
...@@ -2955,10 +2956,16 @@ static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, sub_fra ...@@ -2955,10 +2956,16 @@ static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, sub_fra
nr_get_prach_resources(mac, 0, 0, &ra->prach_resources, ra->rach_ConfigDedicated); 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.ra_PreambleIndex = ra->ra_PreambleIndex;
pdu->prach_config_pdu.prach_tx_power = get_prach_tx_power(mac); pdu->prach_config_pdu.prach_tx_power = get_prach_tx_power(mac);
mac->ra.ra_rnti = nr_get_ra_rnti(pdu->prach_config_pdu.prach_start_symbol, unsigned int slot_RA;
pdu->prach_config_pdu.prach_slot, // 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
pdu->prach_config_pdu.num_ra, // so mu = 0 for prach format < 4.
0); 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); release_ul_config(pdu, false);
nr_scheduled_response_t scheduled_response = {.ul_config = mac->ul_config_request + slotP, nr_scheduled_response_t scheduled_response = {.ul_config = mac->ul_config_request + slotP,
.mac = mac, .mac = mac,
...@@ -3006,7 +3013,7 @@ static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, sub_fra ...@@ -3006,7 +3013,7 @@ static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, sub_fra
// Compute MsgB RNTI // Compute MsgB RNTI
ra->MsgB_rnti = ra->MsgB_rnti =
nr_get_MsgB_rnti(prach_occasion_info_p->start_symbol, prach_occasion_info_p->slot, prach_occasion_info_p->fdm, 0); 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]); LOG_D(NR_MAC, "ra->ra_state %s\n", nrra_ue_text[ra->ra_state]);
ra->ra_state = nrRA_WAIT_MSGB; ra->ra_state = nrRA_WAIT_MSGB;
ra->t_crnti = 0; ra->t_crnti = 0;
......
...@@ -475,7 +475,8 @@ static void config_common(gNB_MAC_INST *nrmac, ...@@ -475,7 +475,8 @@ static void config_common(gNB_MAC_INST *nrmac,
} }
} }
frame_type_t frame_type = get_frame_type(*frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing); NR_FreqBandIndicatorNR_t band = *frequencyInfoDL->frequencyBandList.list.array[0];
frame_type_t frame_type = get_frame_type(band, *scc->ssbSubcarrierSpacing);
nrmac->common_channels[0].frame_type = frame_type; nrmac->common_channels[0].frame_type = frame_type;
// Cell configuration // Cell configuration
...@@ -511,18 +512,26 @@ static void config_common(gNB_MAC_INST *nrmac, ...@@ -511,18 +512,26 @@ static void config_common(gNB_MAC_INST *nrmac,
cfg->prach_config.prach_sequence_length.tl.tag = NFAPI_NR_CONFIG_PRACH_SEQUENCE_LENGTH_TAG; cfg->prach_config.prach_sequence_length.tl.tag = NFAPI_NR_CONFIG_PRACH_SEQUENCE_LENGTH_TAG;
cfg->num_tlv++; cfg->num_tlv++;
cfg->prach_config.prach_ConfigurationIndex.value = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex;
cfg->prach_config.prach_ConfigurationIndex.tl.tag = NFAPI_NR_CONFIG_PRACH_CONFIG_INDEX_TAG;
cfg->num_tlv++;
if (rach_ConfigCommon->msg1_SubcarrierSpacing) if (rach_ConfigCommon->msg1_SubcarrierSpacing)
cfg->prach_config.prach_sub_c_spacing.value = *rach_ConfigCommon->msg1_SubcarrierSpacing; cfg->prach_config.prach_sub_c_spacing.value = *rach_ConfigCommon->msg1_SubcarrierSpacing;
else else {
cfg->prach_config.prach_sub_c_spacing.value = frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing; // 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];
cfg->prach_config.prach_sub_c_spacing.value = get_delta_f_RA_long(format);
}
cfg->prach_config.prach_sub_c_spacing.tl.tag = NFAPI_NR_CONFIG_PRACH_SUB_C_SPACING_TAG; cfg->prach_config.prach_sub_c_spacing.tl.tag = NFAPI_NR_CONFIG_PRACH_SUB_C_SPACING_TAG;
cfg->num_tlv++; cfg->num_tlv++;
cfg->prach_config.restricted_set_config.value = rach_ConfigCommon->restrictedSetConfig; cfg->prach_config.restricted_set_config.value = rach_ConfigCommon->restrictedSetConfig;
cfg->prach_config.restricted_set_config.tl.tag = NFAPI_NR_CONFIG_RESTRICTED_SET_CONFIG_TAG; cfg->prach_config.restricted_set_config.tl.tag = NFAPI_NR_CONFIG_RESTRICTED_SET_CONFIG_TAG;
cfg->num_tlv++; cfg->num_tlv++;
cfg->prach_config.prach_ConfigurationIndex.value = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex;
cfg->prach_config.prach_ConfigurationIndex.tl.tag = NFAPI_NR_CONFIG_PRACH_CONFIG_INDEX_TAG;
cfg->num_tlv++;
switch (rach_ConfigCommon->rach_ConfigGeneric.msg1_FDM) { switch (rach_ConfigCommon->rach_ConfigGeneric.msg1_FDM) {
case 0: case 0:
...@@ -543,10 +552,6 @@ static void config_common(gNB_MAC_INST *nrmac, ...@@ -543,10 +552,6 @@ static void config_common(gNB_MAC_INST *nrmac,
cfg->prach_config.num_prach_fd_occasions.tl.tag = NFAPI_NR_CONFIG_NUM_PRACH_FD_OCCASIONS_TAG; cfg->prach_config.num_prach_fd_occasions.tl.tag = NFAPI_NR_CONFIG_NUM_PRACH_FD_OCCASIONS_TAG;
cfg->num_tlv++; cfg->num_tlv++;
cfg->prach_config.prach_ConfigurationIndex.value = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex;
cfg->prach_config.prach_ConfigurationIndex.tl.tag = NFAPI_NR_CONFIG_PRACH_CONFIG_INDEX_TAG;
cfg->num_tlv++;
cfg->prach_config.num_prach_fd_occasions_list = (nfapi_nr_num_prach_fd_occasions_t *)malloc( cfg->prach_config.num_prach_fd_occasions_list = (nfapi_nr_num_prach_fd_occasions_t *)malloc(
cfg->prach_config.num_prach_fd_occasions.value * sizeof(nfapi_nr_num_prach_fd_occasions_t)); cfg->prach_config.num_prach_fd_occasions.value * sizeof(nfapi_nr_num_prach_fd_occasions_t));
for (int i = 0; i < cfg->prach_config.num_prach_fd_occasions.value; i++) { for (int i = 0; i < cfg->prach_config.num_prach_fd_occasions.value; i++) {
...@@ -588,6 +593,14 @@ static void config_common(gNB_MAC_INST *nrmac, ...@@ -588,6 +593,14 @@ static void config_common(gNB_MAC_INST *nrmac,
cfg->prach_config.ssb_per_rach.tl.tag = NFAPI_NR_CONFIG_SSB_PER_RACH_TAG; cfg->prach_config.ssb_per_rach.tl.tag = NFAPI_NR_CONFIG_SSB_PER_RACH_TAG;
cfg->num_tlv++; cfg->num_tlv++;
// compute and store prach duration in slots from rach_ConfigCommon
NR_RACH_ConfigGeneric_t *rachConfig =
&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric;
NR_COMMON_channels_t *cc = nrmac->common_channels;
const uint32_t pointA = scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA;
const int prach_fmt = (get_nr_prach_format_from_index(rachConfig->prach_ConfigurationIndex, pointA, cc->frame_type) & 0xff);
cc->prach_len = (prach_fmt < 4) ? get_long_prach_dur(prach_fmt, *scc->ssbSubcarrierSpacing) : 1;
// SSB Table Configuration // SSB Table Configuration
cfg->ssb_table.ssb_offset_point_a.value = cfg->ssb_table.ssb_offset_point_a.value =
......
...@@ -223,11 +223,11 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, sub_frame_ ...@@ -223,11 +223,11 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, sub_frame_
if (get_softmodem_params()->phy_test == 0) { if (get_softmodem_params()->phy_test == 0) {
/* we need to make sure that resources for PRACH are free. To avoid that /* we need to make sure that resources for PRACH are free. To avoid that
e.g. PUSCH has already been scheduled, make sure we schedule before e.g. PUSCH has already been scheduled, make sure we schedule before
anything else: below, we simply assume an advance one frame (minus one anything else: below, we simply assume an advance one frame (minus
slot, because otherwise we would allocate the current slot in prach duration, because otherwise we would allocate the current slot in
UL_tti_req_ahead), but be aware that, e.g., K2 is allowed to be larger UL_tti_req_ahead), but be aware that, e.g., K2 is allowed to be larger
(schedule_nr_prach will assert if resources are not free). */ (schedule_nr_prach will assert if resources are not free). */
const sub_frame_t n_slots_ahead = slots_frame - 1 + get_NTN_Koffset(scc); const int n_slots_ahead = slots_frame - cc->prach_len + get_NTN_Koffset(scc);
const frame_t f = (frame + (slot + n_slots_ahead) / slots_frame) % 1024; const frame_t f = (frame + (slot + n_slots_ahead) / slots_frame) % 1024;
const sub_frame_t s = (slot + n_slots_ahead) % slots_frame; const sub_frame_t s = (slot + n_slots_ahead) % slots_frame;
schedule_nr_prach(module_idP, f, s); schedule_nr_prach(module_idP, f, s);
......
...@@ -92,7 +92,8 @@ static int16_t ssb_index_from_prach(module_id_t module_idP, ...@@ -92,7 +92,8 @@ static int16_t ssb_index_from_prach(module_id_t module_idP,
NR_MsgA_ConfigCommon_r16_t *msgacc = NULL; NR_MsgA_ConfigCommon_r16_t *msgacc = NULL;
if (scc->uplinkConfigCommon->initialUplinkBWP->ext1 && scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16) if (scc->uplinkConfigCommon->initialUplinkBWP->ext1 && scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16)
msgacc = scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup; msgacc = scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup;
int mu = nr_get_prach_mu(msgacc, rach_ConfigCommon); 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);
get_nr_prach_info_from_index(config_index, get_nr_prach_info_from_index(config_index,
(int)frameP, (int)frameP,
...@@ -199,7 +200,8 @@ void find_SSB_and_RO_available(gNB_MAC_INST *nrmac) ...@@ -199,7 +200,8 @@ void find_SSB_and_RO_available(gNB_MAC_INST *nrmac)
NR_MsgA_ConfigCommon_r16_t *msgacc = NULL; NR_MsgA_ConfigCommon_r16_t *msgacc = NULL;
if (scc->uplinkConfigCommon->initialUplinkBWP->ext1 && scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16) if (scc->uplinkConfigCommon->initialUplinkBWP->ext1 && scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16)
msgacc = scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup; msgacc = scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup;
int mu = nr_get_prach_mu(msgacc, rach_ConfigCommon); 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 // 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, get_nr_prach_occasion_info_from_index(config_index,
...@@ -354,6 +356,27 @@ static void schedule_nr_MsgA_pusch(NR_UplinkConfigCommon_t *uplinkConfigCommon, ...@@ -354,6 +356,27 @@ static void schedule_nr_MsgA_pusch(NR_UplinkConfigCommon_t *uplinkConfigCommon,
UL_tti_req->n_pdus += 1; UL_tti_req->n_pdus += 1;
} }
static void fill_vrb(const frame_t frame,
const sub_frame_t slot,
int nb_rb,
int beam_idx,
int vrb_size,
int slots_frame,
int rb_start,
int start_symb,
int num_symb,
NR_COMMON_channels_t *cc)
{
const int index = ul_buffer_index(frame, slot, slots_frame, vrb_size);
uint16_t *vrb_map_UL = &cc->vrb_map_UL[beam_idx][index * MAX_BWP_SIZE];
for (int i = 0; i < nb_rb; ++i) {
AssertFatal(
!(vrb_map_UL[rb_start + i] & SL_to_bitmap(start_symb, num_symb)),
"PRACH resources are already occupied!\n");
vrb_map_UL[rb_start + i] |= SL_to_bitmap(start_symb, num_symb);
}
}
void schedule_nr_prach(module_id_t module_idP, frame_t frameP, sub_frame_t slotP) void schedule_nr_prach(module_id_t module_idP, frame_t frameP, sub_frame_t slotP)
{ {
gNB_MAC_INST *gNB = RC.nrmac[module_idP]; gNB_MAC_INST *gNB = RC.nrmac[module_idP];
...@@ -366,7 +389,6 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, sub_frame_t slotP ...@@ -366,7 +389,6 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, sub_frame_t slotP
NR_MsgA_ConfigCommon_r16_t *msgacc = NULL; NR_MsgA_ConfigCommon_r16_t *msgacc = NULL;
if (scc->uplinkConfigCommon->initialUplinkBWP->ext1 && scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16) if (scc->uplinkConfigCommon->initialUplinkBWP->ext1 && scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16)
msgacc = scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup; msgacc = scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup;
int mu = nr_get_prach_mu(msgacc, rach_ConfigCommon);
int slots_frame = gNB->frame_structure.numb_slots_frame; int slots_frame = gNB->frame_structure.numb_slots_frame;
int index = ul_buffer_index(frameP, slotP, slots_frame, gNB->UL_tti_req_ahead_size); int index = ul_buffer_index(frameP, slotP, slots_frame, gNB->UL_tti_req_ahead_size);
nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[module_idP]->UL_tti_req_ahead[0][index]; nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[module_idP]->UL_tti_req_ahead[0][index];
...@@ -385,6 +407,8 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, sub_frame_t slotP ...@@ -385,6 +407,8 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, sub_frame_t slotP
int bwp_start = NRRIV2PRBOFFSET(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); int bwp_start = NRRIV2PRBOFFSET(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE);
uint8_t fdm = cfg->prach_config.num_prach_fd_occasions.value; uint8_t fdm = cfg->prach_config.num_prach_fd_occasions.value;
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 // 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, if (get_nr_prach_info_from_index(config_index,
(int)frameP, (int)frameP,
...@@ -554,13 +578,29 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, sub_frame_t slotP ...@@ -554,13 +578,29 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, sub_frame_t slotP
// block resources in vrb_map_UL // block resources in vrb_map_UL
const int mu_pusch = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing; const int mu_pusch = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing;
const int16_t n_ra_rb = get_N_RA_RB(cfg->prach_config.prach_sub_c_spacing.value, mu_pusch); const int16_t n_ra_rb = get_N_RA_RB(cfg->prach_config.prach_sub_c_spacing.value, mu_pusch);
index = ul_buffer_index(frameP, slotP, slots_frame, gNB->vrb_map_UL_size); // mark PRBs as occupied for current and future slots if prach extends beyond current slot
uint16_t *vrb_map_UL = &cc->vrb_map_UL[beam.idx][index * MAX_BWP_SIZE]; int total_prach_slots;
for (int i = 0; i < n_ra_rb * fdm; ++i) { if (format0 < 4) {
AssertFatal( N_dur = 14; // number of PRACH symbols in PRACH slot
!(vrb_map_UL[bwp_start + rach_ConfigGeneric->msg1_FrequencyStart + i] & SL_to_bitmap(start_symbol, N_t_slot * N_dur)), total_prach_slots = get_long_prach_dur(format0, mu_pusch);
"PRACH resources are already occupied!\n"); AssertFatal(slotP + total_prach_slots - 1 < slots_frame, "PRACH cannot extend across frames\n");
vrb_map_UL[bwp_start + rach_ConfigGeneric->msg1_FrequencyStart + i] |= SL_to_bitmap(start_symbol, N_t_slot * N_dur); } 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.
for (int i = 0; i < total_prach_slots; i++) {
fill_vrb(frameP,
slotP + i,
n_ra_rb * fdm,
beam.idx,
gNB->vrb_map_UL_size,
slots_frame,
bwp_start + rach_ConfigGeneric->msg1_FrequencyStart,
start_symbol,
N_t_slot * N_dur,
cc);
} }
} }
} }
...@@ -721,17 +761,37 @@ void nr_initiate_ra_proc(module_id_t module_idP, ...@@ -721,17 +761,37 @@ void nr_initiate_ra_proc(module_id_t module_idP,
ra->preamble_index = preamble_index; ra->preamble_index = preamble_index;
ra->timing_offset = timing_offset; ra->timing_offset = timing_offset;
ra->msg3_TPC = nr_get_msg3_tpc(preamble_power); ra->msg3_TPC = nr_get_msg3_tpc(preamble_power);
uint8_t ul_carrier_id = 0; // 0 for NUL 1 for SUL
ra->RA_rnti = nr_get_ra_rnti(symbol, slotP, freq_index, ul_carrier_id);
NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
if (scc->uplinkConfigCommon->initialUplinkBWP->ext1 && scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16) { {
ra->ra_type = RA_2_STEP; // 3GPP TS 38.321 Section 5.1.3(a) says t_id for RA-RNTI depends on mu as specified in clause 5.3.2 in TS 38.211
ra->ra_state = nrRA_WAIT_MsgA_PUSCH; // so mu = 0 for prach format < 4.
ra->MsgB_rnti = nr_get_MsgB_rnti(symbol, slotP, freq_index, ul_carrier_id); NR_RACH_ConfigCommon_t *rach_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup;
} else { NR_MsgA_ConfigCommon_r16_t *msgacc = NULL;
ra->ra_type = RA_4_STEP; if (scc->uplinkConfigCommon->initialUplinkBWP->ext1 && scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16)
ra->ra_state = nrRA_Msg2; 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);
uint8_t index = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex;
uint16_t prach_format =
get_nr_prach_format_from_index(index, scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA, cc->frame_type);
unsigned int slot_RA;
if ((prach_format & 0xff) < 4) {
unsigned int slots_per_sf = (1 << mu);
slot_RA = slotP / slots_per_sf;
} else {
slot_RA = slotP;
}
uint8_t ul_carrier_id = 0; // 0 for NUL 1 for SUL
ra->RA_rnti = nr_get_ra_rnti(symbol, slot_RA, freq_index, ul_carrier_id);
if (scc->uplinkConfigCommon->initialUplinkBWP->ext1 && scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16) {
ra->ra_type = RA_2_STEP;
ra->ra_state = nrRA_WAIT_MsgA_PUSCH;
ra->MsgB_rnti = nr_get_MsgB_rnti(symbol, slot_RA, freq_index, ul_carrier_id);
} else {
ra->ra_type = RA_4_STEP;
ra->ra_state = nrRA_Msg2;
}
} }
int index = ra - cc->ra; int index = ra - cc->ra;
......
...@@ -301,6 +301,8 @@ typedef struct { ...@@ -301,6 +301,8 @@ typedef struct {
uint8_t ssb_index[MAX_NUM_OF_SSB]; uint8_t ssb_index[MAX_NUM_OF_SSB];
//CB preambles for each SSB //CB preambles for each SSB
int cb_preambles_per_ssb; int cb_preambles_per_ssb;
/// Max prach length in slots
int prach_len;
} NR_COMMON_channels_t; } NR_COMMON_channels_t;
// SP ZP CSI-RS Resource Set Activation/Deactivation MAC CE // SP ZP CSI-RS Resource Set Activation/Deactivation MAC CE
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment