Commit 1fd3c284 authored by Robert Schmidt's avatar Robert Schmidt

Merge remote-tracking branch 'origin/rework-gnb-prach-mem-management' into...

Merge remote-tracking branch 'origin/rework-gnb-prach-mem-management' into integration_2025_w44 (!3592)

Refactor PRACH handling at the gNB

- Remove race conditions by correctly setting mutexes
- Fix a bug when having multiple RACH occasions
- Reduce memory footprint by removing global memory, which should also
  fix potential memory data races in FHI 7.2
- Additional fixes, see commit messages
parents 77335985 9ce9c16e
......@@ -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;
......
......@@ -240,6 +240,7 @@ configmodule_interface_t *load_configmodule(int argc,
for (int i=0; i<argc; i++)
printf("\"%s\" ", argv[i]);
printf("\n");
fflush(stdout);
/* first parse the command line to look for the -O option */
for (i = 0; i<argc; i++) {
......
......@@ -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;
......
......@@ -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) \
......@@ -316,8 +317,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 */
......
......@@ -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
......
......@@ -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
......
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
......@@ -387,10 +387,8 @@ 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);
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];
......
......@@ -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,34 +1213,11 @@ 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) {
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));
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;
//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,
beam_id,
prachStartSymbol,
p->slot,
prach_oc,
proc->frame_rx,
proc->tti_rx);
}
free_nr_ru_prach_entry(ru,prach_id);
// 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)
} // end if (ru->feprx)
......
......@@ -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;
}
......
......@@ -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 <CTRL-C> 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();
......
......@@ -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
......
......@@ -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,10 +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*));
prach_vars->prach_ifft = (int32_t *)malloc16_clear(1024*2*sizeof(int32_t));
init_prach_list(gNB);
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;
......@@ -266,10 +261,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++) {
......
......@@ -27,8 +27,6 @@
#include <math.h>
#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;
......@@ -114,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] = (int16_t**)malloc(nb_rx_streams * sizeof(int16_t*));
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]);
}
}
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_ru_list(ru);
}
void nr_phy_free_RU(RU_t *ru)
......@@ -174,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);
......
This diff is collapsed.
......@@ -200,32 +200,18 @@ 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);
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,
uint16_t *max_preamble_energy,
uint16_t *max_preamble_delay);
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 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);
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;
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(prach_item_t *, int32_t **, NR_DL_FRAME_PARMS *frame_parms, int N_TA_offset);
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 +231,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, int prach_id);
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(prach_list_t *, prach_item_t *);
void nr_decode_pucch1(c16_t **rxdataF,
pucch_GroupHopping_t pucch_GroupHopping,
......
......@@ -190,19 +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 {
/// Pointer to associated RU descriptor
......@@ -604,11 +591,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
RU_PRACH_list_t prach_list[NUMBER_OF_NR_RU_PRACH_MAX];
/// mutex for prach_list access
pthread_mutex_t prach_list_mutex;
/// 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];
......
......@@ -993,6 +993,9 @@ 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;
......
......@@ -134,28 +134,6 @@ 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;
/// \brief local buffer to compute prach_ifft
int32_t *prach_ifft;
gNB_PRACH_list_t list[NUMBER_OF_NR_PRACH_MAX];
} NR_gNB_PRACH;
typedef struct {
uint8_t NumPRSResources;
prs_config_t prs_cfg[NR_MAX_PRS_RESOURCES_PER_SET];
......@@ -430,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;
......
......@@ -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);
......
......@@ -41,15 +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,
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)
{
}
void nr_phy_config_request(NR_PHY_Config_t *gNB){}
void install_nr_schedule_handlers(NR_IF_Module_t *if_inst){}
......
......@@ -37,15 +37,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,
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)
{
}
void nr_phy_config_request(NR_PHY_Config_t *gNB){}
void install_nr_schedule_handlers(NR_IF_Module_t *if_inst){}
......
......@@ -127,44 +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;
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);
break;
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");
} 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;
}
......
......@@ -49,99 +49,86 @@ 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;
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;
rach_ind->number_of_pdus = 0;
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);
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}.
prach_item_t *prach_id = find_nr_prach(&gNB->prach_list, frame, slot, SEARCH_EXIST);
if (!prach_id) {
return;
}
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,"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],
max_preamble_energy[0]/10,
max_preamble_energy[0]%10,
max_preamble_delay[0],
gNB->prach_energy_counter);
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);
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);
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);
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)
&& (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,
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);
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(res.max_preamble),
T_INT(res.max_preamble_energy),
T_INT(res.max_preamble_delay));
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;
} // for NUMBER_OF_NR_PRACH_OCCASION_MAX
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
rach_ind->slot = prach_start_slot;
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);
}
......@@ -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;
......@@ -151,9 +152,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 +416,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 +559,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 +568,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_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 +587,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;
......@@ -716,9 +715,8 @@ 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);
for (SNR = snr0; SNR < snr1 && !stop; SNR += .1) {
for (ue_speed = ue_speed0; ue_speed < ue_speed1 && !stop; ue_speed += 10) {
......@@ -729,8 +727,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)
......@@ -757,45 +754,67 @@ 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);
}
}
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);
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);
} 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);
}
}
// printf(" preamble_energy %d preamble_rx %d preamble_tx %d \n", preamble_energy, preamble_rx, preamble_tx);
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);
}
}
if (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,
.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);
// printf(" preamble_energy %d preamble_rx %d preamble_tx %d \n", out.max_preamble_energy, out.max_preamble,
// preamble_tx);
if (out.max_preamble != preamble_tx)
prach_errors++;
else
delay_avg += (double)preamble_delay;
delay_avg += (double)out.max_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",
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", 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
......@@ -815,8 +834,7 @@ int main(int argc, char **argv){
}
if (input_fd)
break;
} //SNR loop
} // SNR loop
free_channel_desc_scm(UE2gNB);
nr_phy_free_RU(ru);
......
......@@ -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",
......@@ -1431,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;
}
......
......@@ -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) {
......
......@@ -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);
......
......@@ -28,7 +28,8 @@
#include <stdint.h>
#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.
......
......@@ -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;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment