Files
openairinterface5g/openair1/SCHED_NR/nr_prach_procedures.c
Robert Schmidt 03096dd495 Use spsc_q to process PRACH jobs
Use two queues for PRACH processing:

- prach_ru_queue: pass jobs from TX thread (scheduler) to RU thread. For
  split 8, the RU thread itself handles PRACH processing; for split 7.2,
  it is the library that is responsible for handling PRACH messages (see
  oran_fh_if4p5_south_in())
- prach_l1rx_queue: after jobs have been handled in RU thread, use this
  queue to pass jobs to the RX thread. There, preamble detection is
  performed, and RACH.indication FAPI messages are filled if a preamble
  has been detected.

Together, these queues replace a linear search in a global array that
has been modified by three threads at the same time. The design ensures
that access now is thread-safe, and with less overhead.

Signed-off-by: Robert Schmidt <robert.schmidt@openairinterface.org>
2026-04-16 12:16:47 +02:00

100 lines
4.1 KiB
C

/*
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
*/
/*!
* \brief Implementation of gNB prach procedures from 38.213 LTE specifications
*/
#include "PHY/defs_gNB.h"
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
#include "nfapi_nr_interface_scf.h"
#include "nfapi_pnf.h"
#include "common/utils/LOG/log.h"
#include "assertions.h"
#include <time.h>
int get_nr_prach_duration(uint8_t prach_format)
{
const int val[14] = {0, 0, 0, 0, 2, 4, 6, 2, 12, 2, 6, 2, 4, 6};
AssertFatal(prach_format < sizeofArray(val), "Invalid Prach format %d\n", prach_format);
return val[prach_format];
}
void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, prach_item_t *prach_id, nfapi_nr_rach_indication_t *rach_ind)
{
const frame_t frame = prach_id->frame;
const slot_t slot = prach_id->slot;
rach_ind->sfn = frame;
rach_ind->slot = 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);
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++) {
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}.
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",
frame,
slot,
prach_oc,
prachStartSymbol,
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)
&& (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,
slot,
res.max_preamble,
res.max_preamble_energy / 10,
res.max_preamble_energy % 10,
gNB->measurements.prach_I0,
gNB->prach_thres,
res.max_preamble_delay,
prachStartSymbol,
prach_pdu->num_ra);
T(T_ENB_PHY_INITIATE_RA_PROCEDURE,
T_INT(gNB->Mod_id),
T_INT(frame),
T_INT(slot),
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){
.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 = (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 = 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) + ((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)
gNB->prach_energy_counter++;
} // if prach_id>0
LOG_D(NR_PHY_RACH, "Freeing PRACH entry\n");
free_nr_prach_entry(prach_id);
}