From 7157d4bcd185ee9b64f940a2adb74f2ab2e52e85 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Fri, 19 Sep 2025 11:51:29 +0200 Subject: [PATCH 01/23] add trace when the main NR UE thread ends and when NR UE sets oai_exit variable --- executables/nr-ue.c | 2 +- executables/nr-uesoftmodem.c | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index e7132e15cf..5721b45f8d 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -1091,7 +1091,7 @@ void *UE_thread(void *arg) stream_status = STREAM_STATUS_SYNCED; tx_wait_for_dlsch[slot] = 0; } - + LOG_W(NR_PHY, "UE main thread is ending\n"); return NULL; } diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index fbac6402f5..ca6c48dbef 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -139,10 +139,7 @@ int create_tasks_nrue(uint32_t ue_nb) { void exit_function(const char *file, const char *function, const int line, const char *s, const int assert) { int CC_id; - - if (s != NULL) { - printf("%s:%d %s() Exiting OAI softmodem: %s\n",file,line, function, s); - } + LOG_W(NR_PHY, "called by: %s:%d %s() Exiting OAI softmodem: %s\n", file, line, function, s ? s : "no msg"); oai_exit = 1; @@ -496,9 +493,8 @@ int main(int argc, char **argv) printf("Entering ITTI signals handler\n"); printf("TYPE TO TERMINATE\n"); itti_wait_tasks_end(trigger_deregistration); - printf("Returned from ITTI signal handler\n"); - oai_exit=1; - printf("oai_exit=%d\n",oai_exit); + LOG_W(NR_PHY, "Returned from ITTI signal handler\n"); + oai_exit = 1; if (ouput_vcd) vcd_signal_dumper_close(); From e54738c7e4567c27c41a7b0cbb4ef1f70d95cebc Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Tue, 19 Aug 2025 12:12:52 +0200 Subject: [PATCH 02/23] flush command line printf, it is called before log module initialisation --- common/config/config_load_configmodule.c | 1 + 1 file changed, 1 insertion(+) diff --git a/common/config/config_load_configmodule.c b/common/config/config_load_configmodule.c index cfe05042ce..f5dfe6137f 100644 --- a/common/config/config_load_configmodule.c +++ b/common/config/config_load_configmodule.c @@ -240,6 +240,7 @@ configmodule_interface_t *load_configmodule(int argc, for (int i=0; i Date: Thu, 14 Aug 2025 12:16:20 +0200 Subject: [PATCH 03/23] Remove prach_ifft from premanent allocation Allocate on the stack when necessary. --- openair1/PHY/INIT/nr_init.c | 7 +- openair1/PHY/NR_TRANSPORT/nr_prach.c | 220 +++++++++++---------------- openair1/PHY/defs_gNB.h | 2 - 3 files changed, 87 insertions(+), 142 deletions(-) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 778903be91..23334c8626 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -190,8 +190,7 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB) common_vars->debugBuff_sample_offset = 0; // PRACH - prach_vars->rxsigF = (int16_t **)malloc16_clear(Prx*sizeof(int16_t*)); - prach_vars->prach_ifft = (int32_t *)malloc16_clear(1024*2*sizeof(int32_t)); + prach_vars->rxsigF = (int16_t **)malloc16_clear(Prx * sizeof(int16_t *)); init_prach_list(gNB); @@ -266,10 +265,6 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB) free_and_zero(common_vars->debugBuff); - NR_gNB_PRACH* prach_vars = &gNB->prach_vars; - free_and_zero(prach_vars->rxsigF); - free_and_zero(prach_vars->prach_ifft); - for (int ULSCH_id = 0; ULSCH_id < gNB->max_nb_pusch; ULSCH_id++) { NR_gNB_PUSCH *pusch_vars = &gNB->pusch_vars[ULSCH_id]; for (int i = 0; i < n_buf; i++) { diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 76d9b1185f..f278d4c845 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -452,81 +452,67 @@ void rx_nr_prach(PHY_VARS_gNB *gNB, { AssertFatal(gNB != NULL, "Can only be called from gNB\n"); nfapi_nr_prach_config_t *cfg = &gNB->gNB_config.prach_config; - NR_DL_FRAME_PARMS *fp; + c16_t **rxsigF = (c16_t **)gNB->prach_vars.rxsigF; + uint16_t preamble_index0 = 0; + uint16_t numshift = 0; + int first_nonzero_root_idx = 0; + bool new_dft = false; + int log2_ifft_size = 10; - uint16_t rootSequenceIndex; - int numrootSequenceIndex; - uint8_t restricted_set; - uint8_t n_ra_prb=0xFF; - int nb_rx; + NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; - int16_t **rxsigF = gNB->prach_vars.rxsigF; + const int nb_rx = gNB->gNB_config.carrier_config.num_rx_ant.value; + const int rootSequenceIndex = cfg->num_prach_fd_occasions_list[prach_pdu->num_ra].prach_root_sequence_index.value; + const int numrootSequenceIndex = cfg->num_prach_fd_occasions_list[prach_pdu->num_ra].num_root_sequences.value; + const int NCS = prach_pdu->num_cs; // cfg->num_prach_fd_occasions_list[0].prach_zero_corr_conf.value; + const int prach_sequence_length = cfg->prach_sequence_length.value; + const int msg1_frequencystart = cfg->num_prach_fd_occasions_list[prach_pdu->num_ra].k1.value; + const int restricted_set = cfg->restricted_set_config.value; + const int prach_fmt = prach_pdu->prach_format; + const int N_ZC = prach_sequence_length == 0 ? 839 : 139; - uint8_t preamble_index; - uint16_t NCS=99,NCS2; - uint16_t preamble_offset=0,preamble_offset_old; - int16_t preamble_shift=0; - uint32_t preamble_shift2; - uint16_t preamble_index0=0,n_shift_ra=0,n_shift_ra_bar; - uint16_t d_start=0; - uint16_t numshift=0; - const uint16_t *prach_root_sequence_map; - uint8_t not_found; - uint16_t u; - int16_t *Xu=0; - uint16_t first_nonzero_root_idx=0; - uint8_t new_dft=0; - int32_t lev; - int16_t levdB; - int log2_ifft_size=10; - int16_t prach_ifft_tmp[2048*2] __attribute__((aligned(32))); - int32_t *prach_ifft=(int32_t*)NULL; - - fp = &gNB->frame_parms; + LOG_D(PHY, + "L1 PRACH RX: rooSequenceIndex %d, numRootSeqeuences %d, NCS %d, N_ZC %d, format %d \n", + rootSequenceIndex, + numrootSequenceIndex, + NCS, + N_ZC, + prach_fmt); - nb_rx = gNB->gNB_config.carrier_config.num_rx_ant.value; - rootSequenceIndex = cfg->num_prach_fd_occasions_list[prach_pdu->num_ra].prach_root_sequence_index.value; - numrootSequenceIndex = cfg->num_prach_fd_occasions_list[prach_pdu->num_ra].num_root_sequences.value; - NCS = prach_pdu->num_cs;//cfg->num_prach_fd_occasions_list[0].prach_zero_corr_conf.value; - int prach_sequence_length = cfg->prach_sequence_length.value; - int msg1_frequencystart = cfg->num_prach_fd_occasions_list[prach_pdu->num_ra].k1.value; - // int num_unused_root_sequences = cfg->num_prach_fd_occasions_list[0].num_unused_root_sequences.value; - // cfg->num_prach_fd_occasions_list[0].unused_root_sequences_list - - restricted_set = cfg->restricted_set_config.value; - - uint8_t prach_fmt = prach_pdu->prach_format; - uint16_t N_ZC = (prach_sequence_length==0)?839:139; - - LOG_D(PHY,"L1 PRACH RX: rooSequenceIndex %d, numRootSeqeuences %d, NCS %d, N_ZC %d, format %d \n",rootSequenceIndex,numrootSequenceIndex,NCS,N_ZC,prach_fmt); - - prach_ifft = gNB->prach_vars.prach_ifft; if (LOG_DEBUGFLAG(DEBUG_PRACH)) { - if ((frame&1023) < 20) LOG_D(PHY,"PRACH (gNB) : running rx_prach for slot %d, msg1_frequencystart %d, rootSequenceIndex %d\n", slot, msg1_frequencystart, rootSequenceIndex); + if ((frame & 1023) < 20) + LOG_D(PHY, + "PRACH (gNB) : running rx_prach for slot %d, msg1_frequencystart %d, rootSequenceIndex %d\n", + slot, + msg1_frequencystart, + rootSequenceIndex); } start_meas(&gNB->rx_prach); - prach_root_sequence_map = (cfg->prach_sequence_length.value==0) ? prach_root_sequence_map_0_3 : prach_root_sequence_map_abc; + const uint16_t *prach_root_sequence_map = + cfg->prach_sequence_length.value == 0 ? prach_root_sequence_map_0_3 : prach_root_sequence_map_abc; // PDP is oversampled, e.g. 1024 sample instead of 839 // Adapt the NCS (zero-correlation zones) with oversampling factor e.g. 1024/839 - NCS2 = (N_ZC==839) ? ((NCS<<10)/839) : ((NCS<<8)/139); + int NCS2 = N_ZC == 839 ? (NCS << 10) / 839 : (NCS << 8) / 139; - if (NCS2==0) NCS2 = N_ZC; + if (NCS2 == 0) + NCS2 = N_ZC; + int preamble_offset = 0, preamble_offset_old = 99; - preamble_offset_old = 99; - - *max_preamble_energy = 0; *max_preamble_delay = 0; *max_preamble = 0; - int16_t prachF[2 * 1024]; - for (preamble_index=0 ; preamble_index<64 ; preamble_index++) { + int16_t preamble_shift = 0; + const int dft_sz = N_ZC == 839 ? 1024 : 256; + int32_t prach_ifft[dft_sz] __attribute__((aligned(32))); + for (int preamble_index = 0; preamble_index < 64; preamble_index++) { if (LOG_DEBUGFLAG(DEBUG_PRACH)) { - int en = dB_fixed(signal_energy((int32_t*)&rxsigF[0][0],(N_ZC==839) ? 840: 140)); - if (en>60) LOG_D(PHY,"frame %d, slot %d : Trying preamble %d \n",frame,slot,preamble_index); + int en = dB_fixed(signal_energy((int32_t *)rxsigF[0], N_ZC == 839 ? 840 : 140)); + if (en > 60) + LOG_D(PHY, "frame %d, slot %d : Trying preamble %d \n", frame, slot, preamble_index); } if (restricted_set == 0) { // This is the relative offset in the root sequence table (5.7.2-4 from 36.211) for the given preamble index @@ -534,48 +520,43 @@ void rx_nr_prach(PHY_VARS_gNB *gNB, if (preamble_offset != preamble_offset_old) { preamble_offset_old = preamble_offset; - new_dft = 1; + new_dft = true; // This is the \nu corresponding to the preamble index preamble_shift = 0; - } - - else { - preamble_shift -= NCS; + } else { + preamble_shift -= NCS; if (preamble_shift < 0) - preamble_shift+=N_ZC; + preamble_shift += N_ZC; } } else { // This is the high-speed case - new_dft = 0; + new_dft = false; 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 // preamble index and find the corresponding cyclic shift // Check if all shifts for that root have been processed + int n_shift_ra = 0, n_shift_ra_bar, d_start = 0; if (preamble_index0 == numshift) { - not_found = 1; - new_dft = 1; + bool not_found = true; + new_dft = true; preamble_index0 -= numshift; - //(preamble_offset==0 && numshift==0) ? (preamble_offset) : (preamble_offset++); - - while (not_found == 1) { + while (not_found) { // current root depending on rootSequenceIndex int index = (rootSequenceIndex + preamble_offset) % N_ZC; - - u = prach_root_sequence_map[index]; - + int u = nr_du[prach_root_sequence_map[index]]; uint16_t n_group_ra = 0; - - if ((nr_du[u] < (N_ZC / 3)) && (nr_du[u] >= NCS) ) { - n_shift_ra = nr_du[u] / NCS; - d_start = (nr_du[u] << 1) + (n_shift_ra * NCS); + + if (u < (N_ZC / 3) && u >= NCS) { + n_shift_ra = u / NCS; + d_start = (u << 1) + (n_shift_ra * NCS); n_group_ra = N_ZC / d_start; - n_shift_ra_bar = max(0, (N_ZC-(nr_du[u] << 1) - (n_group_ra * d_start)) / N_ZC); - } else if ((nr_du[u] >= (N_ZC / 3)) && (nr_du[u] <= ((N_ZC - NCS) >> 1))) { - n_shift_ra = (N_ZC - (nr_du[u] << 1)) / NCS; - d_start = N_ZC - (nr_du[u] << 1) + (n_shift_ra * NCS); - n_group_ra = nr_du[u] / d_start; - n_shift_ra_bar = min(n_shift_ra, max(0, (nr_du[u]- (n_group_ra * d_start)) / NCS)); + n_shift_ra_bar = max(0, (N_ZC - (u << 1) - (n_group_ra * d_start)) / N_ZC); + } else if (u >= (N_ZC / 3) && u <= ((N_ZC - NCS) >> 1)) { + n_shift_ra = (N_ZC - (u << 1)) / NCS; + d_start = N_ZC - (u << 1) + (n_shift_ra * NCS); + n_group_ra = u / d_start; + n_shift_ra_bar = min(n_shift_ra, max(0, (u - (n_group_ra * d_start)) / NCS)); } else { n_shift_ra = 0; n_shift_ra_bar = 0; @@ -584,12 +565,13 @@ void rx_nr_prach(PHY_VARS_gNB *gNB, // This is the number of cyclic shifts for the current root u numshift = (n_shift_ra * n_group_ra) + n_shift_ra_bar; // skip to next root and recompute parameters if numshift==0 - (numshift>0) ? (not_found = 0) : (preamble_offset++); + numshift > 0 ? not_found = false : preamble_offset++; } } if (n_shift_ra>0) - preamble_shift = -((d_start * (preamble_index0/n_shift_ra)) + ((preamble_index0%n_shift_ra)*NCS)); // minus because the channel is h(t -\tau + Cv) + preamble_shift = -(d_start * (preamble_index0 / n_shift_ra) + + (preamble_index0 % n_shift_ra) * NCS); // minus because the channel is h(t -\tau + Cv) else preamble_shift = 0; @@ -604,7 +586,7 @@ void rx_nr_prach(PHY_VARS_gNB *gNB, // Compute DFT of RX signal (conjugate input, results in conjugate output) for each new rootSequenceIndex if (LOG_DEBUGFLAG(DEBUG_PRACH)) { - int en = dB_fixed(signal_energy((int32_t*)&rxsigF[0][0],840)); + int en = dB_fixed(signal_energy((int32_t *)rxsigF[0], 840)); if (en>60) LOG_D(PHY, "frame %d, slot %d : preamble index %d, NCS %d, N_ZC/NCS %d: offset %d, preamble shift %d , en %d)\n", @@ -620,42 +602,30 @@ void rx_nr_prach(PHY_VARS_gNB *gNB, LOG_D(PHY,"PRACH RX preamble_index %d, preamble_offset %d\n",preamble_index,preamble_offset); + if (new_dft) { + new_dft = false; - if (new_dft == 1) { - new_dft = 0; - - Xu = (int16_t*)gNB->X_u[preamble_offset-first_nonzero_root_idx]; - + c16_t *Xu = (c16_t *)gNB->X_u[preamble_offset - first_nonzero_root_idx]; LOG_D(PHY,"PRACH RX new dft preamble_offset-first_nonzero_root_idx %d\n",preamble_offset-first_nonzero_root_idx); - memset(prach_ifft,0,((N_ZC==839) ? 2048 : 256)*sizeof(int32_t)); - memset(prachF, 0, sizeof(int16_t) * 2 * 1024); + memset(prach_ifft, 0, sizeof(prach_ifft)); if (LOG_DUMPFLAG(DEBUG_PRACH)) { LOG_M("prach_rxF0.m","prach_rxF0",rxsigF[0],N_ZC,1,1); LOG_M("prach_rxF1.m","prach_rxF1",rxsigF[1],6144,1,1); } - + c16_t prachF[dft_sz] __attribute__((aligned(32))); for (int aa = 0; aa < nb_rx; aa++) { - // Do componentwise product with Xu* on each antenna - - for (int offset = 0; offset < (N_ZC << 1); offset += 2) { - prachF[offset] = (int16_t)(((int32_t)Xu[offset]*rxsigF[aa][offset] + (int32_t)Xu[offset+1]*rxsigF[aa][offset+1])>>15); - prachF[offset+1] = (int16_t)(((int32_t)Xu[offset]*rxsigF[aa][offset+1] - (int32_t)Xu[offset+1]*rxsigF[aa][offset])>>15); + // Do componentwise product with Xu* on each antenna + for (int offset = 0; offset < N_ZC; offset++) { + prachF[offset] = c16MulConjShift(Xu[offset], rxsigF[aa][offset], 15); } - + memset(prachF + N_ZC, 0, sizeof(*prachF) * (dft_sz - N_ZC)); // Now do IFFT of size 1024 (N_ZC=839) or 256 (N_ZC=139) - if (N_ZC == 839) { - idft(IDFT_1024, prachF, prach_ifft_tmp, 1); - // compute energy and accumulate over receive antennas - for (int i = 0; i < 1024; i++) - prach_ifft[i] += (int32_t)prach_ifft_tmp[i<<1]*(int32_t)prach_ifft_tmp[i<<1] + (int32_t)prach_ifft_tmp[1+(i<<1)]*(int32_t)prach_ifft_tmp[1+(i<<1)]; - } else { - idft(IDFT_256, prachF, prach_ifft_tmp, 1); - log2_ifft_size = 8; - // compute energy and accumulate over receive antennas and repetitions for BR - for (int i = 0; i < 256; i++) - prach_ifft[i] += (int32_t)prach_ifft_tmp[i<<1]*(int32_t)prach_ifft_tmp[(i<<1)] + (int32_t)prach_ifft_tmp[1+(i<<1)]*(int32_t)prach_ifft_tmp[1+(i<<1)]; - } + c16_t prach_ifft_tmp[dft_sz] __attribute__((aligned(32))); + idft(get_idft(dft_sz), (int16_t *)prachF, (int16_t *)prach_ifft_tmp, 1); + // compute energy and accumulate over receive antennas + for (int i = 0; i < dft_sz; i++) + prach_ifft[i] += squaredMod(prach_ifft_tmp[i]); if (LOG_DUMPFLAG(DEBUG_PRACH)) { if (aa == 0) @@ -678,14 +648,14 @@ void rx_nr_prach(PHY_VARS_gNB *gNB, } } // new dft - - // check energy in nth time shift, for - preamble_shift2 = ((preamble_shift==0) ? 0 : ((preamble_shift<*max_preamble_energy) { LOG_D(PHY,"preamble_index %d, delay %d en %d dB > %d dB\n",preamble_index,i,levdB,*max_preamble_energy); *max_preamble_energy = levdB; @@ -693,8 +663,7 @@ void rx_nr_prach(PHY_VARS_gNB *gNB, *max_preamble = preamble_index; } } - }// preamble_index - + } // preamble_index // The conversion from *max_preamble_delay from TA value is done here. // It is normalized to the 30.72 Ms/s, considering the numerology, N_RB and the sampling rate @@ -721,23 +690,6 @@ void rx_nr_prach(PHY_VARS_gNB *gNB, } else *TA = *TA/2; - if (LOG_DUMPFLAG(DEBUG_PRACH)) { - //int en = dB_fixed(signal_energy((int32_t*)&rxsigF[0][0],840)); - // if (en>60) { - int k = (12 * n_ra_prb) - 6 * fp->N_RB_UL; - if (k < 0) - k += fp->ofdm_symbol_size; - - k*=12; - k+=13; - k*=2; - - LOG_M("rxsigF.m","prach_rxF", &rxsigF[0][0], 12288, 1, 1); - LOG_M("prach_rxF_comp0.m","prach_rxF_comp0", prachF, 1024, 1, 1); - LOG_M("Xu.m","xu", Xu, N_ZC, 1, 1); - LOG_M("prach_ifft0.m","prach_t0", prach_ifft, 1024, 1, 1); - // } - } stop_meas(&gNB->rx_prach); } diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index ebf459402e..9575e33c7b 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -151,8 +151,6 @@ typedef struct { /// second index: rx antenna [0..63] (hard coded) \note Hard coded array size indexed by \c nb_antennas_rx. /// third index: frequency-domain sample [0..ofdm_symbol_size*12[ int16_t **rxsigF; - /// \brief local buffer to compute prach_ifft - int32_t *prach_ifft; gNB_PRACH_list_t list[NUMBER_OF_NR_PRACH_MAX]; } NR_gNB_PRACH; From f11361343cf6a8e98f0aaa31065ecdcc58d6df28 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Tue, 16 Sep 2025 11:55:57 +0200 Subject: [PATCH 04/23] add management of nb tx antennas=0 in rfsimulator code trace the error of 0 antennas, and avoid infinite loop of calls to read 0 bytes --- radio/rfsimulator/simulator.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/radio/rfsimulator/simulator.c b/radio/rfsimulator/simulator.c index 13a414fed6..94234a755f 100644 --- a/radio/rfsimulator/simulator.c +++ b/radio/rfsimulator/simulator.c @@ -688,6 +688,8 @@ static int rfsimulator_write_internal(rfsimulator_state_t *t, if (b->conn_sock >= 0) { samplesBlockHeader_t header = {nsamps, nbAnt, timestamp}; + if (!nbAnt) + LOG_E(HW, "rfsimulator sending 0 tx antennas\n"); fullwrite(b->conn_sock, &header, sizeof(header), t); if (nbAnt == 1) { fullwrite(b->conn_sock, samplesVoid[0], sampleToByte(nsamps, nbAnt), t); @@ -796,6 +798,8 @@ static void process_recv_header(rfsimulator_state_t *t, buffer_t *b, bool first_ // We have a transmission hole to fill, like TDD // we create no signal samples up to the beginning of this reception int nbAnt = b->th.nbAnt; + if (!nbAnt) + LOG_E(HW, "rfsimulator receive 0 rx antennas\n"); if (b->th.timestamp - b->lastReceivedTS < CirSize) { // case we wrap at circular buffer end for (uint64_t index = b->lastReceivedTS; index < b->th.timestamp; index++) { @@ -822,6 +826,8 @@ static void process_recv_header(rfsimulator_state_t *t, buffer_t *b, bool first_ b->transferPtr = (char *)&b->circularBuf[(b->lastReceivedTS * b->th.nbAnt) % CirSize]; // we now need to read the samples b->remainToTransfer = sampleToByte(b->th.size, b->th.nbAnt); + if (!b->remainToTransfer) + b->headerMode = true; // We got a header with 0 antennas, no I/Q to read return; } From 7d90d9b23e60355ec104ab15a03334549c3d84fb Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Wed, 29 Oct 2025 15:35:04 +0100 Subject: [PATCH 05/23] log: make input parameters const --- common/utils/LOG/log.c | 8 +++++++- common/utils/LOG/log.h | 10 ++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/common/utils/LOG/log.c b/common/utils/LOG/log.c index 1fe2280c15..91c97ac1ac 100644 --- a/common/utils/LOG/log.c +++ b/common/utils/LOG/log.c @@ -145,7 +145,13 @@ static const char *const log_level_highlight_end[] = {LOG_RESET, LOG_RESET, LOG_RESET, LOG_RESET, LOG_RESET, LOG_RESET}; /*!< \brief Optional end-format strings for highlighting */ static void log_output_memory(log_component_t *c, const char *file, const char *func, int line, int comp, int level, const char* format,va_list args); -int write_file_matlab(const char *fname, const char *vname, void *data, int length, int dec, unsigned int format, int multiVec) +int write_file_matlab(const char *fname, + const char *vname, + const void *data, + int length, + int dec, + unsigned int format, + int multiVec) { FILE *fp=NULL; int i; diff --git a/common/utils/LOG/log.h b/common/utils/LOG/log.h index 1f7474253c..a8c7becfdf 100644 --- a/common/utils/LOG/log.h +++ b/common/utils/LOG/log.h @@ -316,8 +316,14 @@ void close_log_mem(void); #define MATLAB_CSHORT_BRACKET1 13 #define MATLAB_CSHORT_BRACKET2 14 #define MATLAB_CSHORT_BRACKET3 15 - -int32_t write_file_matlab(const char *fname, const char *vname, void *data, int length, int dec, unsigned int format, int multiVec); + +int32_t write_file_matlab(const char *fname, + const char *vname, + const void *data, + int length, + int dec, + unsigned int format, + int multiVec); #define write_output(a, b, c, d, e, f) write_file_matlab(a, b, c, d, e, f, 0) /*----------------macro definitions for reading log configuration from the config module */ From a07c03e65f260f2053c52d279de4b364d71d6f16 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Wed, 29 Oct 2025 12:14:31 +0100 Subject: [PATCH 06/23] MAC: use pointers, rewrite FAPI PDU alloc --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 5e9cd47a79..88c9c875ea 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -60,7 +60,7 @@ static int16_t ssb_index_from_prach(module_id_t module_idP, gNB_MAC_INST *gNB = RC.nrmac[module_idP]; NR_COMMON_channels_t *cc = &gNB->common_channels[0]; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - nfapi_nr_config_request_scf_t *cfg = &RC.nrmac[module_idP]->config[0]; + nfapi_nr_config_request_scf_t *cfg = &gNB->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 fdm = cfg->prach_config.num_prach_fd_occasions.value; @@ -351,10 +351,10 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) msgacc = initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup; int slots_frame = gNB->frame_structure.numb_slots_frame; 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_config_request_scf_t *cfg = &RC.nrmac[module_idP]->config[0]; + nfapi_nr_ul_tti_request_t *UL_tti_req = &gNB->UL_tti_req_ahead[0][index]; + nfapi_nr_config_request_scf_t *cfg = &gNB->config[0]; - if (is_ul_slot(slotP, &RC.nrmac[module_idP]->frame_structure)) { + if (is_ul_slot(slotP, &gNB->frame_structure)) { const NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &rach_ConfigCommon->rach_ConfigGeneric; uint8_t config_index = rach_ConfigGeneric->prach_ConfigurationIndex; int slot_index = 0; @@ -390,16 +390,15 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) 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 - AssertFatal(UL_tti_req->n_pdus < sizeof(UL_tti_req->pdus_list) / sizeof(UL_tti_req->pdus_list[0]), - "Invalid UL_tti_req->n_pdus %d\n", - UL_tti_req->n_pdus); - - UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PRACH_PDU_TYPE; - UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_prach_pdu_t); - nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[UL_tti_req->n_pdus].prach_pdu; - memset(prach_pdu, 0, sizeof(nfapi_nr_prach_pdu_t)); + AssertFatal(UL_tti_req->n_pdus < sizeofArray(UL_tti_req->pdus_list), "Invalid UL_tti_req->n_pdus %d\n", UL_tti_req->n_pdus); + nfapi_nr_ul_tti_request_number_of_pdus_t *newpdu = UL_tti_req->pdus_list + UL_tti_req->n_pdus; + *newpdu = (nfapi_nr_ul_tti_request_number_of_pdus_t){ + .pdu_type = NFAPI_NR_UL_CONFIG_PRACH_PDU_TYPE, + .pdu_size = sizeof(nfapi_nr_prach_pdu_t), + }; UL_tti_req->n_pdus += 1; int num_td_occ = 0; + nfapi_nr_prach_pdu_t *prach_pdu = &newpdu->prach_pdu; 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) + @@ -1123,7 +1122,7 @@ static void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, slot_ const uint16_t mask = SL_to_bitmap(ra->msg3_startsymb, ra->msg3_nbSymb); int slots_frame = mac->frame_structure.numb_slots_frame; int buffer_index = ul_buffer_index(ra->Msg3_frame, ra->Msg3_slot, slots_frame, mac->vrb_map_UL_size); - uint16_t *vrb_map_UL = &RC.nrmac[module_idP]->common_channels[CC_id].vrb_map_UL[ra->Msg3_beam.idx][buffer_index * MAX_BWP_SIZE]; + uint16_t *vrb_map_UL = &mac->common_channels[CC_id].vrb_map_UL[ra->Msg3_beam.idx][buffer_index * MAX_BWP_SIZE]; for (int i = 0; i < ra->msg3_nb_rb; ++i) { AssertFatal(!(vrb_map_UL[i + ra->msg3_first_rb + ra->msg3_bwp_start] & mask), "RB %d in %4d.%2d is already taken, cannot allocate Msg3!\n", @@ -1135,7 +1134,7 @@ static void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, slot_ LOG_D(NR_MAC, "UE %04x: %d.%d RA is active, Msg3 in (%d,%d)\n", UE->rnti, frameP, slotP, ra->Msg3_frame, ra->Msg3_slot); buffer_index = ul_buffer_index(ra->Msg3_frame, ra->Msg3_slot, slots_frame, mac->UL_tti_req_ahead_size); - nfapi_nr_ul_tti_request_t *future_ul_tti_req = &RC.nrmac[module_idP]->UL_tti_req_ahead[CC_id][buffer_index]; + nfapi_nr_ul_tti_request_t *future_ul_tti_req = &mac->UL_tti_req_ahead[CC_id][buffer_index]; AssertFatal(future_ul_tti_req->SFN == ra->Msg3_frame && future_ul_tti_req->Slot == ra->Msg3_slot, "future UL_tti_req's frame.slot %d.%d does not match PUSCH %d.%d\n", From f5c1d18638f6cbf850415f2b36b97e77eb9dd0ff Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Thu, 18 Sep 2025 16:20:08 +0200 Subject: [PATCH 07/23] Fix bug in "freeing" prach occasions scheduler after decoding first occasion Release PRACH only after treating the entire PRACH slot/work. Also, release only once, not on every decoding occasion. --- openair1/SCHED_NR/nr_prach_procedures.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair1/SCHED_NR/nr_prach_procedures.c b/openair1/SCHED_NR/nr_prach_procedures.c index c56a37ca1d..7dfe05dccd 100644 --- a/openair1/SCHED_NR/nr_prach_procedures.c +++ b/openair1/SCHED_NR/nr_prach_procedures.c @@ -87,8 +87,6 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac &max_preamble[0], &max_preamble_energy[0], &max_preamble_delay[0]); - LOG_D(NR_PHY,"Freeing PRACH entry %d\n",prach_id); - free_nr_prach_entry(gNB,prach_id); LOG_D(NR_PHY,"[RAPROC] Frame %d, slot %d, occasion %d (prachStartSymbol %d) : Most likely preamble %d, energy %d.%d dB delay %d (prach_energy counter %d)\n", frame,slot,prach_oc,prachStartSymbol, max_preamble[0], @@ -142,6 +140,8 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac gNB->prach_energy_counter++; } //if prach_id>0 rach_ind->slot = prach_start_slot; + LOG_D(NR_PHY,"Freeing PRACH entry %d\n",prach_id); + free_nr_prach_entry(gNB,prach_id); } // for NUMBER_OF_NR_PRACH_OCCASION_MAX VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,0); } From a4d3eb9fadf0abf02102c11a445cec190d7ab80c Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Thu, 14 Aug 2025 10:10:16 +0200 Subject: [PATCH 08/23] replace fix array index by pointers for prach lists in gNB --- executables/nr-ru.c | 9 +- openair1/PHY/NR_TRANSPORT/nr_prach.c | 78 ++++----- .../PHY/NR_TRANSPORT/nr_transport_proto.h | 10 +- openair1/SCHED/nfapi_nr_dummy.c | 16 +- openair1/SCHED_NR/fapi_nr_l1.c | 6 +- openair1/SCHED_NR/nr_prach_procedures.c | 149 +++++++++--------- 6 files changed, 137 insertions(+), 131 deletions(-) diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 20deff5725..bf701f8abc 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -1208,8 +1208,8 @@ void *ru_thread(void *param) proc->tti_rx * gNB->frame_parms.samples_per_slot_wCP); // Do PRACH RU processing - int prach_id = find_nr_prach_ru(ru, proc->frame_rx, proc->tti_rx, SEARCH_EXIST); - if (prach_id >= 0) { + RU_PRACH_list_t *p = find_nr_prach_ru(ru, proc->frame_rx, proc->tti_rx, SEARCH_EXIST); + if (p) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 1 ); T(T_GNB_PHY_PRACH_INPUT_SIGNAL, @@ -1218,12 +1218,11 @@ void *ru_thread(void *param) T_INT(0), 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 - 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; - int beam_id = ru->prach_list[prach_id].beam ? ru->prach_list[prach_id].beam[prach_oc] : 0; + int beam_id = p->beam ? p->beam[prach_oc] : 0; //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, p->fmt, // could also use format @@ -1235,7 +1234,7 @@ void *ru_thread(void *param) proc->frame_rx, proc->tti_rx); } - free_nr_ru_prach_entry(ru,prach_id); + free_nr_ru_prach_entry(ru, p); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 0); } // end if (prach_id >= 0) } // end if (ru->feprx) diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index f278d4c845..12c045e551 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -46,34 +46,38 @@ void init_prach_list(PHY_VARS_gNB *gNB) } } -void free_nr_prach_entry(PHY_VARS_gNB *gNB, int prach_id) +void free_nr_prach_entry(PHY_VARS_gNB *gNB, gNB_PRACH_list_t *p) { - gNB->prach_vars.list[prach_id].frame = -1; - gNB->prach_vars.list[prach_id].slot = -1; - gNB->prach_vars.list[prach_id].num_slots = -1; - free_and_zero(gNB->prach_vars.list[prach_id].beam_nb); + for (uint16_t i = 0; i < NUMBER_OF_NR_PRACH_MAX; i++) { + if (p == gNB->prach_vars.list + i) { + p->frame = -1; + p->slot = -1; + p->num_slots = -1; + free_and_zero(p->beam_nb); + break; + } + } } -int16_t find_nr_prach(PHY_VARS_gNB *gNB,int frame, int slot, find_type_t type) { - +gNB_PRACH_list_t *find_nr_prach(PHY_VARS_gNB *gNB, int frame, int slot, find_type_t type) +{ AssertFatal(gNB!=NULL,"gNB is null\n"); for (uint16_t i=0; iprach_vars.list + i; 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) && (p->frame == -1) && (p->slot == -1)) { - return i; + return p; } else if ((type == SEARCH_EXIST) && (p->frame == frame) && (p->slot + p->num_slots - 1 == slot)) { - return i; + return p; } } - return -1; + return NULL; } -int nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) +gNB_PRACH_list_t *nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) { - int prach_id = find_nr_prach(gNB, SFN, Slot, SEARCH_EXIST_OR_FREE); - AssertFatal(((prach_id >= 0) && (prach_id < NUMBER_OF_NR_PRACH_MAX)), "illegal or no prach_id found!!! prach_id %d\n", prach_id); - gNB_PRACH_list_t *prach = &gNB->prach_vars.list[prach_id]; + gNB_PRACH_list_t *prach = find_nr_prach(gNB, SFN, Slot, SEARCH_EXIST_OR_FREE); + AssertFatal(prach, "prach list full!!!\n"); prach->frame = SFN; prach->slot = Slot; const int format = prach_pdu->prach_format; @@ -94,9 +98,8 @@ int nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *pr bitmap); } } - LOG_D(NR_PHY,"Copying prach pdu %d bytes to index %d\n", (int)sizeof(*prach_pdu), prach_id); - memcpy(&prach->pdu, prach_pdu, sizeof(*prach_pdu)); - return prach_id; + prach->pdu = *prach_pdu; + return prach; } void init_prach_ru_list(RU_t *ru) @@ -110,7 +113,7 @@ void init_prach_ru_list(RU_t *ru) pthread_mutex_init(&ru->prach_list_mutex, NULL); } -int16_t find_nr_prach_ru(RU_t *ru,int frame,int slot, find_type_t type) +RU_PRACH_list_t *find_nr_prach_ru(RU_t *ru, int frame, int slot, find_type_t type) { AssertFatal(ru != NULL, "ru is null\n"); pthread_mutex_lock(&ru->prach_list_mutex); @@ -119,41 +122,44 @@ int16_t find_nr_prach_ru(RU_t *ru,int frame,int slot, find_type_t type) 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) && (p->frame == -1) && (p->slot == -1)) { pthread_mutex_unlock(&ru->prach_list_mutex); - return i; + return p; } else if ((type == SEARCH_EXIST) && (p->frame == frame) && (p->slot + p->num_slots - 1 == slot)) { pthread_mutex_unlock(&ru->prach_list_mutex); - return i; + return p; } } pthread_mutex_unlock(&ru->prach_list_mutex); - return -1; + return NULL; } void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu, int *beam_id) { - int prach_id = find_nr_prach_ru(ru, SFN, Slot, SEARCH_EXIST_OR_FREE); - AssertFatal((prach_id >= 0) && (prach_id < NUMBER_OF_NR_PRACH_MAX), - "illegal or no prach_id found!!! prach_id %d\n", - prach_id); + RU_PRACH_list_t *prach = find_nr_prach_ru(ru, SFN, Slot, SEARCH_EXIST_OR_FREE); + AssertFatal(prach, "ru prach list full\n"); pthread_mutex_lock(&ru->prach_list_mutex); - ru->prach_list[prach_id].frame = SFN; - ru->prach_list[prach_id].slot = Slot; + prach->frame = SFN; + prach->slot = Slot; 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].beam = beam_id; - ru->prach_list[prach_id].prachStartSymbol = prach_pdu->prach_start_symbol; - ru->prach_list[prach_id].num_prach_ocas = prach_pdu->num_prach_ocas; + prach->num_slots = (fmt < 4) ? get_long_prach_dur(fmt, ru->nr_frame_parms->numerology_index) : 1; + prach->fmt = fmt; + prach->numRA = prach_pdu->num_ra; + prach->beam = beam_id; + prach->prachStartSymbol = prach_pdu->prach_start_symbol; + prach->num_prach_ocas = prach_pdu->num_prach_ocas; pthread_mutex_unlock(&ru->prach_list_mutex); } -void free_nr_ru_prach_entry(RU_t *ru, int prach_id) +void free_nr_ru_prach_entry(RU_t *ru, RU_PRACH_list_t *p) { pthread_mutex_lock(&ru->prach_list_mutex); - ru->prach_list[prach_id].frame = -1; - ru->prach_list[prach_id].slot = -1; + for (int i = 0; i < NUMBER_OF_NR_RU_PRACH_MAX; i++) { + if (p == ru->prach_list + i) { + p->frame = -1; + p->slot = -1; + break; + } + } pthread_mutex_unlock(&ru->prach_list_mutex); } diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index a7769dc84d..8547a1415d 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -200,7 +200,7 @@ void nr_fill_ulsch(PHY_VARS_gNB *gNB, int slot, nfapi_nr_pusch_pdu_t *ulsch_pdu); -int nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu); +gNB_PRACH_list_t *nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu); void rx_nr_prach(PHY_VARS_gNB *gNB, nfapi_nr_prach_pdu_t *prach_pdu, @@ -223,8 +223,8 @@ void rx_nr_prach_ru(RU_t *ru, void nr_fill_prach_ru(RU_t *ru,int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu, int *beam_nb); -int16_t find_nr_prach(PHY_VARS_gNB *gNB,int frame,int slot, find_type_t type); -int16_t find_nr_prach_ru(RU_t *ru,int frame,int slot, find_type_t type); +gNB_PRACH_list_t *find_nr_prach(PHY_VARS_gNB *gNB, int frame, int slot, find_type_t type); +RU_PRACH_list_t *find_nr_prach_ru(RU_t *ru, int frame, int slot, find_type_t type); void nr_fill_pucch(PHY_VARS_gNB *gNB, int frame, @@ -247,10 +247,10 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB, void init_prach_list(PHY_VARS_gNB *gNB); void init_prach_ru_list(RU_t *ru); -void free_nr_ru_prach_entry(RU_t *ru, int prach_id); +void free_nr_ru_prach_entry(RU_t *ru, RU_PRACH_list_t *p); int get_nr_prach_duration(uint8_t prach_format); -void free_nr_prach_entry(PHY_VARS_gNB *gNB, int prach_id); +void free_nr_prach_entry(PHY_VARS_gNB *gNB, gNB_PRACH_list_t *); void nr_decode_pucch1(c16_t **rxdataF, pucch_GroupHopping_t pucch_GroupHopping, diff --git a/openair1/SCHED/nfapi_nr_dummy.c b/openair1/SCHED/nfapi_nr_dummy.c index 9c9ecea443..4e4dea190d 100644 --- a/openair1/SCHED/nfapi_nr_dummy.c +++ b/openair1/SCHED/nfapi_nr_dummy.c @@ -37,15 +37,13 @@ void nr_fill_pucch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pucch_pdu_t *pucch_pdu){} -void nr_fill_prach(PHY_VARS_gNB *gNB, - int SFN, - int Slot, - nfapi_nr_prach_pdu_t *prach_pdu){} -void nr_fill_prach_ru(RU_t *ru, - int SFN, - int Slot, - nfapi_nr_prach_pdu_t *prach_pdu){} - +gNB_PRACH_list_t nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) +{ +} +RU_PRACH_list_t nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) +{ +} + void nr_phy_config_request(NR_PHY_Config_t *gNB){} void install_nr_schedule_handlers(NR_IF_Module_t *if_inst){} diff --git a/openair1/SCHED_NR/fapi_nr_l1.c b/openair1/SCHED_NR/fapi_nr_l1.c index 74a2178982..8b88b0195a 100644 --- a/openair1/SCHED_NR/fapi_nr_l1.c +++ b/openair1/SCHED_NR/fapi_nr_l1.c @@ -154,9 +154,9 @@ void nr_schedule_ul_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_tti_request_t *UL_tti UL_tti_req->SFN, UL_tti_req->Slot); nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[i].prach_pdu; - int id = nr_fill_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu); - if (gNB->RU_list[0]->if_south == LOCAL_RF || gNB->RU_list[0]->if_south == REMOTE_IF5) - nr_fill_prach_ru(gNB->RU_list[0], UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu, gNB->prach_vars.list[id].beam_nb); + gNB_PRACH_list_t *prach = nr_fill_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu); + if (prach && (gNB->RU_list[0]->if_south == LOCAL_RF || gNB->RU_list[0]->if_south == REMOTE_IF5)) + nr_fill_prach_ru(gNB->RU_list[0], UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu, prach->beam_nb); break; case NFAPI_NR_UL_CONFIG_SRS_PDU_TYPE: LOG_D(NR_PHY, diff --git a/openair1/SCHED_NR/nr_prach_procedures.c b/openair1/SCHED_NR/nr_prach_procedures.c index 7dfe05dccd..9e581e1a00 100644 --- a/openair1/SCHED_NR/nr_prach_procedures.c +++ b/openair1/SCHED_NR/nr_prach_procedures.c @@ -63,85 +63,88 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac ru=gNB->RU_list[0]; - int prach_id = find_nr_prach(gNB, frame, slot, SEARCH_EXIST); - if (prach_id >= 0) { - 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; - const int prach_start_slot = gNB->prach_vars.list[prach_id].slot; - uint8_t prachStartSymbol; - int N_dur = get_nr_prach_duration(prach_pdu->prach_format); + gNB_PRACH_list_t *prach_id = find_nr_prach(gNB, frame, slot, SEARCH_EXIST); + if (!prach_id) { + return; + } - for(int prach_oc = 0; prach_oc < prach_pdu->num_prach_ocas; prach_oc++) { - for (ru_aa=0,aa=0;ru_aanb_rx;ru_aa++,aa++) { - gNB->prach_vars.rxsigF[aa] = ru->prach_rxsigF[prach_oc][ru_aa]; - } + LOG_D(NR_PHY, "%d.%d Got prach entry\n", frame, slot); + nfapi_nr_prach_pdu_t *prach_pdu = &prach_id->pdu; + const int prach_start_slot = prach_id->slot; + uint8_t prachStartSymbol; + int N_dur = get_nr_prach_duration(prach_pdu->prach_format); - prachStartSymbol = prach_pdu->prach_start_symbol + 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}. + for (int prach_oc = 0; prach_oc < prach_pdu->num_prach_ocas; prach_oc++) { + for (ru_aa = 0, aa = 0; ru_aa < ru->nb_rx; ru_aa++, aa++) { + gNB->prach_vars.rxsigF[aa] = ru->prach_rxsigF[prach_oc][ru_aa]; + } - rx_nr_prach(gNB, - prach_pdu, - prach_oc, - frame, - slot, - &max_preamble[0], - &max_preamble_energy[0], - &max_preamble_delay[0]); - LOG_D(NR_PHY,"[RAPROC] Frame %d, slot %d, occasion %d (prachStartSymbol %d) : Most likely preamble %d, energy %d.%d dB delay %d (prach_energy counter %d)\n", - frame,slot,prach_oc,prachStartSymbol, - max_preamble[0], - max_preamble_energy[0]/10, - max_preamble_energy[0]%10, - max_preamble_delay[0], - gNB->prach_energy_counter); + prachStartSymbol = prach_pdu->prach_start_symbol + 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}. - if ((gNB->prach_energy_counter == NUM_PRACH_RX_FOR_NOISE_ESTIMATE) - && (max_preamble_energy[0] > gNB->measurements.prach_I0 + gNB->prach_thres) - && (rach_ind->number_of_pdus < MAX_NUM_NR_RX_RACH_PDUS)) { - LOG_A(NR_PHY, - "[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", - frame, - prach_start_slot, - max_preamble[0], - max_preamble_energy[0] / 10, - max_preamble_energy[0] % 10, - gNB->measurements.prach_I0, - gNB->prach_thres, - max_preamble_delay[0], - prachStartSymbol, - prach_pdu->num_ra); + rx_nr_prach(gNB, prach_pdu, prach_oc, frame, slot, &max_preamble[0], &max_preamble_energy[0], &max_preamble_delay[0]); + LOG_D(NR_PHY, + "[RAPROC] Frame %d, slot %d, occasion %d (prachStartSymbol %d) : Most likely preamble %d, energy %d.%d dB delay %d " + "(prach_energy counter %d)\n", + frame, + slot, + prach_oc, + prachStartSymbol, + max_preamble[0], + max_preamble_energy[0] / 10, + max_preamble_energy[0] % 10, + max_preamble_delay[0], + gNB->prach_energy_counter); - T(T_ENB_PHY_INITIATE_RA_PROCEDURE, - T_INT(gNB->Mod_id), - T_INT(frame), - T_INT(slot), - T_INT(max_preamble[0]), - T_INT(max_preamble_energy[0]), - T_INT(max_preamble_delay[0])); + if ((gNB->prach_energy_counter == NUM_PRACH_RX_FOR_NOISE_ESTIMATE) + && (max_preamble_energy[0] > gNB->measurements.prach_I0 + gNB->prach_thres) + && (rach_ind->number_of_pdus < MAX_NUM_NR_RX_RACH_PDUS)) { + LOG_A(NR_PHY, + "[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", + frame, + prach_start_slot, + max_preamble[0], + max_preamble_energy[0] / 10, + max_preamble_energy[0] % 10, + gNB->measurements.prach_I0, + gNB->prach_thres, + max_preamble_delay[0], + prachStartSymbol, + prach_pdu->num_ra); - nfapi_nr_prach_indication_pdu_t *ind = rach_ind->pdu_list + rach_ind->number_of_pdus; - ind->phy_cell_id = gNB->gNB_config.cell_config.phy_cell_id.value; - ind->symbol_index = prachStartSymbol; - ind->slot_index = slot; - ind->freq_index = prach_pdu->num_ra; - ind->avg_rssi = (max_preamble_energy[0] < 631) ? (128 + (max_preamble_energy[0] / 5)) : 254; - ind->avg_snr = 0xff; // invalid for now + T(T_ENB_PHY_INITIATE_RA_PROCEDURE, + T_INT(gNB->Mod_id), + T_INT(frame), + T_INT(slot), + T_INT(max_preamble[0]), + T_INT(max_preamble_energy[0]), + T_INT(max_preamble_delay[0])); - ind->num_preamble = 1; - ind->preamble_list[0].preamble_index = max_preamble[0]; - ind->preamble_list[0].timing_advance = max_preamble_delay[0]; - ind->preamble_list[0].preamble_pwr = 0xffffffff; - rach_ind->number_of_pdus++; - } - gNB->measurements.prach_I0 = ((gNB->measurements.prach_I0*900)>>10) + ((max_preamble_energy[0]*124)>>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 < NUM_PRACH_RX_FOR_NOISE_ESTIMATE) - gNB->prach_energy_counter++; - } //if prach_id>0 - rach_ind->slot = prach_start_slot; - LOG_D(NR_PHY,"Freeing PRACH entry %d\n",prach_id); - free_nr_prach_entry(gNB,prach_id); - } // for NUMBER_OF_NR_PRACH_OCCASION_MAX + nfapi_nr_prach_indication_pdu_t *ind = rach_ind->pdu_list + rach_ind->number_of_pdus; + ind->phy_cell_id = gNB->gNB_config.cell_config.phy_cell_id.value; + ind->symbol_index = prachStartSymbol; + ind->slot_index = slot; + ind->freq_index = prach_pdu->num_ra; + ind->avg_rssi = (max_preamble_energy[0] < 631) ? (128 + (max_preamble_energy[0] / 5)) : 254; + ind->avg_snr = 0xff; // invalid for now + + ind->num_preamble = 1; + ind->preamble_list[0].preamble_index = max_preamble[0]; + ind->preamble_list[0].timing_advance = max_preamble_delay[0]; + ind->preamble_list[0].preamble_pwr = 0xffffffff; + rach_ind->number_of_pdus++; + } + gNB->measurements.prach_I0 = ((gNB->measurements.prach_I0 * 900) >> 10) + ((max_preamble_energy[0] * 124) >> 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 < NUM_PRACH_RX_FOR_NOISE_ESTIMATE) + gNB->prach_energy_counter++; + } // if prach_id>0 + rach_ind->slot = prach_start_slot; + LOG_D(NR_PHY, "Freeing PRACH entry\n"); + free_nr_prach_entry(gNB, prach_id); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,0); } From 88cecd707be45000c53b39ec5c74cf090bda1d48 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Thu, 14 Aug 2025 10:53:34 +0200 Subject: [PATCH 09/23] regroup similar lists for "ru" and "gNB" in a common definition Merge the identical sizes. Use correct naming: it is a element of a list, not a list --- executables/nr-ru.c | 14 ++--- openair1/PHY/NR_TRANSPORT/nr_prach.c | 54 ++++++++++--------- .../PHY/NR_TRANSPORT/nr_transport_proto.h | 10 ++-- openair1/PHY/defs_RU.h | 14 +---- openair1/PHY/defs_common.h | 25 +++++++++ openair1/PHY/defs_gNB.h | 14 +---- openair1/SCHED_NR/fapi_nr_l1.c | 4 +- openair1/SCHED_NR/nr_prach_procedures.c | 2 +- 8 files changed, 70 insertions(+), 67 deletions(-) diff --git a/executables/nr-ru.c b/executables/nr-ru.c index bf701f8abc..0e507e5260 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -1208,7 +1208,7 @@ void *ru_thread(void *param) proc->tti_rx * gNB->frame_parms.samples_per_slot_wCP); // Do PRACH RU processing - RU_PRACH_list_t *p = find_nr_prach_ru(ru, proc->frame_rx, proc->tti_rx, SEARCH_EXIST); + prach_item_t *p = find_nr_prach_ru(ru, proc->frame_rx, proc->tti_rx, SEARCH_EXIST); if (p) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 1 ); @@ -1218,15 +1218,15 @@ void *ru_thread(void *param) T_INT(0), 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 - 1, fp) + fp->get_samples_per_slot(proc->tti_rx, fp)) * 4)); - int N_dur = get_nr_prach_duration(p->fmt); + int N_dur = get_nr_prach_duration(p->lower.fmt); - for (int prach_oc = 0; prach_oc < p->num_prach_ocas; prach_oc++) { - int prachStartSymbol = p->prachStartSymbol + prach_oc * N_dur; - int beam_id = p->beam ? p->beam[prach_oc] : 0; + for (int prach_oc = 0; prach_oc < p->lower.num_prach_ocas; prach_oc++) { + int prachStartSymbol = p->lower.prachStartSymbol + prach_oc * N_dur; + int beam_id = p->lower.beam ? p->lower.beam[prach_oc] : 0; //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, - p->fmt, // could also use format - p->numRA, + p->lower.fmt, // could also use format + p->lower.numRA, beam_id, prachStartSymbol, p->slot, diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 12c045e551..7329465f02 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -46,24 +46,24 @@ void init_prach_list(PHY_VARS_gNB *gNB) } } -void free_nr_prach_entry(PHY_VARS_gNB *gNB, gNB_PRACH_list_t *p) +void free_nr_prach_entry(PHY_VARS_gNB *gNB, prach_item_t *p) { for (uint16_t i = 0; i < NUMBER_OF_NR_PRACH_MAX; i++) { if (p == gNB->prach_vars.list + i) { p->frame = -1; p->slot = -1; p->num_slots = -1; - free_and_zero(p->beam_nb); + free_and_zero(p->upper.beam_nb); break; } } } -gNB_PRACH_list_t *find_nr_prach(PHY_VARS_gNB *gNB, int frame, int slot, find_type_t type) +prach_item_t *find_nr_prach(PHY_VARS_gNB *gNB, int frame, int slot, find_type_t type) { AssertFatal(gNB!=NULL,"gNB is null\n"); for (uint16_t i=0; iprach_vars.list + i; + prach_item_t *p = gNB->prach_vars.list + i; 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) && (p->frame == -1) && (p->slot == -1)) { return p; @@ -74,28 +74,29 @@ gNB_PRACH_list_t *find_nr_prach(PHY_VARS_gNB *gNB, int frame, int slot, find_typ return NULL; } -gNB_PRACH_list_t *nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) +prach_item_t *nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) { - gNB_PRACH_list_t *prach = find_nr_prach(gNB, SFN, Slot, SEARCH_EXIST_OR_FREE); + prach_item_t *prach = find_nr_prach(gNB, SFN, Slot, SEARCH_EXIST_OR_FREE); AssertFatal(prach, "prach list full!!!\n"); prach->frame = SFN; prach->slot = Slot; + prach->type=prach_upper; const int format = prach_pdu->prach_format; prach->num_slots = (format < 4) ? get_long_prach_dur(format, gNB->frame_parms.numerology_index) : 1; if (gNB->common_vars.beam_id) { int n_symb = get_nr_prach_duration(prach_pdu->prach_format); - prach->beam_nb = calloc(prach_pdu->beamforming.dig_bf_interface, sizeof(*prach->beam_nb)); + prach->upper.beam_nb = calloc(prach_pdu->beamforming.dig_bf_interface, sizeof(*prach->upper.beam_nb)); for (int i = 0; i < prach_pdu->beamforming.dig_bf_interface; i++) { int fapi_beam_idx = prach_pdu->beamforming.prgs_list[0].dig_bf_interface_list[i].beam_idx; int start_symb = prach_pdu->prach_start_symbol + i * n_symb; int bitmap = SL_to_bitmap(start_symb, n_symb); - prach->beam_nb[i] = beam_index_allocation(gNB->enable_analog_das, - fapi_beam_idx, - &gNB->gNB_config.analog_beamforming_ve, - &gNB->common_vars, - Slot, - NR_NUMBER_OF_SYMBOLS_PER_SLOT, - bitmap); + prach->upper.beam_nb[i] = beam_index_allocation(gNB->enable_analog_das, + fapi_beam_idx, + &gNB->gNB_config.analog_beamforming_ve, + &gNB->common_vars, + Slot, + NR_NUMBER_OF_SYMBOLS_PER_SLOT, + bitmap); } } prach->pdu = *prach_pdu; @@ -105,7 +106,7 @@ gNB_PRACH_list_t *nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_p void init_prach_ru_list(RU_t *ru) { AssertFatal(ru != NULL, "ru is null\n"); - for (int i = 0; i < NUMBER_OF_NR_RU_PRACH_MAX; i++) { + for (int i = 0; i < NUMBER_OF_NR_PRACH_MAX; i++) { ru->prach_list[i].frame = -1; ru->prach_list[i].slot = -1; ru->prach_list[i].num_slots = -1; @@ -113,12 +114,12 @@ void init_prach_ru_list(RU_t *ru) pthread_mutex_init(&ru->prach_list_mutex, NULL); } -RU_PRACH_list_t *find_nr_prach_ru(RU_t *ru, int frame, int slot, find_type_t type) +prach_item_t *find_nr_prach_ru(RU_t *ru, int frame, int slot, find_type_t type) { AssertFatal(ru != NULL, "ru is null\n"); pthread_mutex_lock(&ru->prach_list_mutex); - for (int i = 0; i < NUMBER_OF_NR_RU_PRACH_MAX; i++) { - RU_PRACH_list_t *p = ru->prach_list + i; + for (int i = 0; i < NUMBER_OF_NR_PRACH_MAX; i++) { + prach_item_t *p = ru->prach_list + i; 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) && (p->frame == -1) && (p->slot == -1)) { pthread_mutex_unlock(&ru->prach_list_mutex); @@ -134,7 +135,7 @@ RU_PRACH_list_t *find_nr_prach_ru(RU_t *ru, int frame, int slot, find_type_t typ void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu, int *beam_id) { - RU_PRACH_list_t *prach = find_nr_prach_ru(ru, SFN, Slot, SEARCH_EXIST_OR_FREE); + prach_item_t *prach = find_nr_prach_ru(ru, SFN, Slot, SEARCH_EXIST_OR_FREE); AssertFatal(prach, "ru prach list full\n"); pthread_mutex_lock(&ru->prach_list_mutex); @@ -142,18 +143,19 @@ void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_p prach->slot = Slot; const int fmt = prach_pdu->prach_format; prach->num_slots = (fmt < 4) ? get_long_prach_dur(fmt, ru->nr_frame_parms->numerology_index) : 1; - prach->fmt = fmt; - prach->numRA = prach_pdu->num_ra; - prach->beam = beam_id; - prach->prachStartSymbol = prach_pdu->prach_start_symbol; - prach->num_prach_ocas = prach_pdu->num_prach_ocas; + prach->type=prach_lower; + prach->lower.fmt = fmt; + prach->lower.numRA = prach_pdu->num_ra; + prach->lower.beam = beam_id; + prach->lower.prachStartSymbol = prach_pdu->prach_start_symbol; + prach->lower.num_prach_ocas = prach_pdu->num_prach_ocas; pthread_mutex_unlock(&ru->prach_list_mutex); } -void free_nr_ru_prach_entry(RU_t *ru, RU_PRACH_list_t *p) +void free_nr_ru_prach_entry(RU_t *ru, prach_item_t *p) { 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_PRACH_MAX; i++) { if (p == ru->prach_list + i) { p->frame = -1; p->slot = -1; diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index 8547a1415d..20568e8020 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -200,7 +200,7 @@ void nr_fill_ulsch(PHY_VARS_gNB *gNB, int slot, nfapi_nr_pusch_pdu_t *ulsch_pdu); -gNB_PRACH_list_t *nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu); +prach_item_t *nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu); void rx_nr_prach(PHY_VARS_gNB *gNB, nfapi_nr_prach_pdu_t *prach_pdu, @@ -223,8 +223,8 @@ void rx_nr_prach_ru(RU_t *ru, void nr_fill_prach_ru(RU_t *ru,int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu, int *beam_nb); -gNB_PRACH_list_t *find_nr_prach(PHY_VARS_gNB *gNB, int frame, int slot, find_type_t type); -RU_PRACH_list_t *find_nr_prach_ru(RU_t *ru, int frame, int slot, find_type_t type); +prach_item_t *find_nr_prach(PHY_VARS_gNB *gNB, int frame, int slot, find_type_t type); +prach_item_t *find_nr_prach_ru(RU_t *ru, int frame, int slot, find_type_t type); void nr_fill_pucch(PHY_VARS_gNB *gNB, int frame, @@ -247,10 +247,10 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB, void init_prach_list(PHY_VARS_gNB *gNB); void init_prach_ru_list(RU_t *ru); -void free_nr_ru_prach_entry(RU_t *ru, RU_PRACH_list_t *p); +void free_nr_ru_prach_entry(RU_t *ru, prach_item_t *p); int get_nr_prach_duration(uint8_t prach_format); -void free_nr_prach_entry(PHY_VARS_gNB *gNB, gNB_PRACH_list_t *); +void free_nr_prach_entry(PHY_VARS_gNB *gNB, prach_item_t *); void nr_decode_pucch1(c16_t **rxdataF, pucch_GroupHopping_t pucch_GroupHopping, diff --git a/openair1/PHY/defs_RU.h b/openair1/PHY/defs_RU.h index e72465c4a9..8116dfbc4b 100644 --- a/openair1/PHY/defs_RU.h +++ b/openair1/PHY/defs_RU.h @@ -190,18 +190,6 @@ typedef struct { task_ans_t *ans; } feptx_cmd_t; -typedef struct { - int frame; - int slot; - int fmt; - int numRA; - int prachStartSymbol; - int num_prach_ocas; - int num_slots; - int *beam; -} RU_PRACH_list_t; - -#define NUMBER_OF_NR_RU_PRACH_MAX 8 #define NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX 12 #define RU_RX_SLOT_DEPTH 4 typedef struct RU_proc_t_s { @@ -605,7 +593,7 @@ typedef struct RU_t_s { /// beamforming weight vectors int32_t **beam_weights[NUMBER_OF_eNB_MAX+1][15]; /// prach commands - RU_PRACH_list_t prach_list[NUMBER_OF_NR_RU_PRACH_MAX]; + prach_item_t prach_list[NUMBER_OF_NR_PRACH_MAX]; /// mutex for prach_list access pthread_mutex_t prach_list_mutex; /// received frequency-domain signal for PRACH (IF4p5 RRU) diff --git a/openair1/PHY/defs_common.h b/openair1/PHY/defs_common.h index b6619efc6e..085fbc15a4 100644 --- a/openair1/PHY/defs_common.h +++ b/openair1/PHY/defs_common.h @@ -998,6 +998,31 @@ typedef struct { bool failed; } decode_abort_t; +// TODO will be removed in a late commit +#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h" +#define NUMBER_OF_NR_PRACH_MAX 8 +typedef struct { + int frame; + int slot; + int num_slots; // prach duration in slots + enum { prach_upper, prach_lower } type; + union { + struct { + // identifier for concurrent beams + int *beam_nb; + nfapi_nr_prach_pdu_t pdu; + } upper; + struct { + int fmt; + int numRA; + int prachStartSymbol; + int num_prach_ocas; + int *beam; + } lower; + }; + nfapi_nr_prach_pdu_t pdu; +} prach_item_t; + static inline void init_abort(decode_abort_t *ab) { int ret = pthread_mutex_init(&ab->mutex_failure, NULL); diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 9575e33c7b..f62d19ba3a 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -134,24 +134,12 @@ typedef struct { nfapi_nr_dl_tti_ssb_pdu ssb_pdu; } NR_gNB_SSB_t; -typedef struct { - int frame; - int slot; - // identifier for concurrent beams - // prach duration in slots - int num_slots; - int *beam_nb; - nfapi_nr_prach_pdu_t pdu; -} gNB_PRACH_list_t; - -#define NUMBER_OF_NR_PRACH_MAX 8 - typedef struct { /// \brief ?. /// second index: rx antenna [0..63] (hard coded) \note Hard coded array size indexed by \c nb_antennas_rx. /// third index: frequency-domain sample [0..ofdm_symbol_size*12[ int16_t **rxsigF; - gNB_PRACH_list_t list[NUMBER_OF_NR_PRACH_MAX]; + prach_item_t list[NUMBER_OF_NR_PRACH_MAX]; } NR_gNB_PRACH; typedef struct { diff --git a/openair1/SCHED_NR/fapi_nr_l1.c b/openair1/SCHED_NR/fapi_nr_l1.c index 8b88b0195a..fa5167adff 100644 --- a/openair1/SCHED_NR/fapi_nr_l1.c +++ b/openair1/SCHED_NR/fapi_nr_l1.c @@ -154,9 +154,9 @@ void nr_schedule_ul_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_tti_request_t *UL_tti UL_tti_req->SFN, UL_tti_req->Slot); nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[i].prach_pdu; - gNB_PRACH_list_t *prach = nr_fill_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu); + prach_item_t *prach = nr_fill_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu); if (prach && (gNB->RU_list[0]->if_south == LOCAL_RF || gNB->RU_list[0]->if_south == REMOTE_IF5)) - nr_fill_prach_ru(gNB->RU_list[0], UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu, prach->beam_nb); + nr_fill_prach_ru(gNB->RU_list[0], UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu, prach->upper.beam_nb); break; case NFAPI_NR_UL_CONFIG_SRS_PDU_TYPE: LOG_D(NR_PHY, diff --git a/openair1/SCHED_NR/nr_prach_procedures.c b/openair1/SCHED_NR/nr_prach_procedures.c index 9e581e1a00..cc38665757 100644 --- a/openair1/SCHED_NR/nr_prach_procedures.c +++ b/openair1/SCHED_NR/nr_prach_procedures.c @@ -63,7 +63,7 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac ru=gNB->RU_list[0]; - gNB_PRACH_list_t *prach_id = find_nr_prach(gNB, frame, slot, SEARCH_EXIST); + prach_item_t *prach_id = find_nr_prach(gNB, frame, slot, SEARCH_EXIST); if (!prach_id) { return; } From 4dd340b6bb52df20bc7e48f3bc8a6384e800e18f Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Thu, 14 Aug 2025 11:39:36 +0200 Subject: [PATCH 10/23] merge almost duplicated code for ru prach list and gNB prach list (gNB is not the proper name, it is CU+DU, gNB is RU+CU+DU) --- executables/nr-ru.c | 4 +- openair1/PHY/INIT/nr_init.c | 2 +- openair1/PHY/INIT/nr_init_ru.c | 4 +- openair1/PHY/NR_TRANSPORT/nr_prach.c | 143 +++++++----------- .../PHY/NR_TRANSPORT/nr_transport_proto.h | 10 +- openair1/PHY/defs_RU.h | 5 +- openair1/PHY/defs_common.h | 11 +- openair1/PHY/defs_gNB.h | 2 +- openair1/SCHED/nfapi_nr_dummy.c | 5 +- openair1/SCHED_NR/nr_prach_procedures.c | 4 +- openair1/SIMULATION/NR_PHY/prachsim.c | 12 +- 11 files changed, 79 insertions(+), 123 deletions(-) diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 0e507e5260..1c2e1acaf1 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -1208,7 +1208,7 @@ void *ru_thread(void *param) proc->tti_rx * gNB->frame_parms.samples_per_slot_wCP); // Do PRACH RU processing - prach_item_t *p = find_nr_prach_ru(ru, proc->frame_rx, proc->tti_rx, SEARCH_EXIST); + prach_item_t *p = find_nr_prach(&ru->prach_list, proc->frame_rx, proc->tti_rx, SEARCH_EXIST); if (p) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 1 ); @@ -1234,7 +1234,7 @@ void *ru_thread(void *param) proc->frame_rx, proc->tti_rx); } - free_nr_ru_prach_entry(ru, p); + free_nr_prach_entry(&ru->prach_list, p); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 0); } // end if (prach_id >= 0) } // end if (ru->feprx) diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 23334c8626..75145c78a4 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -192,7 +192,7 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB) // PRACH prach_vars->rxsigF = (int16_t **)malloc16_clear(Prx * sizeof(int16_t *)); - init_prach_list(gNB); + init_prach_list(&gNB->prach_vars.list, prach_upper); int N_RB_UL = cfg->carrier_config.ul_grid_size[cfg->ssb_config.scs_common.value].value; int n_buf = Prx*max_ul_mimo_layers; diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c index ca753938a6..6ad085eb4c 100644 --- a/openair1/PHY/INIT/nr_init_ru.c +++ b/openair1/PHY/INIT/nr_init_ru.c @@ -27,8 +27,6 @@ #include #include "openair1/PHY/defs_RU.h" -void init_prach_ru_list(RU_t *ru); - void nr_phy_init_RU(RU_t *ru) { NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; @@ -132,7 +130,7 @@ void nr_phy_init_RU(RU_t *ru) LOG_D(PHY, "[INIT] %s() ru->num_gNB:%d \n", __FUNCTION__, ru->num_gNB); } // !=IF5 - init_prach_ru_list(ru); + init_prach_list(&ru->prach_list, prach_lower); } void nr_phy_free_RU(RU_t *ru) diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 7329465f02..9fab6254ca 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -36,51 +36,57 @@ #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" #include "openair1/PHY/NR_TRANSPORT/nr_prach.h" -void init_prach_list(PHY_VARS_gNB *gNB) +void init_prach_list(prach_list_t *l, prach_type_t t) { - AssertFatal(gNB != NULL, "gNB is null\n"); - for (int i = 0; i < NUMBER_OF_NR_PRACH_MAX; i++){ - gNB->prach_vars.list[i].frame = -1; - gNB->prach_vars.list[i].slot = -1; - gNB->prach_vars.list[i].num_slots = -1; - } + pthread_mutex_init(&l->prach_list_mutex, NULL); + for (prach_item_t *p = l->list; p < l->list + NUMBER_OF_NR_PRACH_MAX; p++) + *p = (prach_item_t){.frame = -1, .slot = -1, .type = t}; } -void free_nr_prach_entry(PHY_VARS_gNB *gNB, prach_item_t *p) +void free_nr_prach_entry(prach_list_t *l, prach_item_t *p) { - for (uint16_t i = 0; i < NUMBER_OF_NR_PRACH_MAX; i++) { - if (p == gNB->prach_vars.list + i) { - p->frame = -1; - p->slot = -1; - p->num_slots = -1; - free_and_zero(p->upper.beam_nb); + pthread_mutex_lock(&l->prach_list_mutex); + if (p->type == prach_upper) + free_and_zero(p->upper.beam_nb); + *p = (prach_item_t){.frame = -1, .slot = -1, .num_slots = -1}; + pthread_mutex_unlock(&l->prach_list_mutex); +} + +prach_item_t *find_nr_prach(prach_list_t *l, int frame, int slot, find_type_t type) +{ + pthread_mutex_lock(&l->prach_list_mutex); + prach_item_t *p = l->list; + prach_item_t *end = p + NUMBER_OF_NR_PRACH_MAX; + for (; p < end; p++) + if (p->frame == frame && (p->slot + p->num_slots - 1) == slot) break; + if (p == end) { + if (type == SEARCH_EXIST) { + pthread_mutex_unlock(&l->prach_list_mutex); + return NULL; } + for (p = l->list; p < end; p++) + if (p->frame == -1 && p->slot == -1) + break; } -} - -prach_item_t *find_nr_prach(PHY_VARS_gNB *gNB, int frame, int slot, find_type_t type) -{ - AssertFatal(gNB!=NULL,"gNB is null\n"); - for (uint16_t i=0; iprach_vars.list + i; - 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) && (p->frame == -1) && (p->slot == -1)) { - return p; - } else if ((type == SEARCH_EXIST) && (p->frame == frame) && (p->slot + p->num_slots - 1 == slot)) { - return p; - } + if (p == end) { + pthread_mutex_unlock(&l->prach_list_mutex); + return NULL; } - return NULL; + // mark it used, it will be filled later + p->frame = frame; + pthread_mutex_unlock(&l->prach_list_mutex); + return p; } prach_item_t *nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) { - prach_item_t *prach = find_nr_prach(gNB, SFN, Slot, SEARCH_EXIST_OR_FREE); - AssertFatal(prach, "prach list full!!!\n"); - prach->frame = SFN; - prach->slot = Slot; - prach->type=prach_upper; + prach_item_t *prach = find_nr_prach(&gNB->prach_vars.list, SFN, Slot, SEARCH_EXIST_OR_FREE); + if (!prach) { + LOG_W(PHY, "no free space for a new detected rach, discarding\n"); + return NULL; + } + *prach = (prach_item_t){.frame = SFN, .slot = Slot, .type = prach_upper}; const int format = prach_pdu->prach_format; prach->num_slots = (format < 4) ? get_long_prach_dur(format, gNB->frame_parms.numerology_index) : 1; if (gNB->common_vars.beam_id) { @@ -103,66 +109,23 @@ prach_item_t *nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach return prach; } -void init_prach_ru_list(RU_t *ru) -{ - AssertFatal(ru != NULL, "ru is null\n"); - for (int i = 0; i < NUMBER_OF_NR_PRACH_MAX; i++) { - ru->prach_list[i].frame = -1; - ru->prach_list[i].slot = -1; - ru->prach_list[i].num_slots = -1; - } - pthread_mutex_init(&ru->prach_list_mutex, NULL); -} - -prach_item_t *find_nr_prach_ru(RU_t *ru, int frame, int slot, find_type_t type) -{ - AssertFatal(ru != NULL, "ru is null\n"); - pthread_mutex_lock(&ru->prach_list_mutex); - for (int i = 0; i < NUMBER_OF_NR_PRACH_MAX; i++) { - prach_item_t *p = ru->prach_list + i; - 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) && (p->frame == -1) && (p->slot == -1)) { - pthread_mutex_unlock(&ru->prach_list_mutex); - return p; - } else if ((type == SEARCH_EXIST) && (p->frame == frame) && (p->slot + p->num_slots - 1 == slot)) { - pthread_mutex_unlock(&ru->prach_list_mutex); - return p; - } - } - pthread_mutex_unlock(&ru->prach_list_mutex); - return NULL; -} - void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu, int *beam_id) { - prach_item_t *prach = find_nr_prach_ru(ru, SFN, Slot, SEARCH_EXIST_OR_FREE); - AssertFatal(prach, "ru prach list full\n"); - - pthread_mutex_lock(&ru->prach_list_mutex); - prach->frame = SFN; - prach->slot = Slot; - const int fmt = prach_pdu->prach_format; - prach->num_slots = (fmt < 4) ? get_long_prach_dur(fmt, ru->nr_frame_parms->numerology_index) : 1; - prach->type=prach_lower; - prach->lower.fmt = fmt; - prach->lower.numRA = prach_pdu->num_ra; - prach->lower.beam = beam_id; - prach->lower.prachStartSymbol = prach_pdu->prach_start_symbol; - prach->lower.num_prach_ocas = prach_pdu->num_prach_ocas; - pthread_mutex_unlock(&ru->prach_list_mutex); -} - -void free_nr_ru_prach_entry(RU_t *ru, prach_item_t *p) -{ - pthread_mutex_lock(&ru->prach_list_mutex); - for (int i = 0; i < NUMBER_OF_NR_PRACH_MAX; i++) { - if (p == ru->prach_list + i) { - p->frame = -1; - p->slot = -1; - break; - } + prach_item_t *prach = find_nr_prach(&ru->prach_list, SFN, Slot, SEARCH_EXIST_OR_FREE); + if (!prach) { + LOG_E(PHY, "no prach memory found\n"); + return; } - pthread_mutex_unlock(&ru->prach_list_mutex); + const int fmt = prach_pdu->prach_format; + *prach = (prach_item_t){.frame = SFN, + .slot = Slot, + .type = prach_lower, + .num_slots = (fmt < 4) ? get_long_prach_dur(fmt, ru->nr_frame_parms->numerology_index) : 1, + .lower = {.fmt = fmt, + .numRA = prach_pdu->num_ra, + .beam = beam_id, + .prachStartSymbol = prach_pdu->prach_start_symbol, + .num_prach_ocas = prach_pdu->num_prach_ocas}}; } void rx_nr_prach_ru(RU_t *ru, diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index 20568e8020..f43e4cdcdb 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -222,10 +222,7 @@ void rx_nr_prach_ru(RU_t *ru, int subframe); void nr_fill_prach_ru(RU_t *ru,int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu, int *beam_nb); - -prach_item_t *find_nr_prach(PHY_VARS_gNB *gNB, int frame, int slot, find_type_t type); -prach_item_t *find_nr_prach_ru(RU_t *ru, int frame, int slot, find_type_t type); - +prach_item_t *find_nr_prach(prach_list_t *, int frame, int slot, find_type_t type); void nr_fill_pucch(PHY_VARS_gNB *gNB, int frame, int slot, @@ -245,12 +242,9 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB, c16_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], c16_t srs_received_noise[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)]); -void init_prach_list(PHY_VARS_gNB *gNB); -void init_prach_ru_list(RU_t *ru); -void free_nr_ru_prach_entry(RU_t *ru, prach_item_t *p); int get_nr_prach_duration(uint8_t prach_format); -void free_nr_prach_entry(PHY_VARS_gNB *gNB, prach_item_t *); +void free_nr_prach_entry(prach_list_t *, prach_item_t *); void nr_decode_pucch1(c16_t **rxdataF, pucch_GroupHopping_t pucch_GroupHopping, diff --git a/openair1/PHY/defs_RU.h b/openair1/PHY/defs_RU.h index 8116dfbc4b..3d85c96af8 100644 --- a/openair1/PHY/defs_RU.h +++ b/openair1/PHY/defs_RU.h @@ -592,10 +592,7 @@ typedef struct RU_t_s { int32_t *bw_list[NUMBER_OF_eNB_MAX+1]; /// beamforming weight vectors int32_t **beam_weights[NUMBER_OF_eNB_MAX+1][15]; - /// prach commands - prach_item_t prach_list[NUMBER_OF_NR_PRACH_MAX]; - /// mutex for prach_list access - pthread_mutex_t prach_list_mutex; + prach_list_t prach_list; /// received frequency-domain signal for PRACH (IF4p5 RRU) int16_t **prach_rxsigF[NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX]; /// received frequency-domain signal for PRACH BR (IF4p5 RRU) diff --git a/openair1/PHY/defs_common.h b/openair1/PHY/defs_common.h index 085fbc15a4..79f1763842 100644 --- a/openair1/PHY/defs_common.h +++ b/openair1/PHY/defs_common.h @@ -1001,11 +1001,12 @@ typedef struct { // TODO will be removed in a late commit #include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h" #define NUMBER_OF_NR_PRACH_MAX 8 +typedef enum { prach_upper, prach_lower } prach_type_t; typedef struct { int frame; int slot; int num_slots; // prach duration in slots - enum { prach_upper, prach_lower } type; + prach_type_t type; union { struct { // identifier for concurrent beams @@ -1023,6 +1024,14 @@ typedef struct { nfapi_nr_prach_pdu_t pdu; } prach_item_t; +typedef struct { + /// prach commands + prach_item_t list[NUMBER_OF_NR_PRACH_MAX]; + /// mutex for prach_list access + pthread_mutex_t prach_list_mutex; +} prach_list_t; +void init_prach_list(prach_list_t *, prach_type_t); + static inline void init_abort(decode_abort_t *ab) { int ret = pthread_mutex_init(&ab->mutex_failure, NULL); diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index f62d19ba3a..da3b4bcb01 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -139,7 +139,7 @@ typedef struct { /// second index: rx antenna [0..63] (hard coded) \note Hard coded array size indexed by \c nb_antennas_rx. /// third index: frequency-domain sample [0..ofdm_symbol_size*12[ int16_t **rxsigF; - prach_item_t list[NUMBER_OF_NR_PRACH_MAX]; + prach_list_t list; } NR_gNB_PRACH; typedef struct { diff --git a/openair1/SCHED/nfapi_nr_dummy.c b/openair1/SCHED/nfapi_nr_dummy.c index 4e4dea190d..87c1ea576f 100644 --- a/openair1/SCHED/nfapi_nr_dummy.c +++ b/openair1/SCHED/nfapi_nr_dummy.c @@ -37,10 +37,7 @@ void nr_fill_pucch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pucch_pdu_t *pucch_pdu){} -gNB_PRACH_list_t nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) -{ -} -RU_PRACH_list_t nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) +void nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) { } diff --git a/openair1/SCHED_NR/nr_prach_procedures.c b/openair1/SCHED_NR/nr_prach_procedures.c index cc38665757..b649398456 100644 --- a/openair1/SCHED_NR/nr_prach_procedures.c +++ b/openair1/SCHED_NR/nr_prach_procedures.c @@ -63,7 +63,7 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac ru=gNB->RU_list[0]; - prach_item_t *prach_id = find_nr_prach(gNB, frame, slot, SEARCH_EXIST); + prach_item_t *prach_id = find_nr_prach(&gNB->prach_vars.list, frame, slot, SEARCH_EXIST); if (!prach_id) { return; } @@ -145,6 +145,6 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac } // if prach_id>0 rach_ind->slot = prach_start_slot; LOG_D(NR_PHY, "Freeing PRACH entry\n"); - free_nr_prach_entry(gNB, prach_id); + free_nr_prach_entry(&gNB->prach_vars.list, prach_id); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,0); } diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c index 35e242cad3..3eda15fc6f 100644 --- a/openair1/SIMULATION/NR_PHY/prachsim.c +++ b/openair1/SIMULATION/NR_PHY/prachsim.c @@ -151,9 +151,7 @@ int main(int argc, char **argv){ NR_DL_FRAME_PARMS *frame_parms; nfapi_nr_prach_config_t *prach_config; - nfapi_nr_prach_pdu_t *prach_pdu; fapi_nr_prach_config_t *ue_prach_config; - fapi_nr_ul_config_prach_pdu *ue_prach_pdu; channel_desc_t *UE2gNB; SCM_t channel_model = Rayleigh1; @@ -417,7 +415,6 @@ int main(int argc, char **argv){ ru = RC.ru[0]; frame_parms = &gNB->frame_parms; prach_config = &gNB->gNB_config.prach_config; - prach_pdu = &gNB->prach_vars.list[0].pdu; frame_parms = &gNB->frame_parms; //to be initialized I suppose (maybe not necessary for PBCH) s_re = malloc(2*sizeof(double*)); @@ -561,9 +558,6 @@ int main(int argc, char **argv){ prach_config->restricted_set_config.value = restrictedSetConfig; 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_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; memcpy((void*)&ru->config,(void*)&RC.gNB[0]->gNB_config,sizeof(ru->config)); RC.nb_nr_L1_inst=1; @@ -573,6 +567,10 @@ int main(int argc, char **argv){ phy_init_nr_gNB(gNB); nr_phy_init_RU(ru); + nfapi_nr_prach_pdu_t *prach_pdu = &gNB->prach_vars.list.list[0].pdu; + 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_pdu->prach_format = prach_format; // Configure UE UE = malloc(sizeof(PHY_VARS_NR_UE)); @@ -588,7 +586,7 @@ int main(int argc, char **argv){ exit(-1); } - ue_prach_pdu = &UE->prach_vars[0]->prach_pdu; + fapi_nr_ul_config_prach_pdu *ue_prach_pdu = &UE->prach_vars[0]->prach_pdu; ue_prach_config = &UE->nrUE_config.prach_config; txdata = UE->common_vars.txData; From cffb07d798c3b3d466d269cd6d0ecd0d2d2296d0 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Thu, 14 Aug 2025 15:17:13 +0200 Subject: [PATCH 11/23] remove permanent prach rxsigF in gNB and simplify the data structure --- executables/nr-gnb.c | 3 +- openair1/PHY/INIT/nr_init.c | 8 ++--- openair1/PHY/INIT/nr_init_ru.c | 8 ++--- openair1/PHY/NR_TRANSPORT/nr_prach.c | 28 ++++++++------- .../PHY/NR_TRANSPORT/nr_transport_proto.h | 3 +- openair1/PHY/defs_RU.h | 2 +- openair1/PHY/defs_gNB.h | 10 +----- openair1/SCHED_NR/nr_prach_procedures.c | 17 ++++----- openair1/SIMULATION/NR_PHY/prachsim.c | 36 ++++++++++--------- 9 files changed, 51 insertions(+), 64 deletions(-) diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 16ad366a0e..0e4fba9812 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -389,8 +389,7 @@ void init_eNB_afterRU(void) AssertFatal(gNB->RU_list[ru_id]->common.rxdataF != NULL, "RU %d : common.rxdataF is NULL\n", gNB->RU_list[ru_id]->idx); AssertFatal(gNB->RU_list[ru_id]->prach_rxsigF != NULL, "RU %d : prach_rxsigF is NULL\n", gNB->RU_list[ru_id]->idx); for (int i = 0; i < gNB->RU_list[ru_id]->nb_rx; aa++, i++) { - LOG_I(PHY,"Attaching RU %d antenna %d to gNB antenna %d\n", gNB->RU_list[ru_id]->idx, i, aa); - gNB->prach_vars.rxsigF[aa] = gNB->RU_list[ru_id]->prach_rxsigF[0][i]; + LOG_I(PHY, "Attaching RU %d antenna %d to gNB antenna %d\n", gNB->RU_list[ru_id]->idx, i, aa); for (int b = 0; b < gNB->RU_list[ru_id]->num_beams_period; b++) { int idx = i + b * gNB->RU_list[ru_id]->nb_rx; gNB->common_vars.rxdataF[b][aa] = (c16_t *)gNB->RU_list[ru_id]->common.rxdataF[idx]; diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 75145c78a4..88c539ccd3 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -104,9 +104,7 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB) // shortcuts NR_DL_FRAME_PARMS *const fp = &gNB->frame_parms; nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config; - NR_gNB_COMMON *const common_vars = &gNB->common_vars; - NR_gNB_PRACH *const prach_vars = &gNB->prach_vars; - + NR_gNB_COMMON *const common_vars = &gNB->common_vars; common_vars->analog_bf = cfg->analog_beamforming_ve.analog_bf_vendor_ext.value; LOG_I(PHY, "L1 configured with%s analog beamforming\n", common_vars->analog_bf ? "" : "out"); if (common_vars->analog_bf) { @@ -190,9 +188,7 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB) common_vars->debugBuff_sample_offset = 0; // PRACH - prach_vars->rxsigF = (int16_t **)malloc16_clear(Prx * sizeof(int16_t *)); - - init_prach_list(&gNB->prach_vars.list, prach_upper); + init_prach_list(&gNB->prach_list, prach_upper); int N_RB_UL = cfg->carrier_config.ul_grid_size[cfg->ssb_config.scs_common.value].value; int n_buf = Prx*max_ul_mimo_layers; diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c index 6ad085eb4c..d485e4977d 100644 --- a/openair1/PHY/INIT/nr_init_ru.c +++ b/openair1/PHY/INIT/nr_init_ru.c @@ -116,12 +116,12 @@ void nr_phy_init_RU(RU_t *ru) // AssertFatal(ru->nb_rx <= sizeof(ru->prach_rxsigF) / sizeof(ru->prach_rxsigF[0]), // "nb_antennas_rx too large"); for (int j = 0; j < NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX; j++) { - ru->prach_rxsigF[j] = (int16_t**)malloc(nb_rx_streams * sizeof(int16_t*)); - + ru->prach_rxsigF[j] = malloc(nb_rx_streams * sizeof(*ru->prach_rxsigF)); + for (int i = 0; i < nb_rx_streams; i++) { // largest size for PRACH FFT is 4x98304 (16*24576) - ru->prach_rxsigF[j][i] = (int16_t*)malloc16_clear(4 * 98304 * 2 * sizeof(int16_t)); - LOG_D(PHY,"[INIT] prach_vars->rxsigF[%d] = %p\n", i, ru->prach_rxsigF[j][i]); + ru->prach_rxsigF[j][i] = malloc16_clear(4 * 98304 * 2 * sizeof(**ru->prach_rxsigF)); + LOG_D(PHY, "[INIT] prach_vars->rxsigF[%d] = %p\n", i, ru->prach_rxsigF[j][i]); } } diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 9fab6254ca..371160437a 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -81,7 +81,7 @@ prach_item_t *find_nr_prach(prach_list_t *l, int frame, int slot, find_type_t ty prach_item_t *nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) { - prach_item_t *prach = find_nr_prach(&gNB->prach_vars.list, SFN, Slot, SEARCH_EXIST_OR_FREE); + prach_item_t *prach = find_nr_prach(&gNB->prach_list, SFN, Slot, SEARCH_EXIST_OR_FREE); if (!prach) { LOG_W(PHY, "no free space for a new detected rach, discarding\n"); return NULL; @@ -171,7 +171,7 @@ void rx_nr_prach_ru(RU_t *ru, prachStartSymbol, prachOccasion); - int16_t **rxsigF = ru->prach_rxsigF[prachOccasion]; + c16_t **rxsigF = (c16_t **)ru->prach_rxsigF[prachOccasion]; AssertFatal(ru->if_south == LOCAL_RF || ru->if_south == REMOTE_IF5, "we shouldn't call this if if_south != LOCAL_RF or REMOTE_IF5\n"); @@ -392,23 +392,25 @@ void rx_nr_prach_ru(RU_t *ru, // do DFT int16_t *prach2 = prach[aa] + (2*Ncp); // times 2 for complex samples for (int i = 0; i < reps; i++) - dft(dftsize, prach2 + 2*dftlen*i, rxsigF[aa] + 2*dftlen*i, 1); + dft(dftsize, prach2 + 2 * dftlen * i, (int16_t *)rxsigF[aa] + 2 * dftlen * i, 1); //LOG_M("ru_rxsigF_tmp.m","rxsFtmp", rxsigF[aa], dftlen*2*reps, 1, 1); //Coherent combining of PRACH repetitions (assumes channel does not change, to be revisted for "long" PRACH) LOG_D(PHY,"Doing PRACH combining of %d reptitions N_ZC %d\n",reps,N_ZC); - int16_t rxsigF_tmp[N_ZC<<1]; - // if (k+N_ZC > dftlen) { // PRACH signal is split around DC - int16_t *rxsigF2=rxsigF[aa]; - int k2=k<<1; + c16_t rxsigF_tmp[N_ZC]; + // if (k+N_ZC > dftlen) { // PRACH signal is split around DC + c16_t *rxsigF2 = rxsigF[aa]; + int k2 = k; - for (int j=0;jgNB_config.prach_config; - c16_t **rxsigF = (c16_t **)gNB->prach_vars.rxsigF; uint16_t preamble_index0 = 0; uint16_t numshift = 0; int first_nonzero_root_idx = 0; diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index f43e4cdcdb..db391dacc0 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -209,7 +209,8 @@ void rx_nr_prach(PHY_VARS_gNB *gNB, int subframe, uint16_t *max_preamble, uint16_t *max_preamble_energy, - uint16_t *max_preamble_delay); + uint16_t *max_preamble_delay, + c16_t **rxsigF); void rx_nr_prach_ru(RU_t *ru, int prach_fmt, diff --git a/openair1/PHY/defs_RU.h b/openair1/PHY/defs_RU.h index 3d85c96af8..b94d0b1c56 100644 --- a/openair1/PHY/defs_RU.h +++ b/openair1/PHY/defs_RU.h @@ -593,7 +593,7 @@ typedef struct RU_t_s { /// beamforming weight vectors int32_t **beam_weights[NUMBER_OF_eNB_MAX+1][15]; prach_list_t prach_list; - /// received frequency-domain signal for PRACH (IF4p5 RRU) + /// received frequency-domain signal for PRACH (IF4p5 RRU) int16_t **prach_rxsigF[NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX]; /// received frequency-domain signal for PRACH BR (IF4p5 RRU) int16_t **prach_rxsigF_br[4]; diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index da3b4bcb01..ad08cc1df1 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -134,14 +134,6 @@ typedef struct { nfapi_nr_dl_tti_ssb_pdu ssb_pdu; } NR_gNB_SSB_t; -typedef struct { - /// \brief ?. - /// second index: rx antenna [0..63] (hard coded) \note Hard coded array size indexed by \c nb_antennas_rx. - /// third index: frequency-domain sample [0..ofdm_symbol_size*12[ - int16_t **rxsigF; - prach_list_t list; -} NR_gNB_PRACH; - typedef struct { uint8_t NumPRSResources; prs_config_t prs_cfg[NR_MAX_PRS_RESOURCES_PER_SET]; @@ -416,7 +408,7 @@ typedef struct PHY_VARS_gNB_s { int max_nb_pusch; NR_gNB_COMMON common_vars; - NR_gNB_PRACH prach_vars; + prach_list_t prach_list; NR_gNB_PRS prs_vars; NR_gNB_PUSCH *pusch_vars; NR_gNB_PUCCH_t *pucch; diff --git a/openair1/SCHED_NR/nr_prach_procedures.c b/openair1/SCHED_NR/nr_prach_procedures.c index b649398456..74a98dc7f7 100644 --- a/openair1/SCHED_NR/nr_prach_procedures.c +++ b/openair1/SCHED_NR/nr_prach_procedures.c @@ -52,10 +52,6 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac uint16_t max_preamble[4]={0},max_preamble_energy[4]={0},max_preamble_delay[4]={0}; RU_t *ru; - int aa=0; - int ru_aa; - - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,1); rach_ind->sfn = frame; rach_ind->slot = slot; @@ -63,7 +59,7 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac ru=gNB->RU_list[0]; - prach_item_t *prach_id = find_nr_prach(&gNB->prach_vars.list, frame, slot, SEARCH_EXIST); + prach_item_t *prach_id = find_nr_prach(&gNB->prach_list, frame, slot, SEARCH_EXIST); if (!prach_id) { return; } @@ -75,16 +71,15 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac int N_dur = get_nr_prach_duration(prach_pdu->prach_format); for (int prach_oc = 0; prach_oc < prach_pdu->num_prach_ocas; prach_oc++) { - for (ru_aa = 0, aa = 0; ru_aa < ru->nb_rx; ru_aa++, aa++) { - gNB->prach_vars.rxsigF[aa] = ru->prach_rxsigF[prach_oc][ru_aa]; - } - prachStartSymbol = prach_pdu->prach_start_symbol + 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}. - rx_nr_prach(gNB, prach_pdu, prach_oc, frame, slot, &max_preamble[0], &max_preamble_energy[0], &max_preamble_delay[0]); + c16_t *rxsigF[ru->nb_rx]; + for (int i = 0; i < ru->nb_rx; ++i) + rxsigF[i] = (c16_t *)ru->prach_rxsigF[prach_oc][i]; + rx_nr_prach(gNB, prach_pdu, prach_oc, frame, slot, &max_preamble[0], &max_preamble_energy[0], &max_preamble_delay[0], rxsigF); LOG_D(NR_PHY, "[RAPROC] Frame %d, slot %d, occasion %d (prachStartSymbol %d) : Most likely preamble %d, energy %d.%d dB delay %d " "(prach_energy counter %d)\n", @@ -145,6 +140,6 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac } // if prach_id>0 rach_ind->slot = prach_start_slot; LOG_D(NR_PHY, "Freeing PRACH entry\n"); - free_nr_prach_entry(&gNB->prach_vars.list, prach_id); + free_nr_prach_entry(&gNB->prach_list, prach_id); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,0); } diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c index 3eda15fc6f..9f2e06762c 100644 --- a/openair1/SIMULATION/NR_PHY/prachsim.c +++ b/openair1/SIMULATION/NR_PHY/prachsim.c @@ -567,7 +567,7 @@ int main(int argc, char **argv){ phy_init_nr_gNB(gNB); nr_phy_init_RU(ru); - nfapi_nr_prach_pdu_t *prach_pdu = &gNB->prach_vars.list.list[0].pdu; + nfapi_nr_prach_pdu_t *prach_pdu = &gNB->prach_list.list[0].pdu; 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_pdu->prach_format = prach_format; @@ -769,25 +769,27 @@ int main(int argc, char **argv){ nr_slot_fep_ul(frame_parms, ru->common.rxdata[aa], ru->common.rxdataF[aa], l, slot, ru->N_TA_offset); } } + rx_nr_prach_ru(ru, prach_format, numRA, 0, prachStartSymbol, slot, prachOccasion, frame, slot); + c16_t *rxsigF[ru->nb_rx]; + for (int i = 0; i < ru->nb_rx; ++i) + rxsigF[i] = (c16_t *)ru->prach_rxsigF[prachOccasion][i]; + if (n_frames == 1) + printf("ncs %d,num_seq %d\n", + prach_pdu->num_cs, + prach_config->num_prach_fd_occasions_list[fd_occasion].num_root_sequences.value); + rx_nr_prach(gNB, prach_pdu, prachOccasion, frame, subframe, &preamble_rx, &preamble_energy, &preamble_delay, rxsigF); - rx_nr_prach_ru(ru, prach_format, numRA, 0, prachStartSymbol, slot, prachOccasion, frame, slot); + // printf(" preamble_energy %d preamble_rx %d preamble_tx %d \n", preamble_energy, preamble_rx, preamble_tx); - for (int i = 0; i < ru->nb_rx; ++i) - gNB->prach_vars.rxsigF[i] = ru->prach_rxsigF[prachOccasion][i]; - if (n_frames == 1) printf("ncs %d,num_seq %d\n",prach_pdu->num_cs, prach_config->num_prach_fd_occasions_list[fd_occasion].num_root_sequences.value); - rx_nr_prach(gNB, prach_pdu, prachOccasion, frame, subframe, &preamble_rx, &preamble_energy, &preamble_delay); + if (preamble_rx != preamble_tx) + prach_errors++; + else + delay_avg += (double)preamble_delay; - // printf(" preamble_energy %d preamble_rx %d preamble_tx %d \n", preamble_energy, preamble_rx, preamble_tx); + N_ZC = (prach_sequence_length) ? 139 : 839; - if (preamble_rx != preamble_tx) - prach_errors++; - else - delay_avg += (double)preamble_delay; - - N_ZC = (prach_sequence_length) ? 139 : 839; - - if (n_frames==1) { - printf("preamble %d (tx %d) : energy %d, delay %d\n",preamble_rx,preamble_tx,preamble_energy,preamble_delay); + if (n_frames == 1) { + printf("preamble %d (tx %d) : energy %d, delay %d\n", preamble_rx, preamble_tx, preamble_energy, preamble_delay); #ifdef NR_PRACH_DEBUG LOG_M("prach0.m","prach0", &txdata[0][prach_start], frame_parms->samples_per_subframe, 1, 1); LOG_M("rxsig0.m","rxs0", &ru->common.rxdata[0][subframe*frame_parms->samples_per_subframe], frame_parms->samples_per_subframe, 1, 1); @@ -797,7 +799,7 @@ int main(int argc, char **argv){ LOG_M("prach_preamble.m","prachp", &gNB->X_u[0], N_ZC, 1, 1); LOG_M("ue_prach_preamble.m","prachp", &UE->X_u[0], N_ZC, 1, 1); #endif - } + } } printf("SNR %f dB, UE Speed %f km/h: errors %u/%d (delay %f)\n", SNR, ue_speed, prach_errors, n_frames, delay_avg/(double)(n_frames-prach_errors)); From d005336cb89ee5237a295cc5fd9897a0bf8d2ff6 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Thu, 14 Aug 2025 15:41:12 +0200 Subject: [PATCH 12/23] Simplify PRACH beam handling, remove race Simplify by removing a small malloc and memcpy() the beams. This should also remove the data race between ru and gNB/CU-DU --- executables/nr-ru.c | 2 +- openair1/PHY/NR_TRANSPORT/nr_prach.c | 24 ++++++++++++------------ openair1/PHY/defs_common.h | 3 +-- openair1/SCHED_NR/fapi_nr_l1.c | 2 +- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 1c2e1acaf1..f28f2919c4 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -1222,7 +1222,7 @@ void *ru_thread(void *param) for (int prach_oc = 0; prach_oc < p->lower.num_prach_ocas; prach_oc++) { int prachStartSymbol = p->lower.prachStartSymbol + prach_oc * N_dur; - int beam_id = p->lower.beam ? p->lower.beam[prach_oc] : 0; + int beam_id = p->beams[prach_oc]; //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, p->lower.fmt, // could also use format diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 371160437a..3c2eb73e77 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -46,8 +46,6 @@ void init_prach_list(prach_list_t *l, prach_type_t t) void free_nr_prach_entry(prach_list_t *l, prach_item_t *p) { pthread_mutex_lock(&l->prach_list_mutex); - if (p->type == prach_upper) - free_and_zero(p->upper.beam_nb); *p = (prach_item_t){.frame = -1, .slot = -1, .num_slots = -1}; pthread_mutex_unlock(&l->prach_list_mutex); } @@ -91,25 +89,27 @@ prach_item_t *nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach prach->num_slots = (format < 4) ? get_long_prach_dur(format, gNB->frame_parms.numerology_index) : 1; if (gNB->common_vars.beam_id) { int n_symb = get_nr_prach_duration(prach_pdu->prach_format); - prach->upper.beam_nb = calloc(prach_pdu->beamforming.dig_bf_interface, sizeof(*prach->upper.beam_nb)); + AssertFatal(prach_pdu->beamforming.dig_bf_interface < NFAPI_MAX_NUM_BG_IF, + "impossible beams size %d\n", + prach_pdu->beamforming.dig_bf_interface); for (int i = 0; i < prach_pdu->beamforming.dig_bf_interface; i++) { int fapi_beam_idx = prach_pdu->beamforming.prgs_list[0].dig_bf_interface_list[i].beam_idx; int start_symb = prach_pdu->prach_start_symbol + i * n_symb; int bitmap = SL_to_bitmap(start_symb, n_symb); - prach->upper.beam_nb[i] = beam_index_allocation(gNB->enable_analog_das, - fapi_beam_idx, - &gNB->gNB_config.analog_beamforming_ve, - &gNB->common_vars, - Slot, - NR_NUMBER_OF_SYMBOLS_PER_SLOT, - bitmap); + prach->beams[i] = beam_index_allocation(gNB->enable_analog_das, + fapi_beam_idx, + &gNB->gNB_config.analog_beamforming_ve, + &gNB->common_vars, + Slot, + NR_NUMBER_OF_SYMBOLS_PER_SLOT, + bitmap); } } prach->pdu = *prach_pdu; return prach; } -void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu, int *beam_id) +void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu, int *beams) { prach_item_t *prach = find_nr_prach(&ru->prach_list, SFN, Slot, SEARCH_EXIST_OR_FREE); if (!prach) { @@ -123,9 +123,9 @@ void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_p .num_slots = (fmt < 4) ? get_long_prach_dur(fmt, ru->nr_frame_parms->numerology_index) : 1, .lower = {.fmt = fmt, .numRA = prach_pdu->num_ra, - .beam = beam_id, .prachStartSymbol = prach_pdu->prach_start_symbol, .num_prach_ocas = prach_pdu->num_prach_ocas}}; + memcpy(prach->beams, beams, sizeof(prach->beams)); } void rx_nr_prach_ru(RU_t *ru, diff --git a/openair1/PHY/defs_common.h b/openair1/PHY/defs_common.h index 79f1763842..b9923a1b8b 100644 --- a/openair1/PHY/defs_common.h +++ b/openair1/PHY/defs_common.h @@ -1006,11 +1006,11 @@ typedef struct { int frame; int slot; int num_slots; // prach duration in slots + int beams[NFAPI_MAX_NUM_BG_IF]; prach_type_t type; union { struct { // identifier for concurrent beams - int *beam_nb; nfapi_nr_prach_pdu_t pdu; } upper; struct { @@ -1018,7 +1018,6 @@ typedef struct { int numRA; int prachStartSymbol; int num_prach_ocas; - int *beam; } lower; }; nfapi_nr_prach_pdu_t pdu; diff --git a/openair1/SCHED_NR/fapi_nr_l1.c b/openair1/SCHED_NR/fapi_nr_l1.c index fa5167adff..09419d4e84 100644 --- a/openair1/SCHED_NR/fapi_nr_l1.c +++ b/openair1/SCHED_NR/fapi_nr_l1.c @@ -156,7 +156,7 @@ void nr_schedule_ul_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_tti_request_t *UL_tti nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[i].prach_pdu; prach_item_t *prach = nr_fill_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu); if (prach && (gNB->RU_list[0]->if_south == LOCAL_RF || gNB->RU_list[0]->if_south == REMOTE_IF5)) - nr_fill_prach_ru(gNB->RU_list[0], UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu, prach->upper.beam_nb); + nr_fill_prach_ru(gNB->RU_list[0], UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu, prach->beams); break; case NFAPI_NR_UL_CONFIG_SRS_PDU_TYPE: LOG_D(NR_PHY, From c48e0b1a3223c0666b7bd5576487f7673e2e7168 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Mon, 18 Aug 2025 16:57:47 +0200 Subject: [PATCH 13/23] merge variants of prach_item_t as this is the same in gNB and RU --- executables/nr-ru.c | 10 +++---- openair1/PHY/INIT/nr_init.c | 2 +- openair1/PHY/INIT/nr_init_ru.c | 2 +- openair1/PHY/NR_TRANSPORT/nr_prach.c | 26 +++++++------------ .../PHY/NR_TRANSPORT/nr_transport_proto.h | 2 +- openair1/PHY/defs_common.h | 16 +----------- openair1/SCHED/nfapi_lte_dummy.c | 5 +--- openair1/SCHED_NR/fapi_nr_l1.c | 2 +- openair1/SIMULATION/NR_PHY/prachsim.c | 7 ++--- 9 files changed, 24 insertions(+), 48 deletions(-) diff --git a/executables/nr-ru.c b/executables/nr-ru.c index f28f2919c4..ae610beacd 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -1218,15 +1218,15 @@ void *ru_thread(void *param) T_INT(0), 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 - 1, fp) + fp->get_samples_per_slot(proc->tti_rx, fp)) * 4)); - int N_dur = get_nr_prach_duration(p->lower.fmt); + int N_dur = get_nr_prach_duration(p->pdu.prach_format); - for (int prach_oc = 0; prach_oc < p->lower.num_prach_ocas; prach_oc++) { - int prachStartSymbol = p->lower.prachStartSymbol + prach_oc * N_dur; + for (int prach_oc = 0; prach_oc < p->pdu.num_prach_ocas; prach_oc++) { + int prachStartSymbol = p->pdu.prach_start_symbol + prach_oc * N_dur; int beam_id = p->beams[prach_oc]; //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, - p->lower.fmt, // could also use format - p->lower.numRA, + p->pdu.prach_format, // could also use format + p->pdu.num_ra, beam_id, prachStartSymbol, p->slot, diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 88c539ccd3..7a360e30ff 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -188,7 +188,7 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB) common_vars->debugBuff_sample_offset = 0; // PRACH - init_prach_list(&gNB->prach_list, prach_upper); + init_prach_list(&gNB->prach_list); int N_RB_UL = cfg->carrier_config.ul_grid_size[cfg->ssb_config.scs_common.value].value; int n_buf = Prx*max_ul_mimo_layers; diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c index d485e4977d..30ec333c70 100644 --- a/openair1/PHY/INIT/nr_init_ru.c +++ b/openair1/PHY/INIT/nr_init_ru.c @@ -130,7 +130,7 @@ void nr_phy_init_RU(RU_t *ru) LOG_D(PHY, "[INIT] %s() ru->num_gNB:%d \n", __FUNCTION__, ru->num_gNB); } // !=IF5 - init_prach_list(&ru->prach_list, prach_lower); + init_prach_list(&ru->prach_list); } void nr_phy_free_RU(RU_t *ru) diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 3c2eb73e77..d1e337ce2e 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -36,11 +36,11 @@ #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" #include "openair1/PHY/NR_TRANSPORT/nr_prach.h" -void init_prach_list(prach_list_t *l, prach_type_t t) +void init_prach_list(prach_list_t *l) { pthread_mutex_init(&l->prach_list_mutex, NULL); for (prach_item_t *p = l->list; p < l->list + NUMBER_OF_NR_PRACH_MAX; p++) - *p = (prach_item_t){.frame = -1, .slot = -1, .type = t}; + *p = (prach_item_t){.frame = -1, .slot = -1}; } void free_nr_prach_entry(prach_list_t *l, prach_item_t *p) @@ -84,9 +84,10 @@ prach_item_t *nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach LOG_W(PHY, "no free space for a new detected rach, discarding\n"); return NULL; } - *prach = (prach_item_t){.frame = SFN, .slot = Slot, .type = prach_upper}; - const int format = prach_pdu->prach_format; - prach->num_slots = (format < 4) ? get_long_prach_dur(format, gNB->frame_parms.numerology_index) : 1; + const int fmt = prach_pdu->prach_format; + *prach = (prach_item_t){.frame = SFN, + .slot = Slot, + .num_slots = (fmt < 4) ? get_long_prach_dur(fmt, gNB->frame_parms.numerology_index) : 1}; if (gNB->common_vars.beam_id) { int n_symb = get_nr_prach_duration(prach_pdu->prach_format); AssertFatal(prach_pdu->beamforming.dig_bf_interface < NFAPI_MAX_NUM_BG_IF, @@ -109,23 +110,14 @@ prach_item_t *nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach return prach; } -void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu, int *beams) +void nr_fill_prach_ru(RU_t *ru, prach_item_t *gnb_prach) { - prach_item_t *prach = find_nr_prach(&ru->prach_list, SFN, Slot, SEARCH_EXIST_OR_FREE); + prach_item_t *prach = find_nr_prach(&ru->prach_list, gnb_prach->frame, gnb_prach->slot, SEARCH_EXIST_OR_FREE); if (!prach) { LOG_E(PHY, "no prach memory found\n"); return; } - const int fmt = prach_pdu->prach_format; - *prach = (prach_item_t){.frame = SFN, - .slot = Slot, - .type = prach_lower, - .num_slots = (fmt < 4) ? get_long_prach_dur(fmt, ru->nr_frame_parms->numerology_index) : 1, - .lower = {.fmt = fmt, - .numRA = prach_pdu->num_ra, - .prachStartSymbol = prach_pdu->prach_start_symbol, - .num_prach_ocas = prach_pdu->num_prach_ocas}}; - memcpy(prach->beams, beams, sizeof(prach->beams)); + *prach = *gnb_prach; } void rx_nr_prach_ru(RU_t *ru, diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index db391dacc0..1d1ef0a56d 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -222,7 +222,7 @@ void rx_nr_prach_ru(RU_t *ru, int frame, int subframe); -void nr_fill_prach_ru(RU_t *ru,int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu, int *beam_nb); +void nr_fill_prach_ru(RU_t *ru,prach_item_t * ); prach_item_t *find_nr_prach(prach_list_t *, int frame, int slot, find_type_t type); void nr_fill_pucch(PHY_VARS_gNB *gNB, int frame, diff --git a/openair1/PHY/defs_common.h b/openair1/PHY/defs_common.h index b9923a1b8b..b469555354 100644 --- a/openair1/PHY/defs_common.h +++ b/openair1/PHY/defs_common.h @@ -1001,25 +1001,11 @@ typedef struct { // TODO will be removed in a late commit #include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h" #define NUMBER_OF_NR_PRACH_MAX 8 -typedef enum { prach_upper, prach_lower } prach_type_t; typedef struct { int frame; int slot; int num_slots; // prach duration in slots int beams[NFAPI_MAX_NUM_BG_IF]; - prach_type_t type; - union { - struct { - // identifier for concurrent beams - nfapi_nr_prach_pdu_t pdu; - } upper; - struct { - int fmt; - int numRA; - int prachStartSymbol; - int num_prach_ocas; - } lower; - }; nfapi_nr_prach_pdu_t pdu; } prach_item_t; @@ -1029,7 +1015,7 @@ typedef struct { /// mutex for prach_list access pthread_mutex_t prach_list_mutex; } prach_list_t; -void init_prach_list(prach_list_t *, prach_type_t); +void init_prach_list(prach_list_t *); static inline void init_abort(decode_abort_t *ab) { diff --git a/openair1/SCHED/nfapi_lte_dummy.c b/openair1/SCHED/nfapi_lte_dummy.c index d61f0d0548..5d9b5b7a76 100644 --- a/openair1/SCHED/nfapi_lte_dummy.c +++ b/openair1/SCHED/nfapi_lte_dummy.c @@ -45,10 +45,7 @@ void nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu){} -void nr_fill_prach_ru(RU_t *ru, - int SFN, - int Slot, - nfapi_nr_prach_pdu_t *prach_pdu){} +void nr_fill_prach_ru(RU_t *ru,prach_item_t *gnb_prach){} void nr_phy_config_request(NR_PHY_Config_t *gNB){} diff --git a/openair1/SCHED_NR/fapi_nr_l1.c b/openair1/SCHED_NR/fapi_nr_l1.c index 09419d4e84..6d0a3ee7da 100644 --- a/openair1/SCHED_NR/fapi_nr_l1.c +++ b/openair1/SCHED_NR/fapi_nr_l1.c @@ -156,7 +156,7 @@ void nr_schedule_ul_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_tti_request_t *UL_tti nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[i].prach_pdu; prach_item_t *prach = nr_fill_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu); if (prach && (gNB->RU_list[0]->if_south == LOCAL_RF || gNB->RU_list[0]->if_south == REMOTE_IF5)) - nr_fill_prach_ru(gNB->RU_list[0], UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu, prach->beams); + nr_fill_prach_ru(gNB->RU_list[0], prach); break; case NFAPI_NR_UL_CONFIG_SRS_PDU_TYPE: LOG_D(NR_PHY, diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c index 9f2e06762c..9eb9c5c9c5 100644 --- a/openair1/SIMULATION/NR_PHY/prachsim.c +++ b/openair1/SIMULATION/NR_PHY/prachsim.c @@ -774,9 +774,10 @@ int main(int argc, char **argv){ for (int i = 0; i < ru->nb_rx; ++i) rxsigF[i] = (c16_t *)ru->prach_rxsigF[prachOccasion][i]; if (n_frames == 1) - printf("ncs %d,num_seq %d\n", - prach_pdu->num_cs, - prach_config->num_prach_fd_occasions_list[fd_occasion].num_root_sequences.value); + LOG_I(PHY, + "ncs %d,num_seq %d\n", + prach_pdu->num_cs, + prach_config->num_prach_fd_occasions_list[fd_occasion].num_root_sequences.value); rx_nr_prach(gNB, prach_pdu, prachOccasion, frame, subframe, &preamble_rx, &preamble_energy, &preamble_delay, rxsigF); // printf(" preamble_energy %d preamble_rx %d preamble_tx %d \n", preamble_energy, preamble_rx, preamble_tx); From d24e010367a6c1aeea041e1090fada293622aaca Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Thu, 11 Sep 2025 17:30:46 +0200 Subject: [PATCH 14/23] simplify computation of ru->prach_rxsigF[prachOccasion][aa] --- openair1/PHY/NR_TRANSPORT/nr_prach.c | 66 +++++++------------ .../PHY/NR_TRANSPORT/nr_transport_proto.h | 1 - openair1/SCHED_NR/nr_prach_procedures.c | 2 +- openair1/SIMULATION/NR_PHY/prachsim.c | 2 +- 4 files changed, 27 insertions(+), 44 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index d1e337ce2e..40a2900e15 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -133,8 +133,6 @@ void rx_nr_prach_ru(RU_t *ru, AssertFatal(ru != NULL,"ru is null\n"); NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; - int slot2 = slot; - int16_t *prach[ru->nb_rx]; 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; const uint8_t prach_mu = ru->config.prach_config.prach_sub_c_spacing.value; @@ -162,19 +160,8 @@ void rx_nr_prach_ru(RU_t *ru, numRA, prachStartSymbol, prachOccasion); - - c16_t **rxsigF = (c16_t **)ru->prach_rxsigF[prachOccasion]; - AssertFatal(ru->if_south == LOCAL_RF || ru->if_south == REMOTE_IF5, "we shouldn't call this if if_south != LOCAL_RF or REMOTE_IF5\n"); - - for (int aa = 0; aa < ru->nb_rx; aa++) { - if (prach_sequence_length == 0) - slot2 = prachStartSlot; - int idx = aa + beam * ru->nb_rx; - prach[aa] = (int16_t*)&ru->common.rxdata[idx][fp->get_samples_slot_timestamp(slot2, fp, 0) + sample_offset_slot - ru->N_TA_offset]; - } - int reps; int Ncp; int dftlen; @@ -183,11 +170,11 @@ void rx_nr_prach_ru(RU_t *ru, if (prach_sequence_length == 0) { LOG_D(PHY, "PRACH (ru %d) in %d.%d, format %d, msg1_frequencyStart %d\n", - ru->idx, - frame, - slot2, - prachFormat, - msg1_frequencystart); + ru->idx, + frame, + prachStartSlot, + prachFormat, + msg1_frequencystart); switch (prachFormat) { case 0: reps = 1; @@ -371,7 +358,7 @@ void rx_nr_prach_ru(RU_t *ru, int n_ra_prb = msg1_frequencystart; int k = (12*n_ra_prb) - 6*fp->N_RB_UL; - int N_ZC = (prach_sequence_length==0)?839:139; + int N_ZC = (prach_sequence_length == 0) ? 839 : 139; if (k<0) k+=(fp->ofdm_symbol_size); @@ -379,36 +366,34 @@ void rx_nr_prach_ru(RU_t *ru, k+=kbar; for (int aa=0; aanb_rx; aa++) { - AssertFatal(prach[aa]!=NULL,"prach[%d] is null\n",aa); + int slot2 = prach_sequence_length ? slot : prachStartSlot; + int idx = aa + beam * ru->nb_rx; + c16_t *prach = + (c16_t *)&ru->common.rxdata[idx][fp->get_samples_slot_timestamp(slot2, fp, 0) + sample_offset_slot - ru->N_TA_offset]; // do DFT - int16_t *prach2 = prach[aa] + (2*Ncp); // times 2 for complex samples - for (int i = 0; i < reps; i++) - dft(dftsize, prach2 + 2 * dftlen * i, (int16_t *)rxsigF[aa] + 2 * dftlen * i, 1); - - //LOG_M("ru_rxsigF_tmp.m","rxsFtmp", rxsigF[aa], dftlen*2*reps, 1, 1); - - //Coherent combining of PRACH repetitions (assumes channel does not change, to be revisted for "long" PRACH) - LOG_D(PHY,"Doing PRACH combining of %d reptitions N_ZC %d\n",reps,N_ZC); + c16_t *prach2 = prach + Ncp; c16_t rxsigF_tmp[N_ZC]; - // if (k+N_ZC > dftlen) { // PRACH signal is split around DC - c16_t *rxsigF2 = rxsigF[aa]; - int k2 = k; - - for (int j = 0; j < N_ZC; j++, k2++) { - if (k2 == dftlen) - k2 = 0; - rxsigF_tmp[j] = rxsigF2[k2]; - for (int i = 1; i < reps; i++) - rxsigF_tmp[j] = c16add(rxsigF_tmp[j], rxsigF2[k2 + i * dftlen]); + memset(rxsigF_tmp, 0, sizeof(rxsigF_tmp)); + for (int i = 0; i < reps; i++, prach2 += dftlen) { + c16_t tmp[dftlen] __attribute__((aligned(32))); + dft(dftsize, (int16_t *)prach2, (int16_t *)tmp, 1); + // Coherent combining of PRACH repetitions (assumes channel does not change, to be revisted for "long" PRACH) + LOG_D(PHY, "Doing PRACH combining of %d reptitions N_ZC %d\n", reps, N_ZC); + // if (k+N_ZC > dftlen) { // PRACH signal is split around DC + int k2 = k; + for (int j = 0; j < N_ZC; j++, k2++) { + if (k2 == dftlen) + k2 = 0; + rxsigF_tmp[j] = c16add(rxsigF_tmp[j], tmp[k2]); + } } - memcpy(rxsigF2, rxsigF_tmp, N_ZC * sizeof(*rxsigF2)); + memcpy(ru->prach_rxsigF[prachOccasion][aa], rxsigF_tmp, sizeof(rxsigF_tmp)); } } void rx_nr_prach(PHY_VARS_gNB *gNB, nfapi_nr_prach_pdu_t *prach_pdu, - int prachOccasion, int frame, int slot, uint16_t *max_preamble, @@ -658,4 +643,3 @@ void rx_nr_prach(PHY_VARS_gNB *gNB, stop_meas(&gNB->rx_prach); } - diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index 1d1ef0a56d..2cbe1fde77 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -204,7 +204,6 @@ prach_item_t *nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach void rx_nr_prach(PHY_VARS_gNB *gNB, nfapi_nr_prach_pdu_t *prach_pdu, - int prachOccasion, int frame, int subframe, uint16_t *max_preamble, diff --git a/openair1/SCHED_NR/nr_prach_procedures.c b/openair1/SCHED_NR/nr_prach_procedures.c index 74a98dc7f7..632269eeed 100644 --- a/openair1/SCHED_NR/nr_prach_procedures.c +++ b/openair1/SCHED_NR/nr_prach_procedures.c @@ -79,7 +79,7 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac c16_t *rxsigF[ru->nb_rx]; for (int i = 0; i < ru->nb_rx; ++i) rxsigF[i] = (c16_t *)ru->prach_rxsigF[prach_oc][i]; - rx_nr_prach(gNB, prach_pdu, prach_oc, frame, slot, &max_preamble[0], &max_preamble_energy[0], &max_preamble_delay[0], rxsigF); + rx_nr_prach(gNB, prach_pdu, frame, slot, max_preamble, max_preamble_energy, max_preamble_delay, rxsigF); LOG_D(NR_PHY, "[RAPROC] Frame %d, slot %d, occasion %d (prachStartSymbol %d) : Most likely preamble %d, energy %d.%d dB delay %d " "(prach_energy counter %d)\n", diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c index 9eb9c5c9c5..e5f64fff5d 100644 --- a/openair1/SIMULATION/NR_PHY/prachsim.c +++ b/openair1/SIMULATION/NR_PHY/prachsim.c @@ -778,7 +778,7 @@ int main(int argc, char **argv){ "ncs %d,num_seq %d\n", prach_pdu->num_cs, prach_config->num_prach_fd_occasions_list[fd_occasion].num_root_sequences.value); - rx_nr_prach(gNB, prach_pdu, prachOccasion, frame, subframe, &preamble_rx, &preamble_energy, &preamble_delay, rxsigF); + rx_nr_prach(gNB, prach_pdu, frame, subframe, &preamble_rx, &preamble_energy, &preamble_delay, rxsigF); // printf(" preamble_energy %d preamble_rx %d preamble_tx %d \n", preamble_energy, preamble_rx, preamble_tx); From 180f83d196f12463042f6759cfe469367861c7a1 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Wed, 29 Oct 2025 12:13:25 +0100 Subject: [PATCH 15/23] Refactor L1_nr_prach_procedures --- openair1/SCHED_NR/nr_prach_procedures.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/openair1/SCHED_NR/nr_prach_procedures.c b/openair1/SCHED_NR/nr_prach_procedures.c index 632269eeed..db01294da5 100644 --- a/openair1/SCHED_NR/nr_prach_procedures.c +++ b/openair1/SCHED_NR/nr_prach_procedures.c @@ -67,11 +67,10 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac LOG_D(NR_PHY, "%d.%d Got prach entry\n", frame, slot); nfapi_nr_prach_pdu_t *prach_pdu = &prach_id->pdu; const int prach_start_slot = prach_id->slot; - uint8_t prachStartSymbol; int N_dur = get_nr_prach_duration(prach_pdu->prach_format); for (int prach_oc = 0; prach_oc < prach_pdu->num_prach_ocas; prach_oc++) { - prachStartSymbol = prach_pdu->prach_start_symbol + prach_oc * N_dur; + uint prachStartSymbol = prach_pdu->prach_start_symbol + 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}. @@ -119,17 +118,16 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac T_INT(max_preamble_delay[0])); nfapi_nr_prach_indication_pdu_t *ind = rach_ind->pdu_list + rach_ind->number_of_pdus; - ind->phy_cell_id = gNB->gNB_config.cell_config.phy_cell_id.value; - ind->symbol_index = prachStartSymbol; - ind->slot_index = slot; - ind->freq_index = prach_pdu->num_ra; - ind->avg_rssi = (max_preamble_energy[0] < 631) ? (128 + (max_preamble_energy[0] / 5)) : 254; - ind->avg_snr = 0xff; // invalid for now - - ind->num_preamble = 1; - ind->preamble_list[0].preamble_index = max_preamble[0]; - ind->preamble_list[0].timing_advance = max_preamble_delay[0]; - ind->preamble_list[0].preamble_pwr = 0xffffffff; + *ind = (nfapi_nr_prach_indication_pdu_t){ + .phy_cell_id = gNB->gNB_config.cell_config.phy_cell_id.value, + .symbol_index = prachStartSymbol, + .slot_index = slot, + .freq_index = prach_pdu->num_ra, + .avg_rssi = (max_preamble_energy[0] < 631) ? (128 + (max_preamble_energy[0] / 5)) : 254, + .avg_snr = 0xff, // invalid for now + .num_preamble = 1, + .preamble_list = { + {.preamble_index = max_preamble[0], .timing_advance = max_preamble_delay[0], .preamble_pwr = 0xffffffff}}}; rach_ind->number_of_pdus++; } gNB->measurements.prach_I0 = ((gNB->measurements.prach_I0 * 900) >> 10) + ((max_preamble_energy[0] * 124) >> 10); From 4f39ba8f513519446714f99d3b0d2f6929f9cea5 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Wed, 29 Oct 2025 12:10:40 +0100 Subject: [PATCH 16/23] create a trace group for nr rach --- common/utils/LOG/log.h | 5 +++-- common/utils/T/T_messages.txt | 21 +++++++++++++++++++++ executables/nr-ru.c | 2 +- openair1/PHY/NR_TRANSPORT/nr_prach.c | 15 +++++++++++---- openair1/SCHED_NR/fapi_nr_l1.c | 1 + openair1/SCHED_NR/nr_prach_procedures.c | 4 ++-- 6 files changed, 39 insertions(+), 9 deletions(-) diff --git a/common/utils/LOG/log.h b/common/utils/LOG/log.h index a8c7becfdf..c873b0d418 100644 --- a/common/utils/LOG/log.h +++ b/common/utils/LOG/log.h @@ -168,8 +168,9 @@ static const char *const flag_name[] = {FOREACH_FLAG(FLAG_TEXT) ""}; COMP_DEF(GNB_APP, log) \ COMP_DEF(NR_RRC, log) \ COMP_DEF(NR_MAC, log) \ - COMP_DEF(NR_MAC_DCI, log) \ - COMP_DEF(NR_PHY_DCI, log) \ + COMP_DEF(NR_MAC_DCI, log) \ + COMP_DEF(NR_PHY_DCI, log) \ + COMP_DEF(NR_PHY_RACH, log) \ COMP_DEF(NR_PHY, log) \ COMP_DEF(LOADER, log) \ COMP_DEF(ASN1, log) \ diff --git a/common/utils/T/T_messages.txt b/common/utils/T/T_messages.txt index 2f17b62ea5..cd81deda2b 100644 --- a/common/utils/T/T_messages.txt +++ b/common/utils/T/T_messages.txt @@ -519,6 +519,27 @@ ID = LEGACY_NR_PHY_TRACE GROUP = ALL:LEGACY_NR_PHY:LEGACY_GROUP_TRACE:LEGACY FORMAT = string,log +ID = LEGACY_NR_PHY_RACH_INFO + DESC = NR_PHY_RACH legacy logs - info level + GROUP = ALL:LEGACY_NR_PHY_RACH:LEGACY_GROUP_INFO:LEGACY + FORMAT = string,log +ID = LEGACY_NR_PHY_RACH_ERROR + DESC = NR_PHY_RACH legacy logs - error level + GROUP = ALL:LEGACY_NR_PHY_RACH:LEGACY_GROUP_ERROR:LEGACY + FORMAT = string,log +ID = LEGACY_NR_PHY_RACH_WARNING + DESC = NR_PHY_RACH legacy logs - warning level + GROUP = ALL:LEGACY_NR_PHY_RACH:LEGACY_GROUP_WARNING:LEGACY + FORMAT = string,log +ID = LEGACY_NR_PHY_RACH_DEBUG + DESC = NR_PHY_RACH legacy logs - debug level + GROUP = ALL:LEGACY_NR_PHY_RACH:LEGACY_GROUP_DEBUG:LEGACY + FORMAT = string,log +ID = LEGACY_NR_PHY_RACH_TRACE + DESC = NR_PHY_RACH legacy logs - trace level + GROUP = ALL:LEGACY_NR_PHY_RACH:LEGACY_GROUP_TRACE:LEGACY + FORMAT = string,log + ID = LEGACY_S1AP_INFO DESC = S1AP legacy logs - info level GROUP = ALL:LEGACY_S1AP:LEGACY_GROUP_INFO:LEGACY diff --git a/executables/nr-ru.c b/executables/nr-ru.c index ae610beacd..60270d9d0f 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -1219,7 +1219,7 @@ void *ru_thread(void *param) 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 - 1, fp) + fp->get_samples_per_slot(proc->tti_rx, fp)) * 4)); int N_dur = get_nr_prach_duration(p->pdu.prach_format); - + LOG_D(NR_PHY_RACH, "%d.%d try to decode %d occasions \n", frame, slot, p->pdu.num_prach_ocas); for (int prach_oc = 0; prach_oc < p->pdu.num_prach_ocas; prach_oc++) { int prachStartSymbol = p->pdu.prach_start_symbol + prach_oc * N_dur; int beam_id = p->beams[prach_oc]; diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 40a2900e15..425e20dd84 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -46,6 +46,8 @@ void init_prach_list(prach_list_t *l) void free_nr_prach_entry(prach_list_t *l, prach_item_t *p) { pthread_mutex_lock(&l->prach_list_mutex); + if (p->frame == -1) + LOG_E(NR_PHY_RACH, "Freeing a not allocated prach entry\n"); *p = (prach_item_t){.frame = -1, .slot = -1, .num_slots = -1}; pthread_mutex_unlock(&l->prach_list_mutex); } @@ -421,7 +423,7 @@ void rx_nr_prach(PHY_VARS_gNB *gNB, const int prach_fmt = prach_pdu->prach_format; const int N_ZC = prach_sequence_length == 0 ? 839 : 139; - LOG_D(PHY, + LOG_D(NR_PHY_RACH, "L1 PRACH RX: rooSequenceIndex %d, numRootSeqeuences %d, NCS %d, N_ZC %d, format %d \n", rootSequenceIndex, numrootSequenceIndex, @@ -550,7 +552,12 @@ void rx_nr_prach(PHY_VARS_gNB *gNB, en); } - LOG_D(PHY,"PRACH RX preamble_index %d, preamble_offset %d\n",preamble_index,preamble_offset); + LOG_D(NR_PHY_RACH, + "PRACH RX preamble_index %d, preamble_offset %d, preamb shift %d new dft %d\n", + preamble_index, + preamble_offset, + preamble_shift, + new_dft); if (new_dft) { new_dft = false; @@ -606,8 +613,8 @@ void rx_nr_prach(PHY_VARS_gNB *gNB, for (int i = 0; i < NCS2; i++) { int lev = prach_ifft[preamble_shift2 + i]; int levdB = dB_fixed_times10(lev); - if (levdB>*max_preamble_energy) { - LOG_D(PHY,"preamble_index %d, delay %d en %d dB > %d dB\n",preamble_index,i,levdB,*max_preamble_energy); + if (levdB > *max_preamble_energy || (levdB == *max_preamble_energy && *max_preamble_delay > i)) { + LOG_D(NR_PHY_RACH, "preamble_index %d, delay %d en %d dB > %d dB\n", preamble_index, i, levdB, *max_preamble_energy); *max_preamble_energy = levdB; *max_preamble_delay = i; // Note: This has to be normalized to the 30.72 Ms/s sampling rate *max_preamble = preamble_index; diff --git a/openair1/SCHED_NR/fapi_nr_l1.c b/openair1/SCHED_NR/fapi_nr_l1.c index 6d0a3ee7da..ad6f90e6e8 100644 --- a/openair1/SCHED_NR/fapi_nr_l1.c +++ b/openair1/SCHED_NR/fapi_nr_l1.c @@ -154,6 +154,7 @@ void nr_schedule_ul_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_tti_request_t *UL_tti UL_tti_req->SFN, UL_tti_req->Slot); nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[i].prach_pdu; + LOG_D(NR_PHY_RACH, "Add prach decoding request for %d.%d\n", UL_tti_req->SFN, UL_tti_req->Slot); prach_item_t *prach = nr_fill_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu); if (prach && (gNB->RU_list[0]->if_south == LOCAL_RF || gNB->RU_list[0]->if_south == REMOTE_IF5)) nr_fill_prach_ru(gNB->RU_list[0], prach); diff --git a/openair1/SCHED_NR/nr_prach_procedures.c b/openair1/SCHED_NR/nr_prach_procedures.c index db01294da5..caaa579ad0 100644 --- a/openair1/SCHED_NR/nr_prach_procedures.c +++ b/openair1/SCHED_NR/nr_prach_procedures.c @@ -64,8 +64,8 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac return; } - LOG_D(NR_PHY, "%d.%d Got prach entry\n", frame, slot); nfapi_nr_prach_pdu_t *prach_pdu = &prach_id->pdu; + LOG_D(NR_PHY_RACH, "%d.%d, prachstart slot %d prach entry occas %d\n", frame, slot, prach_id->slot, prach_pdu->num_prach_ocas); const int prach_start_slot = prach_id->slot; int N_dur = get_nr_prach_duration(prach_pdu->prach_format); @@ -137,7 +137,7 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac gNB->prach_energy_counter++; } // if prach_id>0 rach_ind->slot = prach_start_slot; - LOG_D(NR_PHY, "Freeing PRACH entry\n"); + LOG_D(NR_PHY_RACH, "Freeing PRACH entry\n"); free_nr_prach_entry(&gNB->prach_list, prach_id); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,0); } From d745e6fcd313fa18f98b48b86dd46b24571b9440 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Fri, 19 Sep 2025 15:08:26 +0200 Subject: [PATCH 17/23] Make the decidated structure the PRACH decoding values contextual The function rx_nr_prach become autonomous, it doesn't read anymore global variables So, it can become (later) a threadpool work, that will send a message when it finishes rx_nr_prach_ru() still use some global variables, but it is executed in sequence, inside the ru main loop, that limits the probability of race conditions --- executables/nr-ru.c | 52 +-- openair1/PHY/NR_TRANSPORT/nr_prach.c | 366 +++++++++--------- .../PHY/NR_TRANSPORT/nr_transport_proto.h | 24 +- openair1/PHY/defs_common.h | 11 + openair1/SCHED_NR/fapi_nr_l1.c | 4 + openair1/SCHED_NR/nr_prach_procedures.c | 41 +- openair1/SIMULATION/NR_PHY/prachsim.c | 114 ++++-- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 7 +- 8 files changed, 314 insertions(+), 305 deletions(-) diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 60270d9d0f..9e4e6a5384 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -1034,7 +1034,7 @@ void *ru_thread(void *param) RU_t *ru = (RU_t *)param; RU_proc_t *proc = &ru->proc; NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; - PHY_VARS_gNB *gNB = RC.gNB[0]; + PHY_VARS_gNB *gNB = RC.gNB[0]; // this RU main loop handes only one RU int ret; int slot = fp->slots_per_frame-1; int frame = 1023; @@ -1047,7 +1047,7 @@ void *ru_thread(void *param) // set default return value sprintf(threadname,"ru_thread %u",ru->idx); LOG_I(PHY,"Starting RU %d (%s,%s) on cpu %d\n",ru->idx,NB_functions[ru->function],NB_timing[ru->if_timing],sched_getcpu()); - ru->config = RC.gNB[0]->gNB_config; + ru->config = gNB->gNB_config; nr_init_frame_parms(&ru->config, fp); nr_dump_frame_parms(fp); @@ -1179,12 +1179,17 @@ void *ru_thread(void *param) proc->timestamp_tx += fp->get_samples_per_slot(i % fp->slots_per_frame, fp); proc->tti_tx = (proc->tti_rx + ru->sl_ahead) % fp->slots_per_frame; proc->frame_tx = proc->tti_rx > proc->tti_tx ? (proc->frame_rx + 1) & 1023 : proc->frame_rx; - LOG_D(PHY,"AFTER fh_south_in - SFN/SL:%d%d RU->proc[RX:%d.%d TX:%d.%d] RC.gNB[0]:[RX:%d%d TX(SFN):%d]\n", - frame,slot, - proc->frame_rx,proc->tti_rx, - proc->frame_tx,proc->tti_tx, - RC.gNB[0]->proc.frame_rx,RC.gNB[0]->proc.slot_rx, - RC.gNB[0]->proc.frame_tx); + LOG_D(PHY, + "AFTER fh_south_in - SFN/SL:%d%d RU->proc[RX:%d.%d TX:%d.%d] RC.gNB[0]:[RX:%d%d TX(SFN):%d]\n", + frame, + slot, + proc->frame_rx, + proc->tti_rx, + proc->frame_tx, + proc->tti_tx, + gNB->proc.frame_rx, + gNB->proc.slot_rx, + gNB->proc.frame_tx); if (ru->idx != 0) proc->frame_tx = (proc->frame_tx + proc->frame_offset) & 1023; @@ -1199,7 +1204,7 @@ void *ru_thread(void *param) LOG_D(NR_PHY, "Setting %d.%d (%d) to busy\n", proc->frame_rx, proc->tti_rx, proc->tti_rx % RU_RX_SLOT_DEPTH); //LOG_M("rxdata.m","rxs",ru->common.rxdata[0],1228800,1,1); LOG_D(PHY,"RU proc: frame_rx = %d, tti_rx = %d\n", proc->frame_rx, proc->tti_rx); - gNBscopeCopy(RC.gNB[0], + gNBscopeCopy(gNB, gNBRxdataF, ru->common.rxdataF[0], sizeof(c16_t), @@ -1208,33 +1213,12 @@ void *ru_thread(void *param) proc->tti_rx * gNB->frame_parms.samples_per_slot_wCP); // Do PRACH RU processing - prach_item_t *p = find_nr_prach(&ru->prach_list, proc->frame_rx, proc->tti_rx, SEARCH_EXIST); + prach_item_t *p = find_nr_prach(&gNB->prach_list, proc->frame_rx, proc->tti_rx, SEARCH_EXIST); if (p) { 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_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 - 1, fp) + fp->get_samples_per_slot(proc->tti_rx, fp)) * 4)); - int N_dur = get_nr_prach_duration(p->pdu.prach_format); - LOG_D(NR_PHY_RACH, "%d.%d try to decode %d occasions \n", frame, slot, p->pdu.num_prach_ocas); - for (int prach_oc = 0; prach_oc < p->pdu.num_prach_ocas; prach_oc++) { - int prachStartSymbol = p->pdu.prach_start_symbol + prach_oc * N_dur; - int beam_id = p->beams[prach_oc]; - //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, - p->pdu.prach_format, // could also use format - p->pdu.num_ra, - beam_id, - prachStartSymbol, - p->slot, - prach_oc, - proc->frame_rx, - proc->tti_rx); - } - free_nr_prach_entry(&ru->prach_list, p); + // this fills ru->prach_rxsigF for processing by gNB + p->rxsigF = (c16_t ***)ru->prach_rxsigF; + rx_nr_prach_ru(p, ru->common.rxdata, ru->nr_frame_parms, ru->N_TA_offset); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 0); } // end if (prach_id >= 0) } // end if (ru->feprx) diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 425e20dd84..0bdb538f20 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -87,9 +87,8 @@ prach_item_t *nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach return NULL; } const int fmt = prach_pdu->prach_format; - *prach = (prach_item_t){.frame = SFN, - .slot = Slot, - .num_slots = (fmt < 4) ? get_long_prach_dur(fmt, gNB->frame_parms.numerology_index) : 1}; + NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; + *prach = (prach_item_t){.frame = SFN, .slot = Slot, .num_slots = (fmt < 4) ? get_long_prach_dur(fmt, fp->numerology_index) : 1}; if (gNB->common_vars.beam_id) { int n_symb = get_nr_prach_duration(prach_pdu->prach_format); AssertFatal(prach_pdu->beamforming.dig_bf_interface < NFAPI_MAX_NUM_BG_IF, @@ -109,6 +108,18 @@ prach_item_t *nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach } } prach->pdu = *prach_pdu; + nfapi_nr_prach_config_t *cfg = &gNB->gNB_config.prach_config; + nfapi_nr_num_prach_fd_occasions_t *occ = &cfg->num_prach_fd_occasions_list[prach_pdu->num_ra]; + prach->rootSequenceIndex = occ->prach_root_sequence_index.value; + prach->numrootSequenceIndex = occ->num_root_sequences.value; + prach->msg1_frequencystart = occ->k1.value; + prach->mu = cfg->prach_sub_c_spacing.value; + prach->prach_sequence_length = cfg->prach_sequence_length.value; + prach->restricted_set = cfg->restricted_set_config.value; + prach->numerology_index = fp->numerology_index; + prach->nb_rx = gNB->gNB_config.carrier_config.num_rx_ant.value; + prach->Xu = gNB->X_u; + prach->rx_prach = &gNB->rx_prach; return prach; } @@ -122,152 +133,140 @@ void nr_fill_prach_ru(RU_t *ru, prach_item_t *gnb_prach) *prach = *gnb_prach; } -void rx_nr_prach_ru(RU_t *ru, - int prachFormat, - int numRA, - int beam, - int prachStartSymbol, - int prachStartSlot, - int prachOccasion, - int frame, - int slot) +static void rx_nr_prach_ru_internal(prach_item_t *p, + int beam_id, + int prachStartSymbol, + int prachOccasion, + int32_t **rxdata, + NR_DL_FRAME_PARMS *fp, + int N_TA_offset) { - AssertFatal(ru != NULL,"ru is null\n"); - - NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; - 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; - const uint8_t prach_mu = ru->config.prach_config.prach_sub_c_spacing.value; - int sample_offset_slot; + const int sum = fp->ofdm_symbol_size + fp->nb_prefix_samples; + const int sum0 = fp->ofdm_symbol_size + fp->nb_prefix_samples0; if (prachStartSymbol == 0) { sample_offset_slot = 0; } else if (fp->slots_per_subframe == 1) { if (prachStartSymbol <= 7) - sample_offset_slot = (fp->ofdm_symbol_size + fp->nb_prefix_samples) * (prachStartSymbol - 1) + (fp->ofdm_symbol_size + fp->nb_prefix_samples0); + sample_offset_slot = sum * (prachStartSymbol - 1) + sum0; else - sample_offset_slot = (fp->ofdm_symbol_size + fp->nb_prefix_samples) * (prachStartSymbol - 2) + (fp->ofdm_symbol_size + fp->nb_prefix_samples0) * 2; + sample_offset_slot = sum * (prachStartSymbol - 2) + sum0 * 2; } else { - if (!(slot%(fp->slots_per_subframe/2))) - sample_offset_slot = (fp->ofdm_symbol_size + fp->nb_prefix_samples) * (prachStartSymbol - 1) + (fp->ofdm_symbol_size + fp->nb_prefix_samples0); + if (!(p->slot % (fp->slots_per_subframe / 2))) + sample_offset_slot = sum * (prachStartSymbol - 1) + sum0; else - sample_offset_slot = (fp->ofdm_symbol_size + fp->nb_prefix_samples) * prachStartSymbol; + sample_offset_slot = sum * prachStartSymbol; } LOG_D(PHY, "frame %d, slot %d: doing rx_nr_prach_ru for format %d, numRA %d, prachStartSymbol %d, prachOccasion %d\n", - frame, - slot, - prachFormat, - numRA, + p->frame, + p->slot, + p->pdu.prach_format, + p->pdu.num_ra, prachStartSymbol, prachOccasion); - AssertFatal(ru->if_south == LOCAL_RF || ru->if_south == REMOTE_IF5, - "we shouldn't call this if if_south != LOCAL_RF or REMOTE_IF5\n"); int reps; int Ncp; int dftlen; - int mu = fp->numerology_index; + int mu = p->numerology_index; - if (prach_sequence_length == 0) { + if (p->prach_sequence_length == 0) { LOG_D(PHY, - "PRACH (ru %d) in %d.%d, format %d, msg1_frequencyStart %d\n", - ru->idx, - frame, - prachStartSlot, - prachFormat, - msg1_frequencystart); - switch (prachFormat) { - case 0: - reps = 1; - Ncp = 3168; - dftlen = 24576; - break; + "PRACH in %d.%d, format %d, msg1_frequencyStart %d\n", + p->frame, + p->slot, + p->pdu.prach_format, + p->msg1_frequencystart); + switch (p->pdu.prach_format) { + case 0: + reps = 1; + Ncp = 3168; + dftlen = 24576; + break; - case 1: - reps = 2; - Ncp = 21024; - dftlen = 24576; - break; + case 1: + reps = 2; + Ncp = 21024; + dftlen = 24576; + break; - case 2: - reps = 4; - Ncp = 4688; - dftlen = 24576; - break; + case 2: + reps = 4; + Ncp = 4688; + dftlen = 24576; + break; - case 3: - reps = 4; - Ncp = 3168; - dftlen = 6144; - break; + case 3: + reps = 4; + Ncp = 3168; + dftlen = 6144; + break; - default: - AssertFatal(1==0, "Illegal prach format %d for length 839\n", prachFormat); - break; + default: + AssertFatal(1 == 0, "Illegal prach format %d for length 839\n", p->pdu.prach_format); + break; } - } - else { + } else { LOG_D(PHY, - "PRACH (ru %d) in %d.%d, format %s, msg1_frequencyStart %d,startSymbol %d\n", - ru->idx, - frame, - slot, - prachfmt[prachFormat], - msg1_frequencystart, - prachStartSymbol); - switch (prachFormat) { - case 4: //A1 - reps = 2; - Ncp = 288 >> mu; - break; + "PRACH in %d.%d, format %s, msg1_frequencyStart %d,startSymbol %d\n", + p->frame, + p->slot, + prachfmt[p->pdu.prach_format], + p->msg1_frequencystart, + prachStartSymbol); + switch (p->pdu.prach_format) { + case 4: // A1 + reps = 2; + Ncp = 288 >> mu; + break; - case 5: //A2 - reps = 4; - Ncp = 576 >> mu; - break; + case 5: // A2 + reps = 4; + Ncp = 576 >> mu; + break; - case 6: //A3 - reps = 6; - Ncp = 864 >> mu; - break; + case 6: // A3 + reps = 6; + Ncp = 864 >> mu; + break; - case 7: //B1 - reps = 2; - Ncp = 216 >> mu; - break; + case 7: // B1 + reps = 2; + Ncp = 216 >> mu; + break; - /* - // B2 and B3 do not exist in FAPI - case 4: //B2 - reps = 4; - Ncp = 360 >> mu; - break; + /* + // B2 and B3 do not exist in FAPI + case 4: //B2 + reps = 4; + Ncp = 360 >> mu; + break; - case 5: //B3 - reps = 6; - Ncp = 504 >> mu; - break; - */ + case 5: //B3 + reps = 6; + Ncp = 504 >> mu; + break; + */ - case 8: //B4 - reps = 12; - Ncp = 936 >> mu; - break; + case 8: // B4 + reps = 12; + Ncp = 936 >> mu; + break; - case 9: //C0 - reps = 1; - Ncp = 1240 >> mu; - break; + case 9: // C0 + reps = 1; + Ncp = 1240 >> mu; + break; - case 10: //C2 - reps = 4; - Ncp = 2048 >> mu; - break; + case 10: // C2 + reps = 4; + Ncp = 2048 >> mu; + break; - default: - AssertFatal(1==0,"unknown prach format %x\n",prachFormat); - break; + default: + AssertFatal(1 == 0, "unknown prach format %x\n", p->pdu.prach_format); + break; } dftlen = 2048 >> mu; } @@ -275,12 +274,11 @@ void rx_nr_prach_ru(RU_t *ru, //actually what we should be checking here is how often the current prach crosses a 0.5ms boundary. //I am not quite sure for which paramter set this would be the case, //so I will ignore it for now and just check if the prach starts on a 0.5ms boundary - if(fp->numerology_index == 0) { + if (p->numerology_index == 0) { if (prachStartSymbol == 0 || prachStartSymbol == 7) Ncp += 16; - } - else { - if (slot%(fp->slots_per_subframe/2)==0 && prachStartSymbol == 0) + } else { + if (p->slot % (fp->slots_per_subframe / 2) == 0 && prachStartSymbol == 0) Ncp += 16; } @@ -351,27 +349,27 @@ void rx_nr_prach_ru(RU_t *ru, // Do forward transform if (LOG_DEBUGFLAG(DEBUG_PRACH)) { - 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", p->nb_rx, Ncp, dftlen); } - const unsigned int K = get_prach_K(prach_sequence_length, prachFormat, fp->numerology_index, prach_mu); - const uint8_t kbar = get_PRACH_k_bar(prach_mu, fp->numerology_index); + const unsigned int K = get_prach_K(p->prach_sequence_length, p->pdu.prach_format, p->numerology_index, p->mu); + const uint8_t kbar = get_PRACH_k_bar(p->mu, p->numerology_index); - int n_ra_prb = msg1_frequencystart; + int n_ra_prb = p->msg1_frequencystart; int k = (12*n_ra_prb) - 6*fp->N_RB_UL; - int N_ZC = (prach_sequence_length == 0) ? 839 : 139; + int N_ZC = (p->prach_sequence_length == 0) ? 839 : 139; if (k<0) k+=(fp->ofdm_symbol_size); k*=K; k+=kbar; - for (int aa=0; aanb_rx; aa++) { - int slot2 = prach_sequence_length ? slot : prachStartSlot; - int idx = aa + beam * ru->nb_rx; - c16_t *prach = - (c16_t *)&ru->common.rxdata[idx][fp->get_samples_slot_timestamp(slot2, fp, 0) + sample_offset_slot - ru->N_TA_offset]; + for (int aa = 0; aa < p->nb_rx; aa++) { + // Fixme: slot or slot makes no sense ??? + int slot2 = p->prach_sequence_length ? p->slot : p->slot; + int idx = aa + beam_id * p->nb_rx; + c16_t *prach = (c16_t *)&rxdata[idx][fp->get_samples_slot_timestamp(slot2, fp, 0) + sample_offset_slot - N_TA_offset]; // do DFT c16_t *prach2 = prach + Ncp; @@ -390,60 +388,56 @@ void rx_nr_prach_ru(RU_t *ru, rxsigF_tmp[j] = c16add(rxsigF_tmp[j], tmp[k2]); } } - memcpy(ru->prach_rxsigF[prachOccasion][aa], rxsigF_tmp, sizeof(rxsigF_tmp)); + memcpy(p->rxsigF[prachOccasion][aa], rxsigF_tmp, sizeof(rxsigF_tmp)); } } -void rx_nr_prach(PHY_VARS_gNB *gNB, - nfapi_nr_prach_pdu_t *prach_pdu, - int frame, - int slot, - uint16_t *max_preamble, - uint16_t *max_preamble_energy, - uint16_t *max_preamble_delay, - c16_t **rxsigF) +void rx_nr_prach_ru(prach_item_t *p, int32_t **rxdata, NR_DL_FRAME_PARMS *fp, int N_TA_offset) { - AssertFatal(gNB != NULL, "Can only be called from gNB\n"); - nfapi_nr_prach_config_t *cfg = &gNB->gNB_config.prach_config; + int N_dur = get_nr_prach_duration(p->pdu.prach_format); + LOG_D(NR_PHY_RACH, "%d.%d try to decode %d occasions \n", p->frame, p->slot, p->pdu.num_prach_ocas); + for (int prach_oc = 0; prach_oc < p->pdu.num_prach_ocas; prach_oc++) { + int prachStartSymbol = p->pdu.prach_start_symbol + prach_oc * N_dur; + int beam_id = p->beams[prach_oc]; + // 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_internal(p, beam_id, prachStartSymbol, prach_oc, rxdata, fp, N_TA_offset); + } +} + +rx_prach_out_t rx_nr_prach(const prach_item_t *in, int occasion) +{ + rx_prach_out_t out = {}; + c16_t **input = in->rxsigF[occasion]; uint16_t preamble_index0 = 0; uint16_t numshift = 0; int first_nonzero_root_idx = 0; bool new_dft = false; int log2_ifft_size = 10; - NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; - - const int nb_rx = gNB->gNB_config.carrier_config.num_rx_ant.value; - const int rootSequenceIndex = cfg->num_prach_fd_occasions_list[prach_pdu->num_ra].prach_root_sequence_index.value; - const int numrootSequenceIndex = cfg->num_prach_fd_occasions_list[prach_pdu->num_ra].num_root_sequences.value; - const int NCS = prach_pdu->num_cs; // cfg->num_prach_fd_occasions_list[0].prach_zero_corr_conf.value; - const int prach_sequence_length = cfg->prach_sequence_length.value; - const int msg1_frequencystart = cfg->num_prach_fd_occasions_list[prach_pdu->num_ra].k1.value; - const int restricted_set = cfg->restricted_set_config.value; - const int prach_fmt = prach_pdu->prach_format; - const int N_ZC = prach_sequence_length == 0 ? 839 : 139; + const int nb_rx = in->nb_rx; + const int NCS = in->pdu.num_cs; + const int prach_fmt = in->pdu.prach_format; + const int N_ZC = in->prach_sequence_length == 0 ? 839 : 139; LOG_D(NR_PHY_RACH, "L1 PRACH RX: rooSequenceIndex %d, numRootSeqeuences %d, NCS %d, N_ZC %d, format %d \n", - rootSequenceIndex, - numrootSequenceIndex, + in->rootSequenceIndex, + in->numrootSequenceIndex, NCS, N_ZC, prach_fmt); if (LOG_DEBUGFLAG(DEBUG_PRACH)) { - if ((frame & 1023) < 20) - LOG_D(PHY, - "PRACH (gNB) : running rx_prach for slot %d, msg1_frequencystart %d, rootSequenceIndex %d\n", - slot, - msg1_frequencystart, - rootSequenceIndex); + if ((in->frame & 1023) < 20) + LOG_D(PHY, "PRACH (gNB) : running rx_prach for slot %d, rootSequenceIndex %d\n", in->slot, in->rootSequenceIndex); } - start_meas(&gNB->rx_prach); + start_meas(in->rx_prach); const uint16_t *prach_root_sequence_map = - cfg->prach_sequence_length.value == 0 ? prach_root_sequence_map_0_3 : prach_root_sequence_map_abc; + in->prach_sequence_length == 0 ? prach_root_sequence_map_0_3 : prach_root_sequence_map_abc; // PDP is oversampled, e.g. 1024 sample instead of 839 // Adapt the NCS (zero-correlation zones) with oversampling factor e.g. 1024/839 @@ -454,19 +448,16 @@ void rx_nr_prach(PHY_VARS_gNB *gNB, int preamble_offset = 0, preamble_offset_old = 99; - *max_preamble_energy = 0; - *max_preamble_delay = 0; - *max_preamble = 0; int16_t preamble_shift = 0; const int dft_sz = N_ZC == 839 ? 1024 : 256; int32_t prach_ifft[dft_sz] __attribute__((aligned(32))); for (int preamble_index = 0; preamble_index < 64; preamble_index++) { if (LOG_DEBUGFLAG(DEBUG_PRACH)) { - int en = dB_fixed(signal_energy((int32_t *)rxsigF[0], N_ZC == 839 ? 840 : 140)); + int en = dB_fixed(signal_energy((int32_t *)input[0], N_ZC == 839 ? 840 : 140)); if (en > 60) - LOG_D(PHY, "frame %d, slot %d : Trying preamble %d \n", frame, slot, preamble_index); + LOG_D(PHY, "frame %d, slot %d : Trying preamble %d \n", in->frame, in->slot, preamble_index); } - if (restricted_set == 0) { + if (in->restricted_set == 0) { // This is the relative offset in the root sequence table (5.7.2-4 from 36.211) for the given preamble index preamble_offset = ((NCS==0)? preamble_index : (preamble_index/(N_ZC/NCS))); @@ -495,7 +486,7 @@ void rx_nr_prach(PHY_VARS_gNB *gNB, preamble_index0 -= numshift; while (not_found) { // current root depending on rootSequenceIndex - int index = (rootSequenceIndex + preamble_offset) % N_ZC; + int index = (in->rootSequenceIndex + preamble_offset) % N_ZC; int u = nr_du[prach_root_sequence_map[index]]; uint16_t n_group_ra = 0; @@ -538,12 +529,12 @@ void rx_nr_prach(PHY_VARS_gNB *gNB, // Compute DFT of RX signal (conjugate input, results in conjugate output) for each new rootSequenceIndex if (LOG_DEBUGFLAG(DEBUG_PRACH)) { - int en = dB_fixed(signal_energy((int32_t *)rxsigF[0], 840)); + int en = dB_fixed(signal_energy((int32_t *)input[0], 840)); if (en>60) LOG_D(PHY, "frame %d, slot %d : preamble index %d, NCS %d, N_ZC/NCS %d: offset %d, preamble shift %d , en %d)\n", - frame, - slot, + in->frame, + in->slot, preamble_index, NCS, N_ZC / NCS, @@ -562,19 +553,19 @@ void rx_nr_prach(PHY_VARS_gNB *gNB, if (new_dft) { new_dft = false; - c16_t *Xu = (c16_t *)gNB->X_u[preamble_offset - first_nonzero_root_idx]; + c16_t *Xu = in->Xu[preamble_offset - first_nonzero_root_idx]; LOG_D(PHY,"PRACH RX new dft preamble_offset-first_nonzero_root_idx %d\n",preamble_offset-first_nonzero_root_idx); memset(prach_ifft, 0, sizeof(prach_ifft)); if (LOG_DUMPFLAG(DEBUG_PRACH)) { - LOG_M("prach_rxF0.m","prach_rxF0",rxsigF[0],N_ZC,1,1); - LOG_M("prach_rxF1.m","prach_rxF1",rxsigF[1],6144,1,1); + LOG_M("prach_rxF0.m", "prach_rxF0", input[0], N_ZC, 1, 1); + LOG_M("prach_rxF1.m", "prach_rxF1", input[1], 6144, 1, 1); } c16_t prachF[dft_sz] __attribute__((aligned(32))); for (int aa = 0; aa < nb_rx; aa++) { // Do componentwise product with Xu* on each antenna for (int offset = 0; offset < N_ZC; offset++) { - prachF[offset] = c16MulConjShift(Xu[offset], rxsigF[aa][offset], 15); + prachF[offset] = c16MulConjShift(Xu[offset], input[aa][offset], 15); } memset(prachF + N_ZC, 0, sizeof(*prachF) * (dft_sz - N_ZC)); // Now do IFFT of size 1024 (N_ZC=839) or 256 (N_ZC=139) @@ -613,11 +604,11 @@ void rx_nr_prach(PHY_VARS_gNB *gNB, for (int i = 0; i < NCS2; i++) { int lev = prach_ifft[preamble_shift2 + i]; int levdB = dB_fixed_times10(lev); - if (levdB > *max_preamble_energy || (levdB == *max_preamble_energy && *max_preamble_delay > i)) { - LOG_D(NR_PHY_RACH, "preamble_index %d, delay %d en %d dB > %d dB\n", preamble_index, i, levdB, *max_preamble_energy); - *max_preamble_energy = levdB; - *max_preamble_delay = i; // Note: This has to be normalized to the 30.72 Ms/s sampling rate - *max_preamble = preamble_index; + if (levdB > out.max_preamble_energy || (levdB == out.max_preamble_energy && out.max_preamble_delay > i)) { + LOG_D(NR_PHY_RACH, "preamble_index %d, delay %d en %d dB > %d dB\n", preamble_index, i, levdB, out.max_preamble_energy); + out.max_preamble_energy = levdB; + out.max_preamble_delay = i; // Note: This has to be normalized to the 30.72 Ms/s sampling rate + out.max_preamble = preamble_index; } } } // preamble_index @@ -637,16 +628,15 @@ void rx_nr_prach(PHY_VARS_gNB *gNB, // Format >3: 2048/2^mu samples @ 30.72 Ms/s, 2048/2^mu * 4 samples @ 122.88 Ms/s // By solving: // max_preamble_delay * ( (2048/2^mu*(fs/30.72M)) / 256 ) / fs = TA * 16 * 64 / 2^mu * Tc - uint16_t *TA = max_preamble_delay; - int mu = fp->numerology_index; - if (cfg->prach_sequence_length.value == 0) { + int mu = in->numerology_index; + if (in->prach_sequence_length == 0) { if (prach_fmt == 0 || prach_fmt == 1 || prach_fmt == 2) - *TA = *TA * 3 * (1 << mu) / 2; + out.max_preamble_delay *= 3 * (1 << mu) / 2; else if (prach_fmt == 3) - *TA = *TA * 3 * (1 << mu) / 8; - } - else *TA = *TA/2; - - stop_meas(&gNB->rx_prach); + out.max_preamble_delay *= 3 * (1 << mu) / 8; + } else + out.max_preamble_delay /= 2; + stop_meas(in->rx_prach); + return out; } diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index 2cbe1fde77..fd0a36536d 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -202,24 +202,14 @@ void nr_fill_ulsch(PHY_VARS_gNB *gNB, prach_item_t *nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu); -void rx_nr_prach(PHY_VARS_gNB *gNB, - nfapi_nr_prach_pdu_t *prach_pdu, - int frame, - int subframe, - uint16_t *max_preamble, - uint16_t *max_preamble_energy, - uint16_t *max_preamble_delay, - c16_t **rxsigF); +typedef struct rx_prach_out { + uint16_t max_preamble; + uint16_t max_preamble_energy; + uint16_t max_preamble_delay; +} rx_prach_out_t; +rx_prach_out_t rx_nr_prach(const prach_item_t *, int occasion); -void rx_nr_prach_ru(RU_t *ru, - int prach_fmt, - int numRA, - int beam, - int prachStartSymbol, - int prachStartSlot, - int prachOccasion, - int frame, - int subframe); +void rx_nr_prach_ru(prach_item_t *, int32_t **, NR_DL_FRAME_PARMS *frame_parms, int N_TA_offset); void nr_fill_prach_ru(RU_t *ru,prach_item_t * ); prach_item_t *find_nr_prach(prach_list_t *, int frame, int slot, find_type_t type); diff --git a/openair1/PHY/defs_common.h b/openair1/PHY/defs_common.h index b469555354..efaccf2bf7 100644 --- a/openair1/PHY/defs_common.h +++ b/openair1/PHY/defs_common.h @@ -1007,6 +1007,17 @@ typedef struct { int num_slots; // prach duration in slots int beams[NFAPI_MAX_NUM_BG_IF]; nfapi_nr_prach_pdu_t pdu; + int rootSequenceIndex; + int numrootSequenceIndex; + int msg1_frequencystart; + int mu; + int prach_sequence_length; + int restricted_set; + int numerology_index; + int nb_rx; + c16_t ***rxsigF; + c16_t (*Xu)[839]; + time_stats_t *rx_prach; } prach_item_t; typedef struct { diff --git a/openair1/SCHED_NR/fapi_nr_l1.c b/openair1/SCHED_NR/fapi_nr_l1.c index ad6f90e6e8..4ec87a1e5f 100644 --- a/openair1/SCHED_NR/fapi_nr_l1.c +++ b/openair1/SCHED_NR/fapi_nr_l1.c @@ -156,8 +156,12 @@ void nr_schedule_ul_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_tti_request_t *UL_tti nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[i].prach_pdu; LOG_D(NR_PHY_RACH, "Add prach decoding request for %d.%d\n", UL_tti_req->SFN, UL_tti_req->Slot); prach_item_t *prach = nr_fill_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu); + if (!prach) + LOG_W(NR_PHY_RACH, "Error in scheduling rach\n"); + /* the present design is not supporting multiple gNB in one RU if (prach && (gNB->RU_list[0]->if_south == LOCAL_RF || gNB->RU_list[0]->if_south == REMOTE_IF5)) nr_fill_prach_ru(gNB->RU_list[0], prach); + */ break; case NFAPI_NR_UL_CONFIG_SRS_PDU_TYPE: LOG_D(NR_PHY, diff --git a/openair1/SCHED_NR/nr_prach_procedures.c b/openair1/SCHED_NR/nr_prach_procedures.c index caaa579ad0..e6cd15b4a9 100644 --- a/openair1/SCHED_NR/nr_prach_procedures.c +++ b/openair1/SCHED_NR/nr_prach_procedures.c @@ -49,16 +49,11 @@ int get_nr_prach_duration(uint8_t prach_format) void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rach_indication_t *rach_ind) { - uint16_t max_preamble[4]={0},max_preamble_energy[4]={0},max_preamble_delay[4]={0}; - - RU_t *ru; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_ENB_PRACH_RX,1); rach_ind->sfn = frame; rach_ind->slot = slot; rach_ind->number_of_pdus = 0; - ru=gNB->RU_list[0]; - prach_item_t *prach_id = find_nr_prach(&gNB->prach_list, frame, slot, SEARCH_EXIST); if (!prach_id) { return; @@ -74,11 +69,7 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac // 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}. - - c16_t *rxsigF[ru->nb_rx]; - for (int i = 0; i < ru->nb_rx; ++i) - rxsigF[i] = (c16_t *)ru->prach_rxsigF[prach_oc][i]; - rx_nr_prach(gNB, prach_pdu, frame, slot, max_preamble, max_preamble_energy, max_preamble_delay, rxsigF); + rx_prach_out_t res = rx_nr_prach(prach_id, prach_oc); LOG_D(NR_PHY, "[RAPROC] Frame %d, slot %d, occasion %d (prachStartSymbol %d) : Most likely preamble %d, energy %d.%d dB delay %d " "(prach_energy counter %d)\n", @@ -86,26 +77,26 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac slot, prach_oc, prachStartSymbol, - max_preamble[0], - max_preamble_energy[0] / 10, - max_preamble_energy[0] % 10, - max_preamble_delay[0], + res.max_preamble, + res.max_preamble_energy / 10, + res.max_preamble_energy % 10, + res.max_preamble_delay, gNB->prach_energy_counter); if ((gNB->prach_energy_counter == NUM_PRACH_RX_FOR_NOISE_ESTIMATE) - && (max_preamble_energy[0] > gNB->measurements.prach_I0 + gNB->prach_thres) + && (res.max_preamble_energy > gNB->measurements.prach_I0 + gNB->prach_thres) && (rach_ind->number_of_pdus < MAX_NUM_NR_RX_RACH_PDUS)) { LOG_A(NR_PHY, "[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", frame, prach_start_slot, - max_preamble[0], - max_preamble_energy[0] / 10, - max_preamble_energy[0] % 10, + res.max_preamble, + res.max_preamble_energy / 10, + res.max_preamble_energy % 10, gNB->measurements.prach_I0, gNB->prach_thres, - max_preamble_delay[0], + res.max_preamble_delay, prachStartSymbol, prach_pdu->num_ra); @@ -113,9 +104,9 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac T_INT(gNB->Mod_id), T_INT(frame), T_INT(slot), - T_INT(max_preamble[0]), - T_INT(max_preamble_energy[0]), - T_INT(max_preamble_delay[0])); + T_INT(res.max_preamble), + T_INT(res.max_preamble_energy), + T_INT(res.max_preamble_delay)); nfapi_nr_prach_indication_pdu_t *ind = rach_ind->pdu_list + rach_ind->number_of_pdus; *ind = (nfapi_nr_prach_indication_pdu_t){ @@ -123,14 +114,14 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac .symbol_index = prachStartSymbol, .slot_index = slot, .freq_index = prach_pdu->num_ra, - .avg_rssi = (max_preamble_energy[0] < 631) ? (128 + (max_preamble_energy[0] / 5)) : 254, + .avg_rssi = (res.max_preamble_energy < 631) ? (128 + (res.max_preamble_energy / 5)) : 254, .avg_snr = 0xff, // invalid for now .num_preamble = 1, .preamble_list = { - {.preamble_index = max_preamble[0], .timing_advance = max_preamble_delay[0], .preamble_pwr = 0xffffffff}}}; + {.preamble_index = res.max_preamble, .timing_advance = res.max_preamble_delay, .preamble_pwr = 0xffffffff}}}; rach_ind->number_of_pdus++; } - gNB->measurements.prach_I0 = ((gNB->measurements.prach_I0 * 900) >> 10) + ((max_preamble_energy[0] * 124) >> 10); + gNB->measurements.prach_I0 = ((gNB->measurements.prach_I0 * 900) >> 10) + ((res.max_preamble_energy * 124) >> 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 < NUM_PRACH_RX_FOR_NOISE_ESTIMATE) diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c index e5f64fff5d..7d87ac54a7 100644 --- a/openair1/SIMULATION/NR_PHY/prachsim.c +++ b/openair1/SIMULATION/NR_PHY/prachsim.c @@ -135,10 +135,11 @@ int main(int argc, char **argv){ double **s_re, **s_im, **r_re, **r_im, iqim = 0.0, delay_avg = 0, ue_speed = 0, fs=-1, bw; int i, l, aa, aarx, trial, n_frames = 1, rx_prach_start; //, ntrials=1; 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; + int N_RB_UL = 106, delay = 0, NCS_config = 13, rootSequenceIndex = 1, threequarter_fs = 0, mu = 1, fd_occasion = 0, + loglvl = OAILOG_INFO; 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; - uint16_t Nid_cell = 0, preamble_tx = 0, preamble_delay, format0, format1; + uint16_t Nid_cell = 0, preamble_tx = 0, format0, format1; uint32_t tx_lev = 10000, prach_errors = 0; //,tx_lev_dB; uint64_t SSB_positions = 0x01; uint16_t RA_sfn_index; @@ -714,9 +715,17 @@ int main(int argc, char **argv){ } rx_prach_start = subframe*frame_parms->samples_per_subframe; - if (n_frames==1) printf("slot %d, rx_prach_start %d\n",slot,rx_prach_start); - uint16_t preamble_rx, preamble_energy; + if (n_frames == 1) + printf("slot %d, rx_prach_start %d\n", slot, rx_prach_start); + c16_t **rxsigF[NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX]; + for (int j = 0; j < NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX; j++) { + rxsigF[j] = malloc(ru->nb_rx * sizeof(*rxsigF)); + for (int i = 0; i < ru->nb_rx; i++) { + // largest size for PRACH FFT is 4x98304 (16*24576) + rxsigF[j][i] = malloc16_clear(4 * 98304 * sizeof(**rxsigF)); + } + } for (SNR = snr0; SNR < snr1 && !stop; SNR += .1) { for (ue_speed = ue_speed0; ue_speed < ue_speed1 && !stop; ue_speed += 10) { @@ -727,8 +736,7 @@ int main(int argc, char **argv){ prach_errors=0; for (trial = 0; trial < n_frames && !stop; trial++) { - - if (input_fd==NULL) { + if (input_fd == NULL) { sigma2_dB = 10*log10((double)tx_lev) - SNR - 10*log10(N_RB_UL*12/N_ZC); if (n_frames==1) @@ -755,52 +763,72 @@ int main(int argc, char **argv){ tmp->i = (short)(.167 * (r_im[aa][i] + (iqim * r_re[aa][i]) + sqrt(sigma2 / 2) * gaussdouble(0.0, 1.0))); } } - } else { - n_bytes = fread(&ru->common.rxdata[0][rx_prach_start],sizeof(int32_t),frame_parms->samples_per_subframe,input_fd); - printf("fread %d bytes from file %s\n",n_bytes,input_file); - if (n_bytes!=frame_parms->samples_per_subframe) { - printf("expected %d bytes\n",frame_parms->samples_per_subframe); - exit(-1); - } - } + } else { + n_bytes = fread(&ru->common.rxdata[0][rx_prach_start], sizeof(int32_t), frame_parms->samples_per_subframe, input_fd); + printf("fread %d bytes from file %s\n", n_bytes, input_file); + if (n_bytes != frame_parms->samples_per_subframe) { + printf("expected %d bytes\n", frame_parms->samples_per_subframe); + exit(-1); + } + } - for (l = 0; l < frame_parms->symbols_per_slot; l++) { - for (aa = 0; aa < frame_parms->nb_antennas_rx; aa++) { - nr_slot_fep_ul(frame_parms, ru->common.rxdata[aa], ru->common.rxdataF[aa], l, slot, ru->N_TA_offset); - } - } - rx_nr_prach_ru(ru, prach_format, numRA, 0, prachStartSymbol, slot, prachOccasion, frame, slot); - c16_t *rxsigF[ru->nb_rx]; - for (int i = 0; i < ru->nb_rx; ++i) - rxsigF[i] = (c16_t *)ru->prach_rxsigF[prachOccasion][i]; - if (n_frames == 1) - LOG_I(PHY, - "ncs %d,num_seq %d\n", - prach_pdu->num_cs, - prach_config->num_prach_fd_occasions_list[fd_occasion].num_root_sequences.value); - rx_nr_prach(gNB, prach_pdu, frame, subframe, &preamble_rx, &preamble_energy, &preamble_delay, rxsigF); + for (l = 0; l < frame_parms->symbols_per_slot; l++) { + for (aa = 0; aa < frame_parms->nb_antennas_rx; aa++) { + nr_slot_fep_ul(frame_parms, ru->common.rxdata[aa], ru->common.rxdataF[aa], l, slot, ru->N_TA_offset); + } + } - // printf(" preamble_energy %d preamble_rx %d preamble_tx %d \n", preamble_energy, preamble_rx, preamble_tx); + nfapi_nr_prach_config_t *cfg = &gNB->gNB_config.prach_config; + nfapi_nr_num_prach_fd_occasions_t *occ = &cfg->num_prach_fd_occasions_list[prach_pdu->num_ra]; + prach_pdu->num_prach_ocas=1; + prach_item_t in = {.frame = frame, + .slot = slot, + .pdu = *prach_pdu, + .rootSequenceIndex = occ->prach_root_sequence_index.value, + .numrootSequenceIndex = occ->num_root_sequences.value, + .msg1_frequencystart = occ->k1.value, + .mu = cfg->prach_sub_c_spacing.value, + .prach_sequence_length = cfg->prach_sequence_length.value, + .restricted_set = cfg->restricted_set_config.value, + .numerology_index = gNB->frame_parms.numerology_index, + .nb_rx = gNB->gNB_config.carrier_config.num_rx_ant.value, + .rxsigF = rxsigF, + .Xu = gNB->X_u, + .rx_prach = &gNB->rx_prach}; + rx_nr_prach_ru(&in, ru->common.rxdata, ru->nr_frame_parms, ru->N_TA_offset); + if (n_frames == 1) + LOG_I(PHY, + "ncs %d,num_seq %d\n", + prach_pdu->num_cs, + prach_config->num_prach_fd_occasions_list[fd_occasion].num_root_sequences.value); + rx_prach_out_t out = rx_nr_prach(&in, prachOccasion); - if (preamble_rx != preamble_tx) - prach_errors++; - else - delay_avg += (double)preamble_delay; + // printf(" preamble_energy %d preamble_rx %d preamble_tx %d \n", out.max_preamble_energy, out.max_preamble, + // preamble_tx); - N_ZC = (prach_sequence_length) ? 139 : 839; + if (out.max_preamble != preamble_tx) + prach_errors++; + else + delay_avg += (double)out.max_preamble_delay; - if (n_frames == 1) { - printf("preamble %d (tx %d) : energy %d, delay %d\n", preamble_rx, preamble_tx, preamble_energy, preamble_delay); + N_ZC = (prach_sequence_length) ? 139 : 839; + + if (n_frames == 1) { + printf("preamble %d (tx %d) : energy %d, delay %d\n", + out.max_preamble, + preamble_tx, + out.max_preamble_energy, + out.max_preamble_delay); #ifdef NR_PRACH_DEBUG LOG_M("prach0.m","prach0", &txdata[0][prach_start], frame_parms->samples_per_subframe, 1, 1); LOG_M("rxsig0.m","rxs0", &ru->common.rxdata[0][subframe*frame_parms->samples_per_subframe], frame_parms->samples_per_subframe, 1, 1); LOG_M("ru_rxsig0.m","rxs0", &ru->common.rxdata[0][subframe*frame_parms->samples_per_subframe], frame_parms->samples_per_subframe, 1, 1); LOG_M("ru_rxsigF0.m","rxsF0", ru->common.rxdataF[0], frame_parms->ofdm_symbol_size*frame_parms->symbols_per_slot, 1, 1); - LOG_M("ru_prach_rxsigF0.m","rxsF0", ru->prach_rxsigF[0][0], N_ZC, 1, 1); + LOG_M("ru_prach_rxsigF0.m", "rxsF0", rxsigF[0][0], N_ZC, 1, 1); LOG_M("prach_preamble.m","prachp", &gNB->X_u[0], N_ZC, 1, 1); LOG_M("ue_prach_preamble.m","prachp", &UE->X_u[0], N_ZC, 1, 1); #endif - } + } } printf("SNR %f dB, UE Speed %f km/h: errors %u/%d (delay %f)\n", SNR, ue_speed, prach_errors, n_frames, delay_avg/(double)(n_frames-prach_errors)); @@ -817,7 +845,13 @@ int main(int argc, char **argv){ if (input_fd) break; } //SNR loop - + for (int j = 0; j < NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX; j++) { + for (int i = 0; i < ru->nb_rx; i++) { + // largest size for PRACH FFT is 4x98304 (16*24576) + free(rxsigF[j][i]); + } + free(rxsigF[j]); + } free_channel_desc_scm(UE2gNB); nr_phy_free_RU(ru); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 88c9c875ea..198975f1ae 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -1430,7 +1430,12 @@ static void nr_generate_Msg2(module_id_t module_idP, scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.ra_ResponseWindow; const int n_slots_frame = nr_mac->frame_structure.numb_slots_frame; if (!msg2_in_response_window(ra->preamble_frame, ra->preamble_slot, n_slots_frame, rrc_ra_ResponseWindow, frameP, slotP)) { - LOG_E(NR_MAC, "UE RA-RNTI %04x TC-RNTI %04x: exceeded RA window, cannot schedule Msg2\n", ra->RA_rnti, UE->rnti); + LOG_E(NR_MAC, + "sfn: %d.%d UE RA-RNTI %04x TC-RNTI %04x: exceeded RA window, cannot schedule Msg2\n", + frameP, + slotP, + ra->RA_rnti, + UE->rnti); nr_release_ra_UE(nr_mac, UE->rnti); return; } From fff95cc07580d588cb7411d1f5f4fe51fff1d1a1 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Wed, 29 Oct 2025 15:20:36 +0100 Subject: [PATCH 18/23] Refactor rx_nr_prach --- openair1/PHY/NR_TRANSPORT/nr_prach.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 0bdb538f20..101bd76463 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -409,7 +409,6 @@ void rx_nr_prach_ru(prach_item_t *p, int32_t **rxdata, NR_DL_FRAME_PARMS *fp, in rx_prach_out_t rx_nr_prach(const prach_item_t *in, int occasion) { rx_prach_out_t out = {}; - c16_t **input = in->rxsigF[occasion]; uint16_t preamble_index0 = 0; uint16_t numshift = 0; int first_nonzero_root_idx = 0; @@ -453,7 +452,7 @@ rx_prach_out_t rx_nr_prach(const prach_item_t *in, int occasion) int32_t prach_ifft[dft_sz] __attribute__((aligned(32))); for (int preamble_index = 0; preamble_index < 64; preamble_index++) { if (LOG_DEBUGFLAG(DEBUG_PRACH)) { - int en = dB_fixed(signal_energy((int32_t *)input[0], N_ZC == 839 ? 840 : 140)); + int en = dB_fixed(signal_energy((int32_t *)in->rxsigF[occasion][0], N_ZC == 839 ? 840 : 140)); if (en > 60) LOG_D(PHY, "frame %d, slot %d : Trying preamble %d \n", in->frame, in->slot, preamble_index); } @@ -527,9 +526,9 @@ rx_prach_out_t rx_nr_prach(const prach_item_t *in, int occasion) first_nonzero_root_idx = preamble_offset; } - // Compute DFT of RX signal (conjugate input, results in conjugate output) for each new rootSequenceIndex + // Compute DFT of RX signal (conjugate in->rxsigF[occasion], results in conjugate output) for each new rootSequenceIndex if (LOG_DEBUGFLAG(DEBUG_PRACH)) { - int en = dB_fixed(signal_energy((int32_t *)input[0], 840)); + int en = dB_fixed(signal_energy((int32_t *)in->rxsigF[occasion][0], 840)); if (en>60) LOG_D(PHY, "frame %d, slot %d : preamble index %d, NCS %d, N_ZC/NCS %d: offset %d, preamble shift %d , en %d)\n", @@ -558,14 +557,14 @@ rx_prach_out_t rx_nr_prach(const prach_item_t *in, int occasion) memset(prach_ifft, 0, sizeof(prach_ifft)); if (LOG_DUMPFLAG(DEBUG_PRACH)) { - LOG_M("prach_rxF0.m", "prach_rxF0", input[0], N_ZC, 1, 1); - LOG_M("prach_rxF1.m", "prach_rxF1", input[1], 6144, 1, 1); + LOG_M("prach_rxF0.m", "prach_rxF0", in->rxsigF[occasion][0], N_ZC, 1, 1); + LOG_M("prach_rxF1.m", "prach_rxF1", in->rxsigF[occasion][1], 6144, 1, 1); } c16_t prachF[dft_sz] __attribute__((aligned(32))); for (int aa = 0; aa < nb_rx; aa++) { // Do componentwise product with Xu* on each antenna for (int offset = 0; offset < N_ZC; offset++) { - prachF[offset] = c16MulConjShift(Xu[offset], input[aa][offset], 15); + prachF[offset] = c16MulConjShift(Xu[offset], in->rxsigF[occasion][aa][offset], 15); } memset(prachF + N_ZC, 0, sizeof(*prachF) * (dft_sz - N_ZC)); // Now do IFFT of size 1024 (N_ZC=839) or 256 (N_ZC=139) From 1292cd68b7d0fe830d0c78285ba6df7bee252189 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Wed, 29 Oct 2025 15:16:02 +0100 Subject: [PATCH 19/23] Remove the usage of global mem for rach rx process saves about 600MB of memory allocation Move the definition of PRACH items and the PRACH list to the defs_nr_commons.h file. Do not re-write the entire structure in nr_schedule_rx_prach(), as it is quite large now. --- executables/nr-gnb.c | 1 - executables/nr-ru.c | 3 +- openair1/PHY/INIT/nr_init_ru.c | 20 ----------- openair1/PHY/NR_TRANSPORT/nr_prach.c | 15 +++------ .../PHY/NR_TRANSPORT/nr_transport_proto.h | 1 - openair1/PHY/defs_RU.h | 2 -- openair1/PHY/defs_common.h | 33 ++----------------- openair1/PHY/defs_nr_common.h | 28 ++++++++++++++++ openair1/SIMULATION/NR_PHY/prachsim.c | 21 ++---------- radio/fhi_72/oaioran.c | 7 +++- radio/fhi_72/oran_isolate.c | 30 +++++++++-------- radio/fhi_72/oran_isolate.h | 5 +-- 12 files changed, 64 insertions(+), 102 deletions(-) diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 0e4fba9812..b0509f158d 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -387,7 +387,6 @@ void init_eNB_afterRU(void) int aa = 0; for (int ru_id = 0; ru_id < gNB->num_RU; ru_id++) { AssertFatal(gNB->RU_list[ru_id]->common.rxdataF != NULL, "RU %d : common.rxdataF is NULL\n", gNB->RU_list[ru_id]->idx); - AssertFatal(gNB->RU_list[ru_id]->prach_rxsigF != NULL, "RU %d : prach_rxsigF is NULL\n", gNB->RU_list[ru_id]->idx); for (int i = 0; i < gNB->RU_list[ru_id]->nb_rx; aa++, i++) { LOG_I(PHY, "Attaching RU %d antenna %d to gNB antenna %d\n", gNB->RU_list[ru_id]->idx, i, aa); for (int b = 0; b < gNB->RU_list[ru_id]->num_beams_period; b++) { diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 9e4e6a5384..ea43ecdff1 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -1216,8 +1216,7 @@ void *ru_thread(void *param) prach_item_t *p = find_nr_prach(&gNB->prach_list, proc->frame_rx, proc->tti_rx, SEARCH_EXIST); if (p) { VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 1 ); - // this fills ru->prach_rxsigF for processing by gNB - p->rxsigF = (c16_t ***)ru->prach_rxsigF; + // need to extract RACH data for lqter processing by rx_nr_prach() rx_nr_prach_ru(p, ru->common.rxdata, ru->nr_frame_parms, ru->N_TA_offset); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 0); } // end if (prach_id >= 0) diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c index 30ec333c70..71418bb1e3 100644 --- a/openair1/PHY/INIT/nr_init_ru.c +++ b/openair1/PHY/INIT/nr_init_ru.c @@ -112,25 +112,10 @@ void nr_phy_init_RU(RU_t *ru) LOG_D(PHY, "rxdataF[%d] %p for RU %d\n", i, ru->common.rxdataF[i], ru->idx); } - /* number of elements of an array X is computed as sizeof(X) / sizeof(X[0]) */ - // AssertFatal(ru->nb_rx <= sizeof(ru->prach_rxsigF) / sizeof(ru->prach_rxsigF[0]), - // "nb_antennas_rx too large"); - for (int j = 0; j < NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX; j++) { - ru->prach_rxsigF[j] = malloc(nb_rx_streams * sizeof(*ru->prach_rxsigF)); - - for (int i = 0; i < nb_rx_streams; i++) { - // largest size for PRACH FFT is 4x98304 (16*24576) - ru->prach_rxsigF[j][i] = malloc16_clear(4 * 98304 * 2 * sizeof(**ru->prach_rxsigF)); - LOG_D(PHY, "[INIT] prach_vars->rxsigF[%d] = %p\n", i, ru->prach_rxsigF[j][i]); - } - } - AssertFatal(ru->num_gNB <= NUMBER_OF_gNB_MAX, "gNB instances %d > %d\n", ru->num_gNB,NUMBER_OF_gNB_MAX); LOG_D(PHY, "[INIT] %s() ru->num_gNB:%d \n", __FUNCTION__, ru->num_gNB); } // !=IF5 - - init_prach_list(&ru->prach_list); } void nr_phy_free_RU(RU_t *ru) @@ -172,11 +157,6 @@ void nr_phy_free_RU(RU_t *ru) free_and_zero(ru->common.rxdataF[i]); free_and_zero(ru->common.rxdataF); - for (int j = 0; j < NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX; j++) { - for (int i = 0; i < nb_rx_streams; i++) - free_and_zero(ru->prach_rxsigF[j][i]); - free_and_zero(ru->prach_rxsigF[j]); - } for(int i = 0; i < ru->num_beams_period; ++i) free_and_zero(ru->common.beam_id[i]); free_and_zero(ru->common.beam_id); diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 101bd76463..0d6a4887ca 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -88,7 +88,10 @@ prach_item_t *nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach } const int fmt = prach_pdu->prach_format; NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; - *prach = (prach_item_t){.frame = SFN, .slot = Slot, .num_slots = (fmt < 4) ? get_long_prach_dur(fmt, fp->numerology_index) : 1}; + // we set only elements as the whole structure has been cleaned when we release it + prach->frame = SFN; + prach->slot = Slot; + prach->num_slots = fmt < 4 ? get_long_prach_dur(fmt, fp->numerology_index) : 1; if (gNB->common_vars.beam_id) { int n_symb = get_nr_prach_duration(prach_pdu->prach_format); AssertFatal(prach_pdu->beamforming.dig_bf_interface < NFAPI_MAX_NUM_BG_IF, @@ -123,16 +126,6 @@ prach_item_t *nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach return prach; } -void nr_fill_prach_ru(RU_t *ru, prach_item_t *gnb_prach) -{ - prach_item_t *prach = find_nr_prach(&ru->prach_list, gnb_prach->frame, gnb_prach->slot, SEARCH_EXIST_OR_FREE); - if (!prach) { - LOG_E(PHY, "no prach memory found\n"); - return; - } - *prach = *gnb_prach; -} - static void rx_nr_prach_ru_internal(prach_item_t *p, int beam_id, int prachStartSymbol, diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index fd0a36536d..31a89e823b 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -211,7 +211,6 @@ rx_prach_out_t rx_nr_prach(const prach_item_t *, int occasion); void rx_nr_prach_ru(prach_item_t *, int32_t **, NR_DL_FRAME_PARMS *frame_parms, int N_TA_offset); -void nr_fill_prach_ru(RU_t *ru,prach_item_t * ); prach_item_t *find_nr_prach(prach_list_t *, int frame, int slot, find_type_t type); void nr_fill_pucch(PHY_VARS_gNB *gNB, int frame, diff --git a/openair1/PHY/defs_RU.h b/openair1/PHY/defs_RU.h index b94d0b1c56..0e21f37fde 100644 --- a/openair1/PHY/defs_RU.h +++ b/openair1/PHY/defs_RU.h @@ -190,7 +190,6 @@ typedef struct { task_ans_t *ans; } feptx_cmd_t; -#define NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX 12 #define RU_RX_SLOT_DEPTH 4 typedef struct RU_proc_t_s { /// Pointer to associated RU descriptor @@ -592,7 +591,6 @@ typedef struct RU_t_s { int32_t *bw_list[NUMBER_OF_eNB_MAX+1]; /// beamforming weight vectors int32_t **beam_weights[NUMBER_OF_eNB_MAX+1][15]; - prach_list_t prach_list; /// received frequency-domain signal for PRACH (IF4p5 RRU) int16_t **prach_rxsigF[NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX]; /// received frequency-domain signal for PRACH BR (IF4p5 RRU) diff --git a/openair1/PHY/defs_common.h b/openair1/PHY/defs_common.h index efaccf2bf7..dbb07a9bbb 100644 --- a/openair1/PHY/defs_common.h +++ b/openair1/PHY/defs_common.h @@ -993,41 +993,14 @@ extern int sync_var; #define MBSFN_FDD_SF6 0x10 #define MBSFN_FDD_SF7 0x08 #define MBSFN_FDD_SF8 0x04 + +#define NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX 12 + typedef struct { pthread_mutex_t mutex_failure; bool failed; } decode_abort_t; -// TODO will be removed in a late commit -#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h" -#define NUMBER_OF_NR_PRACH_MAX 8 -typedef struct { - int frame; - int slot; - int num_slots; // prach duration in slots - int beams[NFAPI_MAX_NUM_BG_IF]; - nfapi_nr_prach_pdu_t pdu; - int rootSequenceIndex; - int numrootSequenceIndex; - int msg1_frequencystart; - int mu; - int prach_sequence_length; - int restricted_set; - int numerology_index; - int nb_rx; - c16_t ***rxsigF; - c16_t (*Xu)[839]; - time_stats_t *rx_prach; -} prach_item_t; - -typedef struct { - /// prach commands - prach_item_t list[NUMBER_OF_NR_PRACH_MAX]; - /// mutex for prach_list access - pthread_mutex_t prach_list_mutex; -} prach_list_t; -void init_prach_list(prach_list_t *); - static inline void init_abort(decode_abort_t *ab) { int ret = pthread_mutex_init(&ab->mutex_failure, NULL); diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 0d1cab4045..f4681020eb 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -133,6 +133,34 @@ typedef struct { int resource_type; } nr_srs_info_t; +#define NUMBER_OF_NR_PRACH_MAX 8 +typedef struct { + int frame; + int slot; + int num_slots; // prach duration in slots + int beams[NFAPI_MAX_NUM_BG_IF]; + nfapi_nr_prach_pdu_t pdu; + int rootSequenceIndex; + int numrootSequenceIndex; + int msg1_frequencystart; + int mu; + int prach_sequence_length; + int restricted_set; + int numerology_index; + int nb_rx; + c16_t rxsigF[NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX][NB_ANTENNAS_RX][NR_PRACH_SEQ_LEN_L]; + c16_t (*Xu)[839]; + time_stats_t *rx_prach; +} prach_item_t; + +typedef struct { + /// prach commands + prach_item_t list[NUMBER_OF_NR_PRACH_MAX]; + /// mutex for prach_list access + pthread_mutex_t prach_list_mutex; +} prach_list_t; +void init_prach_list(prach_list_t *); + typedef struct NR_DL_FRAME_PARMS NR_DL_FRAME_PARMS; typedef uint32_t (*get_samples_per_slot_t)(int slot, const NR_DL_FRAME_PARMS *fp); diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c index 7d87ac54a7..aba532a80d 100644 --- a/openair1/SIMULATION/NR_PHY/prachsim.c +++ b/openair1/SIMULATION/NR_PHY/prachsim.c @@ -718,15 +718,6 @@ int main(int argc, char **argv){ if (n_frames == 1) printf("slot %d, rx_prach_start %d\n", slot, rx_prach_start); - c16_t **rxsigF[NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX]; - for (int j = 0; j < NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX; j++) { - rxsigF[j] = malloc(ru->nb_rx * sizeof(*rxsigF)); - for (int i = 0; i < ru->nb_rx; i++) { - // largest size for PRACH FFT is 4x98304 (16*24576) - rxsigF[j][i] = malloc16_clear(4 * 98304 * sizeof(**rxsigF)); - } - } - for (SNR = snr0; SNR < snr1 && !stop; SNR += .1) { for (ue_speed = ue_speed0; ue_speed < ue_speed1 && !stop; ue_speed += 10) { delay_avg = 0.0; @@ -792,7 +783,6 @@ int main(int argc, char **argv){ .restricted_set = cfg->restricted_set_config.value, .numerology_index = gNB->frame_parms.numerology_index, .nb_rx = gNB->gNB_config.carrier_config.num_rx_ant.value, - .rxsigF = rxsigF, .Xu = gNB->X_u, .rx_prach = &gNB->rx_prach}; rx_nr_prach_ru(&in, ru->common.rxdata, ru->nr_frame_parms, ru->N_TA_offset); @@ -824,7 +814,7 @@ int main(int argc, char **argv){ LOG_M("rxsig0.m","rxs0", &ru->common.rxdata[0][subframe*frame_parms->samples_per_subframe], frame_parms->samples_per_subframe, 1, 1); LOG_M("ru_rxsig0.m","rxs0", &ru->common.rxdata[0][subframe*frame_parms->samples_per_subframe], frame_parms->samples_per_subframe, 1, 1); LOG_M("ru_rxsigF0.m","rxsF0", ru->common.rxdataF[0], frame_parms->ofdm_symbol_size*frame_parms->symbols_per_slot, 1, 1); - LOG_M("ru_prach_rxsigF0.m", "rxsF0", rxsigF[0][0], N_ZC, 1, 1); + LOG_M("ru_prach_rxsigF0.m", "rxsF0", in.rxsigF[0][0], N_ZC, 1, 1); LOG_M("prach_preamble.m","prachp", &gNB->X_u[0], N_ZC, 1, 1); LOG_M("ue_prach_preamble.m","prachp", &UE->X_u[0], N_ZC, 1, 1); #endif @@ -844,14 +834,7 @@ int main(int argc, char **argv){ } if (input_fd) break; - } //SNR loop - for (int j = 0; j < NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX; j++) { - for (int i = 0; i < ru->nb_rx; i++) { - // largest size for PRACH FFT is 4x98304 (16*24576) - free(rxsigF[j][i]); - } - free(rxsigF[j]); - } + } // SNR loop free_channel_desc_scm(UE2gNB); nr_phy_free_RU(ru); diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index 37661d7ad1..493221d6a9 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -184,12 +184,17 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot) int nb_rx_per_ru = ru->nb_rx / fh_init->xran_ports; /* If it is PRACH slot, copy prach IQ from XRAN PRACH buffer to OAI PRACH buffer */ if (is_prach_slot) { + if (!ru->prach_buf) { + LOG_W(HW, "we get rach data from ru, but it is not scheduled %d.%d\n", frame, slot); + return -1; + } for (sym_idx = 0; sym_idx < prach_sym; sym_idx++) { for (int aa = 0; aa < ru->nb_rx; aa++) { int16_t *dst, *src; int idx = 0; oran_buf_list_t *bufs = get_xran_buffers(aa / nb_rx_per_ru); - dst = ru->prach_buf[aa]; // + (sym_idx*576)); + // hardcoded to use only first prach occasion + dst = (int16_t *)ru->prach_buf[0][aa]; src = (int16_t *)bufs->prachdstdecomp[aa % nb_rx_per_ru][tti % XRAN_N_FE_BUF_LEN].pBuffers[sym_idx].pData; /* convert Network order to host order */ if (ru_conf->compMeth_PRACH == XRAN_COMPMETHOD_NONE) { diff --git a/radio/fhi_72/oran_isolate.c b/radio/fhi_72/oran_isolate.c index 48e95e7344..9158e468d4 100644 --- a/radio/fhi_72/oran_isolate.c +++ b/radio/fhi_72/oran_isolate.c @@ -31,6 +31,7 @@ #include "common/utils/LOG/log.h" #include "common/utils/LOG/vcd_signal_dumper.h" #include "openair1/PHY/defs_gNB.h" +#include "openair1/PHY/NR_TRANSPORT/nr_transport_proto.h" #include "oaioran.h" #include "oran-config.h" @@ -212,13 +213,15 @@ int trx_oran_ctlrecv(openair0_device *device, void *msg, ssize_t msg_len) void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot) { - ru_info_t ru_info; - ru_info.nb_rx = ru->nb_rx * ru->num_beams_period; - ru_info.nb_tx = ru->nb_tx * ru->num_beams_period; - ru_info.rxdataF = ru->common.rxdataF; - ru_info.beam_id = ru->common.beam_id; - ru_info.num_beams_period = ru->num_beams_period; - ru_info.prach_buf = ru->prach_rxsigF[0]; // index: [prach_oca][ant_id] + prach_item_t *prach_id = find_nr_prach(&ru->gNB_list[0]->prach_list, *frame, *slot, SEARCH_EXIST); + ru_info_t ru_info = { + .nb_rx = ru->nb_rx * ru->num_beams_period, + .nb_tx = ru->nb_tx * ru->num_beams_period, + .rxdataF = ru->common.rxdataF, + .beam_id = ru->common.beam_id, + .num_beams_period = ru->num_beams_period, + .prach_buf = prach_id ? prach_id->rxsigF : NULL, + }; RU_proc_t *proc = &ru->proc; int f, sl; @@ -269,12 +272,13 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot) void oran_fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) { start_meas(&ru->tx_fhaul); - ru_info_t ru_info; - ru_info.nb_rx = ru->nb_rx * ru->num_beams_period; - ru_info.nb_tx = ru->nb_tx * ru->num_beams_period; - ru_info.txdataF_BF = ru->common.txdataF_BF; - ru_info.beam_id = ru->common.beam_id; - ru_info.num_beams_period = ru->num_beams_period; + ru_info_t ru_info = { + .nb_rx = ru->nb_rx * ru->num_beams_period, + .nb_tx = ru->nb_tx * ru->num_beams_period, + .txdataF_BF = ru->common.txdataF_BF, + .beam_id = ru->common.beam_id, + .num_beams_period = ru->num_beams_period, + }; // printf("south_out:\tframe=%d\tslot=%d\ttimestamp=%ld\n",frame,slot,timestamp); diff --git a/radio/fhi_72/oran_isolate.h b/radio/fhi_72/oran_isolate.h index 7dd61ad739..6ec011a24b 100644 --- a/radio/fhi_72/oran_isolate.h +++ b/radio/fhi_72/oran_isolate.h @@ -28,7 +28,8 @@ #include #include "xran_fh_o_du.h" - +#include "openair1/PHY/impl_defs_nr.h" +#include "openair1/PHY/TOOLS/tools_defs.h" /* * Structure added to bear the information needed from OAI RU */ @@ -50,7 +51,7 @@ typedef struct ru_info_s { int num_beams_period; // Needed for Prach - int16_t **prach_buf; + c16_t (*prach_buf)[NB_ANTENNAS_RX][NR_PRACH_SEQ_LEN_L]; } ru_info_t; /** @brief Reads RX data (PRACH/PUSCH) of next slot. From 80223d36d532e04bf05e250ea00a793963715cdf Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Wed, 29 Oct 2025 15:20:09 +0100 Subject: [PATCH 20/23] Rename nr_fill_prach to nr_schedule_rx_prach() --- doc/SW-archi-graph.md | 2 +- openair1/PHY/NR_TRANSPORT/nr_prach.c | 2 +- openair1/PHY/NR_TRANSPORT/nr_transport_proto.h | 2 +- openair1/SCHED/nfapi_lte_dummy.c | 10 ++++------ openair1/SCHED/nfapi_nr_dummy.c | 2 +- openair1/SCHED_NR/fapi_nr_l1.c | 2 +- 6 files changed, 9 insertions(+), 11 deletions(-) diff --git a/doc/SW-archi-graph.md b/doc/SW-archi-graph.md index a3397ed297..cf826e6e43 100644 --- a/doc/SW-archi-graph.md +++ b/doc/SW-archi-graph.md @@ -39,7 +39,7 @@ rx_func_implem[rx_func] --> handle_nr_nfapi_xxx_pdu --> sendTxFilled((L1_tx_filled)) --> nr_fill_ul_xxx - --> nr_fill_prach + --> nr_schedule_rx_prach() end gNB_dlsch_ulsch_scheduler --> NR_Schedule_response end diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 0d6a4887ca..823af815d3 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -79,7 +79,7 @@ prach_item_t *find_nr_prach(prach_list_t *l, int frame, int slot, find_type_t ty return p; } -prach_item_t *nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) +prach_item_t *nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) { prach_item_t *prach = find_nr_prach(&gNB->prach_list, SFN, Slot, SEARCH_EXIST_OR_FREE); if (!prach) { diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index 31a89e823b..0714f3dde3 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -200,7 +200,7 @@ void nr_fill_ulsch(PHY_VARS_gNB *gNB, int slot, nfapi_nr_pusch_pdu_t *ulsch_pdu); -prach_item_t *nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu); +prach_item_t *nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu); typedef struct rx_prach_out { uint16_t max_preamble; diff --git a/openair1/SCHED/nfapi_lte_dummy.c b/openair1/SCHED/nfapi_lte_dummy.c index 5d9b5b7a76..be532a0c54 100644 --- a/openair1/SCHED/nfapi_lte_dummy.c +++ b/openair1/SCHED/nfapi_lte_dummy.c @@ -41,12 +41,10 @@ void nr_fill_pucch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pucch_pdu_t *pucch_pdu){} -void nr_fill_prach(PHY_VARS_gNB *gNB, - int SFN, - int Slot, - nfapi_nr_prach_pdu_t *prach_pdu){} -void nr_fill_prach_ru(RU_t *ru,prach_item_t *gnb_prach){} - +void nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) +{ +} + void nr_phy_config_request(NR_PHY_Config_t *gNB){} void install_nr_schedule_handlers(NR_IF_Module_t *if_inst){} diff --git a/openair1/SCHED/nfapi_nr_dummy.c b/openair1/SCHED/nfapi_nr_dummy.c index 87c1ea576f..7377a455dd 100644 --- a/openair1/SCHED/nfapi_nr_dummy.c +++ b/openair1/SCHED/nfapi_nr_dummy.c @@ -37,7 +37,7 @@ void nr_fill_pucch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pucch_pdu_t *pucch_pdu){} -void nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) +void nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) { } diff --git a/openair1/SCHED_NR/fapi_nr_l1.c b/openair1/SCHED_NR/fapi_nr_l1.c index 4ec87a1e5f..448af8c0e3 100644 --- a/openair1/SCHED_NR/fapi_nr_l1.c +++ b/openair1/SCHED_NR/fapi_nr_l1.c @@ -155,7 +155,7 @@ void nr_schedule_ul_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_tti_request_t *UL_tti UL_tti_req->Slot); nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[i].prach_pdu; LOG_D(NR_PHY_RACH, "Add prach decoding request for %d.%d\n", UL_tti_req->SFN, UL_tti_req->Slot); - prach_item_t *prach = nr_fill_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu); + prach_item_t *prach = nr_schedule_rx_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu); if (!prach) LOG_W(NR_PHY_RACH, "Error in scheduling rach\n"); /* the present design is not supporting multiple gNB in one RU From 0d083d83fcbf2b86170522f169e2309194e4045c Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Wed, 29 Oct 2025 15:18:46 +0100 Subject: [PATCH 21/23] Simplify code through lookup of PDU name, delete commented code --- .../nfapi/public_inc/nfapi_nr_interface_scf.h | 5 ++- openair1/SCHED_NR/fapi_nr_l1.c | 43 +++++-------------- 2 files changed, 15 insertions(+), 33 deletions(-) diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h index 754ef60e55..12cf081fdc 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h @@ -1481,7 +1481,10 @@ typedef enum { NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE, NFAPI_NR_UL_CONFIG_SRS_PDU_TYPE, } nfapi_nr_ul_config_pdu_type_e; - +static const char* const txt_nfapi_nr_ul_config_pdu_type[] = {"NFAPI_NR_UL_CONFIG_PRACH_PDU_TYPE", + "NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE", + "NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE", + "NFAPI_NR_UL_CONFIG_SRS_PDU_TYPE"}; typedef struct { uint16_t pdu_type;//0: PRACH PDU, 1: PUSCH PDU, 2: PUCCH PDU, 3: SRS PDU diff --git a/openair1/SCHED_NR/fapi_nr_l1.c b/openair1/SCHED_NR/fapi_nr_l1.c index 448af8c0e3..9e4ab67efc 100644 --- a/openair1/SCHED_NR/fapi_nr_l1.c +++ b/openair1/SCHED_NR/fapi_nr_l1.c @@ -127,49 +127,28 @@ void nr_schedule_ul_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_tti_request_t *UL_tti int slot = UL_tti_req->Slot; for (int i = 0; i < UL_tti_req->n_pdus; i++) { - switch (UL_tti_req->pdus_list[i].pdu_type) { + int type = UL_tti_req->pdus_list[i].pdu_type; + LOG_D(NR_PHY, + "frame %d, slot %d got %s for %d.%d\n", + frame, + slot, + txt_nfapi_nr_ul_config_pdu_type[type], + UL_tti_req->SFN, + UL_tti_req->Slot); + switch (type) { case NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE: - LOG_D(NR_PHY, - "frame %d, slot %d, Got NFAPI_NR_UL_TTI_PUSCH_PDU_TYPE for %d.%d\n", - frame, - slot, - UL_tti_req->SFN, - UL_tti_req->Slot); nr_fill_ulsch(gNB, UL_tti_req->SFN, UL_tti_req->Slot, &UL_tti_req->pdus_list[i].pusch_pdu); break; case NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE: - LOG_D(NR_PHY, - "frame %d, slot %d, Got NFAPI_NR_UL_TTI_PUCCH_PDU_TYPE for %d.%d\n", - frame, - slot, - UL_tti_req->SFN, - UL_tti_req->Slot); nr_fill_pucch(gNB, UL_tti_req->SFN, UL_tti_req->Slot, &UL_tti_req->pdus_list[i].pucch_pdu); break; - case NFAPI_NR_UL_CONFIG_PRACH_PDU_TYPE: - LOG_D(NR_PHY, - "frame %d, slot %d, Got NFAPI_NR_UL_TTI_PRACH_PDU_TYPE for %d.%d\n", - frame, - slot, - UL_tti_req->SFN, - UL_tti_req->Slot); + case NFAPI_NR_UL_CONFIG_PRACH_PDU_TYPE: { nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[i].prach_pdu; - LOG_D(NR_PHY_RACH, "Add prach decoding request for %d.%d\n", UL_tti_req->SFN, UL_tti_req->Slot); prach_item_t *prach = nr_schedule_rx_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu); if (!prach) LOG_W(NR_PHY_RACH, "Error in scheduling rach\n"); - /* the present design is not supporting multiple gNB in one RU - if (prach && (gNB->RU_list[0]->if_south == LOCAL_RF || gNB->RU_list[0]->if_south == REMOTE_IF5)) - nr_fill_prach_ru(gNB->RU_list[0], prach); - */ - break; + } break; case NFAPI_NR_UL_CONFIG_SRS_PDU_TYPE: - LOG_D(NR_PHY, - "frame %d, slot %d, Got NFAPI_NR_UL_CONFIG_SRS_PDU_TYPE for %d.%d\n", - frame, - slot, - UL_tti_req->SFN, - UL_tti_req->Slot); nr_fill_srs(gNB, UL_tti_req->SFN, UL_tti_req->Slot, &UL_tti_req->pdus_list[i].srs_pdu); break; } From d8d15205805735c6d3c0c9f81b0098bfdc9c97ae Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Tue, 21 Oct 2025 21:56:58 +0200 Subject: [PATCH 22/23] reduce sl_ahead to catch the RACH Msg1 in time in 24PRB test a bit difficult to understand: sl_ahead=6 => we systematically miss the rach detection in the scheduler because the scheduler runs more than 6 slots ahead the rx slot processing (here > 11 slots because 6 (DL and UL slots) + 4 (RU_RX_SLOT_DEPTH, so UL only)) so, reducing sl_ahead works better than large sl_ahead because the idea behind is: the scheduler of slot+sl_ahead will never create work to do in a UL slot before slot+sl_ahead+X (as minimum k2 is X, in the 24PRB CI test: 6) --- ci-scripts/conf_files/gnb.sa.band78.24prb.rfsim.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/ci-scripts/conf_files/gnb.sa.band78.24prb.rfsim.conf b/ci-scripts/conf_files/gnb.sa.band78.24prb.rfsim.conf index 4a3d2852c4..afe40c733c 100644 --- a/ci-scripts/conf_files/gnb.sa.band78.24prb.rfsim.conf +++ b/ci-scripts/conf_files/gnb.sa.band78.24prb.rfsim.conf @@ -196,6 +196,7 @@ RUs = ( att_tx = 0 att_rx = 0; bands = [78]; + sl_ahead=3; max_pdschReferenceSignalPower = -27; max_rxgain = 114; sf_extension = 0; From 9ce9c16e368fcca70152c9d712e4cc3f82cc24f5 Mon Sep 17 00:00:00 2001 From: Laurent THOMAS Date: Wed, 29 Oct 2025 16:25:42 +0100 Subject: [PATCH 23/23] Add documentation on PRACH processing --- doc/rach_processing_in_gNB.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 doc/rach_processing_in_gNB.md diff --git a/doc/rach_processing_in_gNB.md b/doc/rach_processing_in_gNB.md new file mode 100644 index 0000000000..5c15cf0812 --- /dev/null +++ b/doc/rach_processing_in_gNB.md @@ -0,0 +1,24 @@ +The gNB RACH processing + +1. Collect I/Q samples +The gNB/ru main loop, in ru_thread() +If there is rach occasions in this slot +this main loop calls rx_nr_prach_ru() that stores the I/Q samples in the prach_item_t context + +2.process the samples +L1_rx_thread() has received slot indication by msg on queue resp_L1, it calls rx_func() => L1_nr_prach_procedures() +L1_nr_prach_procedures() fills nfapi_nr_rach_indication_t structure from result of rx_nr_prach() that process the content of rxsigF[prachOccasion][aa] +rx_func() sends the decoded rach to upper processing by call to NR_UL_indication() that calls handle_nr_rach() => nr_initiate_ra_proc() + +nr_initiate_ra_proc() creates a UE context if it needs, then sets UE.ra.ra_state to what it should do + +3. send the RACH DL +tx_func() that is launched by L1_tx_thread() as it gets L1_tx_out msg (from main loop in 1.) +tx_func()=>run_scheduler_monolithic()=>gNB_dlsch_ulsch_scheduler()=>nr_scheduler_RA() +nr_scheduler_RA() process all existing UE contexts, to see it it has to schedule a RACH DL + +4. global synchronisation +resp_L1 msg for (2.) is created in tx_func() that is launched by L1_tx_thread() (see3.) when it receives slot indication as it gets L1_tx_out msg +this msg is sent by the main loop (see 1.) +tx_func()=>run_scheduler_monolithic()=>nr_schedule_response ()=>nr_schedule_ul_tti_req ()=> nr_schedule_rx_prach() +writes in the triggering structure to (1.) that it will have to run rx_nr_prach_ru() in a given future slot