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>
This commit is contained in:
@@ -161,7 +161,12 @@ static void rx_func(processingData_L1_t *info)
|
||||
NR_UL_IND_t UL_INFO = {.frame = frame_rx, .slot = slot_rx, .module_id = gNB->Mod_id, .CC_id = gNB->CC_id};
|
||||
// Do PRACH RU processing
|
||||
UL_INFO.rach_ind.pdu_list = UL_INFO.prach_pdu_indication_list;
|
||||
L1_nr_prach_procedures(gNB, frame_rx, slot_rx, &UL_INFO.rach_ind);
|
||||
UL_INFO.rach_ind.number_of_pdus = 0;
|
||||
// even if processing is late, we might collect all PRACH
|
||||
// the last PRACH's frame/slot is when all UE's appear to have accessed
|
||||
prach_item_t p;
|
||||
while (spsc_q_get(&gNB->prach_l1rx_queue, &p, sizeof(p)))
|
||||
L1_nr_prach_procedures(gNB, &p, &UL_INFO.rach_ind);
|
||||
|
||||
//WA: comment rotation in tx/rx
|
||||
if (gNB->phase_comp) {
|
||||
|
||||
+10
-4
@@ -15,6 +15,7 @@
|
||||
#include "common/utils/nr/nr_common.h"
|
||||
#include "common/utils/assertions.h"
|
||||
#include "common/utils/system.h"
|
||||
#include "common/utils/fsn.h"
|
||||
#include "common/ran_context.h"
|
||||
|
||||
#include "radio/COMMON/common_lib.h"
|
||||
@@ -980,11 +981,16 @@ 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(&gNB->prach_list, proc->frame_rx, proc->tti_rx, gNB->frame_parms.nb_antennas_rx, NR_SEARCH_EXIST);
|
||||
if (p) {
|
||||
fsn_t now = {.f = proc->frame_rx, .s = proc->tti_rx, .mu = fp->numerology_index};
|
||||
prach_item_t p;
|
||||
while (get_next_nr_prach(&gNB->prach_ru_queue, &now, &p)) {
|
||||
// need to extract RACH data for later processing by rx_nr_prach()
|
||||
rx_nr_prach_ru(p, ru->common.rxdata, ru->nr_frame_parms, ru->N_TA_offset);
|
||||
rx_nr_prach_ru(&p, ru->common.rxdata, ru->nr_frame_parms, ru->N_TA_offset);
|
||||
bool success = spsc_q_put(&gNB->prach_l1rx_queue, &p, sizeof(p));
|
||||
// assume prach_l1rx_queue never full: prach_ru_queue filled at
|
||||
// constant pace, but prach_l1rx_queue emptied as fast as possible,
|
||||
// see rx_func()
|
||||
DevAssert(success);
|
||||
} // end if (prach_id >= 0)
|
||||
} // end if (ru->feprx)
|
||||
} // end if (slot_type == NR_UPLINK_SLOT || slot_type == NR_MIXED_SLOT) {
|
||||
|
||||
@@ -166,7 +166,7 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB)
|
||||
common_vars->debugBuff_sample_offset = 0;
|
||||
|
||||
// PRACH
|
||||
init_prach_list(&gNB->prach_list);
|
||||
init_nr_prach(gNB);
|
||||
|
||||
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;
|
||||
@@ -208,6 +208,7 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB)
|
||||
free_gnb_lowpapr_sequences();
|
||||
|
||||
reset_nr_transport(gNB);
|
||||
reset_nr_prach(gNB);
|
||||
|
||||
destroy_DLSCH_struct(gNB);
|
||||
|
||||
|
||||
@@ -12,72 +12,73 @@
|
||||
#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)
|
||||
void init_nr_prach(PHY_VARS_gNB *gNB)
|
||||
{
|
||||
pthread_mutex_init(&l->prach_list_mutex, NULL);
|
||||
memset(l->list, 0, sizeof(l->list));
|
||||
int num_prach = 8;
|
||||
gNB->prach_ru_queue = spsc_q_alloc(num_prach, sizeof(prach_item_t));
|
||||
gNB->prach_l1rx_queue = spsc_q_alloc(num_prach, sizeof(prach_item_t));
|
||||
}
|
||||
|
||||
void free_nr_prach_entry(prach_list_t *l, prach_item_t *p)
|
||||
void reset_nr_prach(PHY_VARS_gNB *gNB)
|
||||
{
|
||||
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, .nb_rx = p->nb_rx, .prach_buf = (void *)(p + 1)};
|
||||
pthread_mutex_unlock(&l->prach_list_mutex);
|
||||
spsc_q_free(&gNB->prach_ru_queue);
|
||||
spsc_q_free(&gNB->prach_l1rx_queue);
|
||||
}
|
||||
|
||||
prach_item_t *find_nr_prach(prach_list_t *l, int frame, int slot, int nb_rx, nr_find_type_t type)
|
||||
void free_nr_prach_entry(prach_item_t *p)
|
||||
{
|
||||
pthread_mutex_lock(&l->prach_list_mutex);
|
||||
AssertFatal(nb_rx, "Error! Number of antennas set to 0.\n");
|
||||
prach_item_t **p = l->list;
|
||||
prach_item_t **end = p + NUMBER_OF_NR_PRACH_MAX;
|
||||
for (; p < end; p++)
|
||||
if ((*p) && (*p)->frame == frame && ((*p)->slot + (*p)->num_slots - 1) == slot)
|
||||
break;
|
||||
if (p == end) {
|
||||
if (type == NR_SEARCH_EXIST) {
|
||||
pthread_mutex_unlock(&l->prach_list_mutex);
|
||||
return NULL;
|
||||
}
|
||||
for (p = l->list; p < end; p++)
|
||||
if (!(*p) || ((*p)->frame == -1 && (*p)->slot == -1))
|
||||
break;
|
||||
}
|
||||
if (p == end) {
|
||||
pthread_mutex_unlock(&l->prach_list_mutex);
|
||||
return NULL;
|
||||
}
|
||||
// mark it used, it will be filled later
|
||||
if (*p && (*p)->nb_rx != nb_rx) {
|
||||
LOG_W(PHY, "rach procedure nb_rx ant changed from %d to %d\n", (*p)->nb_rx, nb_rx);
|
||||
free(*p);
|
||||
*p = NULL;
|
||||
}
|
||||
if (!(*p)) {
|
||||
*p = calloc(1, sizeof(prach_item_t) + sizeof(c16_t) * nb_rx * NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX * NR_PRACH_SEQ_LEN_L);
|
||||
(*p)->prach_buf = (void *)((*p) + 1);
|
||||
}
|
||||
(*p)->nb_rx = nb_rx;
|
||||
(*p)->frame = frame;
|
||||
pthread_mutex_unlock(&l->prach_list_mutex);
|
||||
return (*p);
|
||||
free(p->prach_buf);
|
||||
}
|
||||
|
||||
prach_item_t *nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu)
|
||||
static bool drop_old_prach(const void *data, void *user)
|
||||
{
|
||||
const prach_item_t *p = data;
|
||||
const fsn_t *now = user;
|
||||
const fsn_t t = {p->frame, p->slot, now->mu};
|
||||
bool drop = fsn_in_the_past(t, *now);
|
||||
if (drop)
|
||||
LOG_E(NR_PHY, "%4d.%2d PRACH job is in the past (%4d.%2d)\n", now->f, now->s, t.f, t.s);
|
||||
return drop;
|
||||
}
|
||||
|
||||
static bool get_current_prach(const void *data, void *user)
|
||||
{
|
||||
const prach_item_t *p = data;
|
||||
const fsn_t *now = user;
|
||||
const fsn_t t = {p->frame, p->slot, now->mu};
|
||||
return fsn_equal(t, *now);
|
||||
}
|
||||
|
||||
bool get_next_nr_prach(spsc_q_t *q, const fsn_t *now, prach_item_t *p)
|
||||
{
|
||||
spsc_q_drop_while(q, drop_old_prach, (void *)now);
|
||||
return spsc_q_get_if(q, get_current_prach, (void *)now, p, sizeof(*p));
|
||||
}
|
||||
|
||||
void 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, gNB->frame_parms.nb_antennas_rx, NR_SEARCH_EXIST_OR_FREE);
|
||||
if (!prach) {
|
||||
LOG_W(PHY, "no free space for a new detected rach, discarding\n");
|
||||
return NULL;
|
||||
}
|
||||
const int fmt = prach_pdu->prach_format;
|
||||
NR_DL_FRAME_PARMS *fp = &gNB->frame_parms;
|
||||
// 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;
|
||||
const NR_DL_FRAME_PARMS *fp = &gNB->frame_parms;
|
||||
const nfapi_nr_prach_config_t *cfg = &gNB->gNB_config.prach_config;
|
||||
const nfapi_nr_num_prach_fd_occasions_t *occ = &cfg->num_prach_fd_occasions_list[prach_pdu->num_ra];
|
||||
prach_item_t prach = {
|
||||
.frame = SFN,
|
||||
.slot = Slot,
|
||||
.num_slots = fmt < 4 ? get_long_prach_dur(fmt, fp->numerology_index) : 1,
|
||||
.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 = fp->numerology_index,
|
||||
.nb_rx = gNB->gNB_config.carrier_config.num_rx_ant.value,
|
||||
.Xu = gNB->X_u,
|
||||
.rx_prach = &gNB->rx_prach,
|
||||
// TODO can be made permanently allocated?
|
||||
.prach_buf = calloc_or_fail(1, sizeof(c16_t) * prach.nb_rx * NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX * NR_PRACH_SEQ_LEN_L),
|
||||
};
|
||||
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,
|
||||
@@ -87,7 +88,7 @@ prach_item_t *nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_n
|
||||
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->beams[i] = beam_index_allocation(gNB->enable_analog_das,
|
||||
prach.beams[i] = beam_index_allocation(gNB->enable_analog_das,
|
||||
fapi_beam_idx,
|
||||
&gNB->common_vars,
|
||||
Slot,
|
||||
@@ -95,20 +96,9 @@ prach_item_t *nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_n
|
||||
bitmap);
|
||||
}
|
||||
}
|
||||
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;
|
||||
bool found = spsc_q_put(&gNB->prach_ru_queue, &prach, sizeof(prach));
|
||||
if (!found)
|
||||
LOG_W(NR_PHY, "%4d.%2d PRACH occ queue is full: dropping PRACH request\n", SFN, Slot);
|
||||
}
|
||||
|
||||
static void rx_nr_prach_ru_internal(prach_item_t *p,
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "PHY/defs_nr_common.h"
|
||||
#include "PHY/defs_gNB.h"
|
||||
#include "common/utils/fsn.h"
|
||||
|
||||
#define NR_PBCH_PDU_BITS 24
|
||||
|
||||
@@ -167,7 +168,7 @@ void nr_fill_ulsch(PHY_VARS_gNB *gNB,
|
||||
int slot,
|
||||
nfapi_nr_pusch_pdu_t *ulsch_pdu);
|
||||
|
||||
prach_item_t *nr_schedule_rx_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);
|
||||
|
||||
typedef struct rx_prach_out {
|
||||
uint16_t max_preamble;
|
||||
@@ -178,12 +179,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);
|
||||
|
||||
typedef enum {
|
||||
NR_SEARCH_EXIST = 0,
|
||||
NR_SEARCH_EXIST_OR_FREE
|
||||
} nr_find_type_t;
|
||||
|
||||
prach_item_t *find_nr_prach(prach_list_t *, int frame, int slot, int nb_rx, nr_find_type_t type);
|
||||
void nr_fill_pucch(PHY_VARS_gNB *gNB,
|
||||
int frame,
|
||||
int slot,
|
||||
@@ -219,7 +214,10 @@ nr_srs_info_t nr_srs_rx_procedures(PHY_VARS_gNB *gNB,
|
||||
|
||||
int get_nr_prach_duration(uint8_t prach_format);
|
||||
|
||||
void free_nr_prach_entry(prach_list_t *, prach_item_t *);
|
||||
void init_nr_prach(PHY_VARS_gNB *gNB);
|
||||
void reset_nr_prach(PHY_VARS_gNB *gNB);
|
||||
void free_nr_prach_entry(prach_item_t *);
|
||||
bool get_next_nr_prach(spsc_q_t *q, const fsn_t *now, prach_item_t *p);
|
||||
|
||||
void nr_decode_pucch1(PHY_VARS_gNB *gNB,
|
||||
c16_t **rxdataF,
|
||||
|
||||
@@ -46,14 +46,6 @@ typedef struct {
|
||||
c16_t (*prach_buf)[NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX][NR_PRACH_SEQ_LEN_L];
|
||||
} 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 {
|
||||
int nb_id;
|
||||
int Nid[MAX_PUCCH0_NID];
|
||||
@@ -378,7 +370,8 @@ typedef struct PHY_VARS_gNB_s {
|
||||
int max_nb_pusch;
|
||||
|
||||
NR_gNB_COMMON common_vars;
|
||||
prach_list_t prach_list;
|
||||
spsc_q_t prach_ru_queue;
|
||||
spsc_q_t prach_l1rx_queue;
|
||||
// TODO: can we remove c from NR_gNB_DLSCH_t and put it on the stack?
|
||||
NR_gNB_DLSCH_t *dlsch;
|
||||
NR_gNB_PRS prs_vars;
|
||||
|
||||
@@ -21,20 +21,14 @@ int get_nr_prach_duration(uint8_t prach_format)
|
||||
return val[prach_format];
|
||||
}
|
||||
|
||||
void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rach_indication_t *rach_ind)
|
||||
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;
|
||||
rach_ind->number_of_pdus = 0;
|
||||
|
||||
prach_item_t *prach_id = find_nr_prach(&gNB->prach_list, frame, slot, gNB->frame_parms.nb_antennas_rx, NR_SEARCH_EXIST);
|
||||
if (!prach_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
for (int prach_oc = 0; prach_oc < prach_pdu->num_prach_ocas; prach_oc++) {
|
||||
@@ -63,7 +57,7 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac
|
||||
"[RAPROC] %d.%d Initiating RA procedure with preamble %d, energy %d.%d dB (I0 %d, thres %d), delay %d start symbol "
|
||||
"%u freq index %u\n",
|
||||
frame,
|
||||
prach_start_slot,
|
||||
slot,
|
||||
res.max_preamble,
|
||||
res.max_preamble_energy / 10,
|
||||
res.max_preamble_energy % 10,
|
||||
@@ -100,7 +94,6 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac
|
||||
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_RACH, "Freeing PRACH entry\n");
|
||||
free_nr_prach_entry(&gNB->prach_list, prach_id);
|
||||
free_nr_prach_entry(prach_id);
|
||||
}
|
||||
|
||||
@@ -1330,9 +1330,7 @@ void nr_save_ul_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_tti_request_t *UL_tti_req
|
||||
break;
|
||||
case NFAPI_NR_UL_CONFIG_PRACH_PDU_TYPE: {
|
||||
nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[i].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");
|
||||
nr_schedule_rx_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu);
|
||||
} break;
|
||||
case NFAPI_NR_UL_CONFIG_SRS_PDU_TYPE:
|
||||
nr_fill_srs(gNB, UL_tti_req->SFN, UL_tti_req->Slot, &UL_tti_req->pdus_list[i].srs_pdu);
|
||||
|
||||
@@ -18,7 +18,7 @@ void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB,
|
||||
int slot);
|
||||
void nr_save_ul_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_tti_request_t *UL_tti_req);
|
||||
int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, NR_UL_IND_t *UL_INFO);
|
||||
void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rach_indication_t *rach_ind);
|
||||
void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, prach_item_t *prach_id, nfapi_nr_rach_indication_t *rach_ind);
|
||||
void nr_common_signal_procedures (PHY_VARS_gNB *gNB,int frame,int slot, const nfapi_nr_dl_tti_ssb_pdu *ssb_pdu);
|
||||
void nr_feptx_ofdm(RU_t *ru,int frame_tx,int tti_tx);
|
||||
void nr_feptx0(RU_t *ru,int tti_tx,int first_symbol, int num_symbols, int aa);
|
||||
|
||||
@@ -547,12 +547,10 @@ int main(int argc, char **argv){
|
||||
phy_init_nr_gNB(gNB);
|
||||
nr_phy_init_RU(ru);
|
||||
|
||||
prach_item_t *prach_data = calloc(1,sizeof(prach_item_t));
|
||||
gNB->prach_list.list[0] = prach_data;
|
||||
nfapi_nr_prach_pdu_t *prach_pdu = &prach_data->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;
|
||||
nfapi_nr_prach_pdu_t prach_pdu = {0};
|
||||
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));
|
||||
@@ -749,14 +747,14 @@ int main(int argc, char **argv){
|
||||
}
|
||||
|
||||
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;
|
||||
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 = malloc(sizeof(prach_item_t)
|
||||
+ sizeof(c16_t) * gNB->gNB_config.carrier_config.num_rx_ant.value
|
||||
* NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX * NR_PRACH_SEQ_LEN_L);
|
||||
*in = (prach_item_t){.frame = frame,
|
||||
.slot = slot,
|
||||
.pdu = *prach_pdu,
|
||||
.pdu = prach_pdu,
|
||||
.rootSequenceIndex = occ->prach_root_sequence_index.value,
|
||||
.numrootSequenceIndex = occ->num_root_sequences.value,
|
||||
.msg1_frequencystart = occ->k1.value,
|
||||
@@ -772,7 +770,7 @@ int main(int argc, char **argv){
|
||||
if (n_frames == 1)
|
||||
LOG_I(PHY,
|
||||
"ncs %d,num_seq %d\n",
|
||||
prach_pdu->num_cs,
|
||||
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);
|
||||
|
||||
@@ -823,7 +821,6 @@ int main(int argc, char **argv){
|
||||
nr_phy_free_RU(ru);
|
||||
free(RC.ru[0]);
|
||||
free(RC.ru);
|
||||
free(prach_data);
|
||||
phy_free_nr_gNB(gNB);
|
||||
// allocated in set_tdd_config_nr()
|
||||
int nb_slots_to_set = (1<<mu)*NR_NUMBER_OF_SUBFRAMES_PER_FRAME;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "xran_sync_api.h"
|
||||
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "common/utils/fsn.h"
|
||||
#include "openair1/PHY/defs_gNB.h"
|
||||
#include "openair1/PHY/NR_TRANSPORT/nr_transport_proto.h"
|
||||
#include "oaioran.h"
|
||||
@@ -205,19 +206,21 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot)
|
||||
.prach_buf = NULL,
|
||||
};
|
||||
|
||||
prach_item_t *prach_id = find_nr_prach(&ru->gNB_list[0]->prach_list, *frame, *slot, ru->nr_frame_parms->nb_antennas_rx, SEARCH_EXIST);
|
||||
if (prach_id) {
|
||||
prach_item_t p;
|
||||
PHY_VARS_gNB *gNB = ru->gNB_list[0];
|
||||
fsn_t now = {.f = *frame, .s = *slot, .mu = gNB->frame_parms.numerology_index};
|
||||
if (get_next_nr_prach(&gNB->prach_ru_queue, &now, &p)) {
|
||||
struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
|
||||
int slots_per_subframe = 1 << fh_cfg->frame_conf.nNumerology;
|
||||
uint32_t subframe = *slot / slots_per_subframe; // `slot` = slot in which PRACH is received
|
||||
// PRACH occasion in a frame if and only if SFN % x == y, TS 38.211 Table 6.3.3.2-2/3/4
|
||||
nr_prach_info_t prach_info = get_prach_info(0);
|
||||
bool is_prach_frame = (*frame % prach_info.x == prach_info.y);
|
||||
bool is_prach_slot = is_prach_frame && xran_is_prach_slot(0, subframe, (prach_id->slot % slots_per_subframe)); // `prach_id->slot` = slot in which PRACH is scheduled
|
||||
bool is_prach_slot = is_prach_frame && xran_is_prach_slot(0, subframe, (p.slot % slots_per_subframe)); // `p.slot` = slot in which PRACH is scheduled
|
||||
if (is_prach_slot) {
|
||||
ru_info.prach_buf = prach_id->prach_buf;
|
||||
ru_info.prach_buf = p.prach_buf;
|
||||
} else {
|
||||
LOG_W(HW, "[%d.%d] Expected PRACH reception of scheduled slot %d\n", *frame, *slot, prach_id->slot);
|
||||
LOG_W(HW, "[%d.%d] Expected PRACH reception of scheduled slot %d\n", *frame, *slot, p.slot);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,6 +235,15 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot)
|
||||
printf("ORAN: %d.%d ORAN_fh_if4p5_south_in ERROR in RX function \n", f, sl);
|
||||
}
|
||||
|
||||
if (ru_info.prach_buf) {
|
||||
// xran_fh_rx_read_slot() should have read PRACH, write back to queue
|
||||
bool success = spsc_q_put(&gNB->prach_l1rx_queue, &p, sizeof(p));
|
||||
// assume prach_l1rx_queue never full: prach_ru_queue filled at
|
||||
// constant pace, but prach_l1rx_queue emptied as fast as possible,
|
||||
// see rx_func()
|
||||
DevAssert(success);
|
||||
}
|
||||
|
||||
int slots_per_frame = 10 << (ru->openair0_cfg.nr_scs_for_raster);
|
||||
proc->tti_rx = sl;
|
||||
proc->frame_rx = f;
|
||||
|
||||
Reference in New Issue
Block a user