diff --git a/CMakeLists.txt b/CMakeLists.txt index b1a85819a0..1c4ba0c42e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -855,7 +855,6 @@ set(NR_PHY_SRC_RU ${OPENAIR1_DIR}/PHY/MODULATION/nr_beamforming.c ${OPENAIR1_DIR}/PHY/MODULATION/slot_fep_nr.c ${OPENAIR1_DIR}/PHY/INIT/nr_init_ru.c - ${OPENAIR1_DIR}/PHY/if4_tools.c ) set(PHY_SRC_UE diff --git a/executables/lte-ru.c b/executables/lte-ru.c index a0a82deabd..1314fd8876 100644 --- a/executables/lte-ru.c +++ b/executables/lte-ru.c @@ -2357,7 +2357,6 @@ void set_function_spec_param(RU_t *ru) { case LOCAL_RF: // this is an RU with integrated RF (RRU, eNB) if (ru->function == NGFI_RRU_IF5) { // IF5 RRU ru->do_prach = 0; // no prach processing in RU - ru->fh_north_in = NULL; // no shynchronous incoming fronthaul from north ru->fh_north_out = fh_if5_north_out; // need only to do send_IF5 reception ru->fh_south_out = tx_rf; // send output to RF ru->fh_north_asynch_in = fh_if5_north_asynch_in; // TX packets come asynchronously @@ -2381,7 +2380,6 @@ void set_function_spec_param(RU_t *ru) { } } else if (ru->function == NGFI_RRU_IF4p5) { ru->do_prach = 1; // do part of prach processing in RU - ru->fh_north_in = NULL; // no synchronous incoming fronthaul from north ru->fh_north_out = fh_if4p5_north_out; // send_IF4p5 on reception ru->fh_south_out = tx_rf; // send output to RF ru->fh_north_asynch_in = fh_if4p5_north_asynch_in; // TX packets come asynchronously @@ -2410,7 +2408,6 @@ void set_function_spec_param(RU_t *ru) { ru->feprx = (get_thread_worker_conf() == WORKER_DISABLE) ? fep_full : ru_fep_full_2thread; // RX DFTs ru->feptx_ofdm = (get_thread_worker_conf() == WORKER_DISABLE) ? feptx_ofdm : feptx_ofdm_2thread; // this is fep with idft and precoding ru->feptx_prec = feptx_prec; // this is fep with idft and precoding - ru->fh_north_in = NULL; // no incoming fronthaul from north ru->fh_north_out = NULL; // no outgoing fronthaul to north ru->start_if = NULL; // no if interface ru->rfdevice.host_type = RAU_HOST; diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index ef9447e08d..cae39120f6 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -98,14 +98,10 @@ static void tx_func(processingData_L1tx_t *info) start_meas(&info->gNB->phy_proc_tx); phy_procedures_gNB_TX(info->gNB, &sched_response.DL_req, &sched_response.TX_req, &sched_response.UL_dci_req, frame_tx,slot_tx); - PHY_VARS_gNB *gNB = info->gNB; - processingData_RU_t syncMsgRU; - syncMsgRU.frame_tx = frame_tx; - syncMsgRU.slot_tx = slot_tx; - syncMsgRU.ru = gNB->RU_list[0]; - syncMsgRU.timestamp_tx = info->timestamp_tx; - LOG_D(PHY, "gNB: %d.%d : calling RU TX function\n", syncMsgRU.frame_tx, syncMsgRU.slot_tx); - ru_tx_func((void *)&syncMsgRU); + LOG_D(PHY, "gNB: %d.%d : calling fhi dl_slot_send\n", frame_tx, slot_tx); + RU_t *fhi_ru = gNB->RU_list[0]; + nr_fhi_t *fhi = (fhi_ru->if_south == LOCAL_RF) ? fhi_ru->rfdevice.fhi : fhi_ru->ifdevice.fhi; + fhi->dl_slot_send(gNB, frame_tx, slot_tx, info->timestamp_tx); stop_meas(&info->gNB->phy_proc_tx); } } @@ -249,15 +245,8 @@ static size_t dump_L1_meas_stats(PHY_VARS_gNB *gNB, RU_t *ru, char *output, size output += print_meas_log(&ru->txdataF_copy_stats, "txdataF_copy", NULL, NULL, output, end - output); } - if (ru->fh_north_asynch_in) - output += print_meas_log(&ru->rx_fhaul,"rx_fhaul",NULL,NULL, output, end - output); - output += print_meas_log(&ru->tx_fhaul,"tx_fhaul",NULL,NULL, output, end - output); - if (ru->fh_north_out) { - output += print_meas_log(&ru->compression,"compression",NULL,NULL, output, end - output); - output += print_meas_log(&ru->transport,"transport",NULL,NULL, output, end - output); - } return output - begin; } diff --git a/executables/nr-ru.c b/executables/nr-ru.c index fd8a0ef45f..e5d810f4bb 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -21,8 +21,6 @@ #include "radio/COMMON/common_lib.h" #include "radio/ETHERNET/ethernet_lib.h" -#include "PHY/if4_tools.h" - #include "PHY/defs_nr_common.h" #include "PHY/phy_extern.h" #include "PHY/NR_TRANSPORT/nr_transport_proto.h" @@ -52,294 +50,28 @@ static int DEFRUTPCORES[] = {-1,-1,-1,-1}; static void NRRCconfig_RU(configmodule_interface_t *cfg); -/*************************************************************/ -/* Southbound Fronthaul functions, RCC/RAU */ - -// southbound IF5 fronthaul for 16-bit OAI format -void fh_if5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) -{ - int offset = get_samples_slot_timestamp(ru->nr_frame_parms, slot); - void *buffs[ru->nb_tx]; - for (int aid = 0; aid < ru->nb_tx; aid++) - buffs[aid] = (void*)&ru->common.txdata[aid][offset]; - struct timespec txmeas; - clock_gettime(CLOCK_MONOTONIC, &txmeas); - LOG_D(NR_PHY, - "IF5 TX %d.%d, TS %lu, buffs[0] %p, buffs[1] %p ener0 %f dB, tx start %d\n", - frame, - slot, - timestamp, - buffs[0], - buffs[1], - 10 * log10((double)signal_energy(buffs[0], get_samples_per_slot(slot, ru->nr_frame_parms))), - (int)txmeas.tv_nsec); - ru->ifdevice.trx_write_func2(&ru->ifdevice, timestamp, buffs, 0, get_samples_per_slot(slot, ru->nr_frame_parms), 0, ru->nb_tx); -} - -// southbound IF4p5 fronthaul -void fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) -{ - LOG_D(PHY,"Sending IF4p5 for frame %d subframe %d\n",ru->proc.frame_tx,ru->proc.tti_tx); - - if ((nr_slot_select(&ru->config, ru->proc.frame_tx, ru->proc.tti_tx) & NR_DOWNLINK_SLOT) > 0) - send_IF4p5(ru,frame, slot, IF4p5_PDLFFT); -} - -/*************************************************************/ -/* Input Fronthaul from south RCC/RAU */ - -// Synchronous if5 from south - -void fh_if5_south_in(RU_t *ru, int *frame, int *tti) -{ - NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; - RU_proc_t *proc = &ru->proc; - start_meas(&ru->rx_fhaul); - - ru->ifdevice.trx_read_func2(&ru->ifdevice, &proc->timestamp_rx, NULL, get_samples_per_slot(*tti, fp)); - if (proc->first_rx == 1) - ru->ts_offset = proc->timestamp_rx; - proc->frame_rx = ((proc->timestamp_rx - ru->ts_offset) / (fp->samples_per_subframe * 10)) & 1023; - proc->tti_rx = get_slot_from_timestamp(proc->timestamp_rx - ru->ts_offset, fp); - - if (proc->first_rx == 0) { - if (proc->tti_rx != *tti) { - LOG_E(PHY,"Received Timestamp doesn't correspond to the time we think it is (proc->tti_rx %d, subframe %d)\n",proc->tti_rx,*tti); - if (!oai_exit) - exit_fun("Exiting"); - return; - } - - if (proc->frame_rx != *frame) { - LOG_E(PHY,"Received Timestamp doesn't correspond to the time we think it is (proc->frame_rx %d frame %d proc->tti_rx %d tti %d)\n",proc->frame_rx,*frame,proc->tti_rx,*tti); - if (!oai_exit) - exit_fun("Exiting"); - return; - } - } else { - proc->first_rx = 0; - *frame = proc->frame_rx; - *tti = proc->tti_rx; - } - - stop_meas(&ru->rx_fhaul); - struct timespec rxmeas; - clock_gettime(CLOCK_MONOTONIC, &rxmeas); - double fhtime = ru->rx_fhaul.p_time/(cpu_freq_GHz*1000.0); - if (fhtime > 800) - LOG_W(PHY, - "IF5 %d.%d => RX %d.%d first_rx %d: time %f, rxstart %ld\n", - *frame, - *tti, - proc->frame_rx, - proc->tti_rx, - proc->first_rx, - ru->rx_fhaul.p_time / (cpu_freq_GHz * 1000.0), - rxmeas.tv_nsec); - else - LOG_D(PHY, - "IF5 %d.%d => RX %d.%d first_rx %d: time %f, rxstart %ld\n", - *frame, - *tti, - proc->frame_rx, - proc->tti_rx, - proc->first_rx, - ru->rx_fhaul.p_time / (cpu_freq_GHz * 1000.0), - rxmeas.tv_nsec); -} - -// Synchronous if4p5 from south -void fh_if4p5_south_in(RU_t *ru, - int *frame, - int *slot) { - NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; - RU_proc_t *proc = &ru->proc; - int f,sl; - uint16_t packet_type; - uint32_t symbol_number=0; - uint32_t symbol_mask_full=0; - - do { // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!! - recv_IF4p5(ru, &f, &sl, &packet_type, &symbol_number); - - if (packet_type == IF4p5_PULFFT) proc->symbol_mask[sl] = proc->symbol_mask[sl] | (1<first_rx == 0) && (f != *frame)) - LOG_E(PHY, "rx_fh_if4p5: PULTICK received frame %d != expected %d\n", f, *frame); - - if ((proc->first_rx == 0) && (sl != *slot)) - LOG_E(PHY, "rx_fh_if4p5: PULTICK received subframe %d != expected %d (first_rx %d)\n", sl, *slot, proc->first_rx); - - break; - } else if (packet_type == IF4p5_PRACH) { - // nothing in RU for RAU - } - - LOG_D(PHY,"rx_fh_if4p5: subframe %d symbol mask %x\n",*slot,proc->symbol_mask[sl]); - } while(proc->symbol_mask[sl] != symbol_mask_full); - - //caculate timestamp_rx, timestamp_tx based on frame and subframe - proc->tti_rx = sl; - proc->frame_rx = f; - proc->timestamp_rx = (proc->frame_rx * fp->samples_per_subframe * 10) + get_samples_slot_timestamp(fp, proc->tti_rx); - // proc->timestamp_tx = proc->timestamp_rx + (4*fp->samples_per_subframe); - proc->tti_tx = (sl+ru->sl_ahead)%fp->slots_per_frame; - proc->frame_tx = (sl > (fp->slots_per_frame - 1 - (ru->sl_ahead))) ? (f + 1) & 1023 : f; - - if (proc->first_rx == 0) { - if (proc->tti_rx != *slot) { - LOG_E(PHY,"Received Timestamp (IF4p5) doesn't correspond to the time we think it is (proc->tti_rx %d, subframe %d)\n",proc->tti_rx,*slot); - exit_fun("Exiting"); - } - - if (proc->frame_rx != *frame) { - LOG_E(PHY,"Received Timestamp (IF4p5) doesn't correspond to the time we think it is (proc->frame_rx %d frame %d)\n",proc->frame_rx,*frame); - exit_fun("Exiting"); - } - } else { - proc->first_rx = 0; - *frame = proc->frame_rx; - *slot = proc->tti_rx; - } - - proc->symbol_mask[proc->tti_rx] = 0; - LOG_D(PHY,"RU %d: fh_if4p5_south_in sleeping ...\n",ru->idx); -} - -// asynchronous inbound if4p5 fronthaul from south -void fh_if4p5_south_asynch_in(RU_t *ru,int *frame,int *slot) { - NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; - RU_proc_t *proc = &ru->proc; - uint16_t packet_type; - uint32_t symbol_number = 0; - uint32_t symbol_mask = (1 << fp->symbols_per_slot) - 1; - uint32_t prach_rx = 0; - - do { // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!! - recv_IF4p5(ru, &proc->frame_rx, &proc->tti_rx, &packet_type, &symbol_number); - if (proc->first_rx != 0) { - *frame = proc->frame_rx; - *slot = proc->tti_rx; - proc->first_rx = 0; - } else { - if (proc->frame_rx != *frame) { - LOG_E(PHY,"frame_rx %d is not what we expect %d\n",proc->frame_rx,*frame); - exit_fun("Exiting"); - } - if (proc->tti_rx != *slot) { - LOG_E(PHY,"tti_rx %d is not what we expect %d\n",proc->tti_rx,*slot); - exit_fun("Exiting"); - } - } - - if (packet_type == IF4p5_PULFFT) - symbol_mask &= ~(1 << symbol_number); - else if (packet_type == IF4p5_PRACH) - prach_rx &= ~0x1; - } while (symbol_mask > 0 || prach_rx > 0); // haven't received all PUSCH symbols and PRACH information -} - -/*************************************************************/ -/* Input Fronthaul from North RRU */ - -// RRU IF4p5 TX fronthaul receiver. Assumes an if_device on input and if or rf device on output -// receives one subframe's worth of IF4p5 OFDM symbols and OFDM modulates -void fh_if4p5_north_in(RU_t *ru,int *frame,int *slot) -{ - uint32_t symbol_number=0; - uint32_t symbol_mask, symbol_mask_full; - uint16_t packet_type; - /// **** incoming IF4p5 from remote RCC/RAU **** /// - symbol_number = 0; - symbol_mask = 0; - symbol_mask_full = (1<<(ru->nr_frame_parms->symbols_per_slot))-1; - - do { - recv_IF4p5(ru, frame, slot, &packet_type, &symbol_number); - symbol_mask = symbol_mask | (1<nr_frame_parms; - nfapi_nr_config_request_scf_t *cfg = &ru->config; - RU_proc_t *proc = &ru->proc; - uint16_t packet_type; - uint32_t symbol_mask_full = 0; - int slot_tx,frame_tx; - LOG_D(PHY, "%s(ru:%p frame, subframe)\n", __FUNCTION__, ru); - uint32_t symbol_number = 0; - uint32_t symbol_mask = 0; - - // symbol_mask_full = ((subframe_select(fp,*slot) == SF_S) ? (1<dl_symbols_in_S_subframe) : (1<symbols_per_slot))-1; - do { - recv_IF4p5(ru, &frame_tx, &slot_tx, &packet_type, &symbol_number); - - if (((nr_slot_select(cfg, frame_tx, slot_tx) & NR_DOWNLINK_SLOT) > 0) && (symbol_number == 0)) - start_meas(&ru->rx_fhaul); - - LOG_D(PHY,"slot %d (%d): frame %d, slot %d, symbol %d\n", - *slot,nr_slot_select(cfg,frame_tx,*slot),frame_tx,slot_tx,symbol_number); - - if (proc->first_tx != 0) { - *frame = frame_tx; - *slot = slot_tx; - proc->first_tx = 0; - } else { - AssertFatal(frame_tx == *frame, - "frame_tx %d is not what we expect %d\n",frame_tx,*frame); - AssertFatal(slot_tx == *slot, - "slot_tx %d is not what we expect %d\n",slot_tx,*slot); - } - - if (packet_type == IF4p5_PDLFFT) { - symbol_mask = symbol_mask | (1< 0) - stop_meas(&ru->rx_fhaul); - - proc->tti_tx = slot_tx; - proc->frame_tx = frame_tx; - - if (frame_tx == 0 && slot_tx == 0) - proc->frame_tx_unwrap += 1024; - proc->timestamp_tx = - ((uint64_t)frame_tx + proc->frame_tx_unwrap) * fp->samples_per_subframe * 10 + get_samples_slot_timestamp(fp, slot_tx); - LOG_D(PHY, "RU %d/%d TST %lu, frame %d, subframe %d\n", ru->idx, 0, proc->timestamp_tx, frame_tx, slot_tx); - - if (ru->feptx_ofdm) - ru->feptx_ofdm(ru, frame_tx, slot_tx); - - if (ru->fh_south_out) - ru->fh_south_out(ru, frame_tx, slot_tx, proc->timestamp_tx); -} - -void fh_if5_north_out(RU_t *ru) +// Common ul_slot_ready: push TX slot descriptor to the L1 TX thread queue +static void nr_fhi_ul_slot_ready(struct PHY_VARS_gNB_s *gNB, + int frame_tx, int slot_tx, + int frame_rx, int slot_rx, + uint64_t timestamp_tx) { - /// **** send_IF5 of rxdata to BBU **** /// - AssertFatal(1 == 0, "Shouldn't get here\n"); + notifiedFIFO_elt_t *resTx = newNotifiedFIFO_elt(sizeof(processingData_L1tx_t), 0, &gNB->L1_tx_out, NULL); + resTx->key = slot_tx; + processingData_L1tx_t *syncMsgTx = NotifiedFifoData(resTx); + *syncMsgTx = (processingData_L1tx_t){.gNB = gNB, + .frame = frame_tx, + .slot = slot_tx, + .frame_rx = frame_rx, + .slot_rx = slot_rx, + .timestamp_tx = timestamp_tx}; + pushNotifiedFIFO(&gNB->L1_tx_out, resTx); } -// RRU IF4p5 northbound interface (RX) -void fh_if4p5_north_out(RU_t *ru) -{ - RU_proc_t *proc=&ru->proc; - start_meas(&ru->tx_fhaul); - send_IF4p5(ru, proc->frame_rx, proc->tti_rx, IF4p5_PULFFT); - stop_meas(&ru->tx_fhaul); -} - -static void rx_rf(RU_t *ru, int *frame, int *slot) +static void rx_rf(struct PHY_VARS_gNB_s *gNB, int *frame, int *slot) { + RU_t *ru = gNB->RU_list[0]; RU_proc_t *proc = &ru->proc; NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; openair0_config_t *cfg = &ru->openair0_cfg; @@ -737,25 +469,12 @@ int setup_RU_buffers(RU_t *ru) return(0); } -void ru_tx_func(void *param) +// LOCAL_RF: IFFT+CP then write time-domain samples to RF device +static void nr_fhi_rf_dl_slot_send(struct PHY_VARS_gNB_s *gNB, int frame, int slot, uint64_t timestamp) { - processingData_RU_t *info = (processingData_RU_t *) param; - RU_t *ru = info->ru; - int frame_tx = info->frame_tx; - int slot_tx = info->slot_tx; - - // do TX front-end processing if needed (precoding and/or IDFTs) - if (ru->feptx_prec) - ru->feptx_prec(ru,frame_tx,slot_tx); - - // do OFDM with/without TX front-end processing if needed - if (ru->fh_north_asynch_in == NULL && ru->feptx_ofdm) - ru->feptx_ofdm(ru, frame_tx, slot_tx); - - if (ru->fh_north_asynch_in == NULL && ru->fh_south_out) - ru->fh_south_out(ru, frame_tx, slot_tx, info->timestamp_tx); - if (ru->fh_north_out) - ru->fh_north_out(ru); + RU_t *ru = gNB->RU_list[0]; + nr_feptx_tp(ru, frame, slot); // Transmit Precoding + IDFTs + tx_rf(ru, frame, slot, timestamp); } /* @brief wait for the next RX TTI to be free @@ -810,15 +529,12 @@ void *ru_thread(void *param) int ret; int slot = fp->slots_per_frame-1; int frame = 1023; - char threadname[40]; int initial_wait = 0; bool rx_tti_busy[RU_RX_SLOT_DEPTH] = {false}; // set default return value ru_thread_status = 0; - // 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()); + LOG_I(PHY,"Starting RU %d (%s) on cpu %d\n",ru->idx,NB_functions[ru->function],sched_getcpu()); ru->config = gNB->gNB_config; nr_init_frame_parms(&ru->config, fp); @@ -827,25 +543,11 @@ void *ru_thread(void *param) fill_rf_config(ru, ru->rf_config_file); fill_split7_2_config(&ru->openair0_cfg.split7, &ru->config, fp); - // Start IF device if any - if (ru->nr_start_if) { + if (ru->if_south == REMOTE_IF5 || ru->if_south == REMOTE_IF4p5) { LOG_I(PHY, "starting transport\n"); ret = openair0_transport_load(&ru->ifdevice, &ru->openair0_cfg, &ru->eth_params); AssertFatal(ret == 0, "RU %u: openair0_transport_init() ret %d: cannot initialize transport protocol\n", ru->idx, ret); - if (ru->ifdevice.get_internal_parameter != NULL) { - /* it seems the device can "overwrite" (request?) to set the callbacks - * for fh_south_in()/fh_south_out() differently */ - void *t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_in"); - if (t != NULL) - ru->fh_south_in = t; - t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_out"); - if (t != NULL) - ru->fh_south_out = t; - } else { - malloc_IF4p5_buffer(ru); - } - int cpu = sched_getcpu(); if (ru->ru_thread_core > -1 && cpu != ru->ru_thread_core) { /* we start the ru_thread using threadCreate(), which already sets CPU @@ -858,8 +560,13 @@ void *ru_thread(void *param) LOG_I(PHY, "RU %d: manually set CPU affinity to CPU %d\n", ru->idx, ru->ru_thread_core); } + if (ru->if_south == REMOTE_IF5) { + for (int i = 0; i < ru->nb_rx; i++) + ru->openair0_cfg.rxbase[i] = ru->common.rxdata[i]; + } LOG_I(PHY, "Starting IF interface for RU %d, nb_rx %d\n", ru->idx, ru->nb_rx); - AssertFatal(ru->nr_start_if(ru) == 0, "Could not start the IF device\n"); + ret = ru->ifdevice.trx_start_func(&ru->ifdevice); + AssertFatal(ret == 0, "Could not start the IF device\n"); } else if (ru->if_south == LOCAL_RF) { // configure RF parameters only ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); @@ -871,6 +578,20 @@ void *ru_thread(void *param) exit(-1); } + if (ru->if_south == REMOTE_IF5) { + ret = ru->ifdevice.thirdparty_startstreaming(&ru->ifdevice); + AssertFatal(ret == 0, "Cannot start third-party streaming.\n"); + } else if (ru->if_south == LOCAL_RF) { + ret = ru->rfdevice.trx_start_func(&ru->rfdevice); + AssertFatal(ret == 0, "Cannot start RF device.\n"); + LOG_I(PHY, "RU %d RF started cpu_meas_enabled %d\n", ru->idx, cpu_meas_enabled); + // start Tx write thread + if (usrp_tx_thread == 1) { + ret = ru->rfdevice.trx_write_init(&ru->rfdevice); + AssertFatal(ret == 0, "Cannot start Tx thread.\n"); + } + } + LOG_I(PHY, "Signaling main thread that RU %d is ready, sl_ahead %d\n",ru->idx,ru->sl_ahead); pthread_mutex_lock(&RC.ru_mutex); RC.ru_mask &= ~(1<idx); @@ -878,26 +599,6 @@ void *ru_thread(void *param) pthread_mutex_unlock(&RC.ru_mutex); wait_sync("ru_thread"); - // Start RF device if any - if (ru->start_rf) { - if (ru->start_rf(ru) != 0) - LOG_E(HW, "Could not start the RF device\n"); - else - LOG_I(PHY, "RU %d rf device ready\n", ru->idx); - } else - LOG_I(PHY, "RU %d no rf device\n", ru->idx); - - LOG_I(PHY, "RU %d RF started cpu_meas_enabled %d\n", ru->idx, cpu_meas_enabled); - // start trx write thread - if (usrp_tx_thread == 1) { - if (ru->start_write_thread) { - if (ru->start_write_thread(ru) != 0) { - LOG_E(HW, "Could not start tx write thread\n"); - } else { - LOG_I(PHY, "tx write thread ready\n"); - } - } - } // This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices struct timespec slot_start; @@ -919,8 +620,9 @@ void *ru_thread(void *param) // synchronization on input FH interface, acquire signals/data and block LOG_D(PHY,"[RU_thread] read data: frame_rx = %d, tti_rx = %d\n", frame, slot); - AssertFatal(ru->fh_south_in, "No fronthaul interface at south port"); - ru->fh_south_in(ru, &frame, &slot); + nr_fhi_t *fhi = (ru->if_south == LOCAL_RF) ? ru->rfdevice.fhi : ru->ifdevice.fhi; + AssertFatal(fhi->ul_slot_receive, "No UL fronthaul interface"); + fhi->ul_slot_receive(gNB, &frame, &slot); if (initial_wait == 1 && proc->frame_rx < 300) { if (proc->frame_rx > 0 && ((proc->frame_rx % 100) == 0) && proc->tti_rx == 0) { @@ -943,7 +645,7 @@ void *ru_thread(void *param) 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", + "AFTER ul_slot_receive - 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, @@ -962,8 +664,8 @@ void *ru_thread(void *param) if (slot_type == NR_UPLINK_SLOT || slot_type == NR_MIXED_SLOT) { if (!wait_free_rx_tti(&gNB->L1_rx_out, rx_tti_busy, proc->frame_rx, proc->tti_rx)) break; // nothing to wait for: we have to stop - if (ru->feprx) { - ru->feprx(ru,proc->tti_rx); + if (ru->if_south == LOCAL_RF || ru->if_south == REMOTE_IF5) { + nr_fep_tp(ru,proc->tti_rx); 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); @@ -987,69 +689,16 @@ void *ru_thread(void *param) // see rx_func() DevAssert(success); } // end if (prach_id >= 0) - } // end if (ru->feprx) + } // end if (ru->if_south == LOCAL_RF || ru->if_south == REMOTE_IF5) } // end if (slot_type == NR_UPLINK_SLOT || slot_type == NR_MIXED_SLOT) { - notifiedFIFO_elt_t *resTx = newNotifiedFIFO_elt(sizeof(processingData_L1tx_t), 0, &gNB->L1_tx_out, NULL); - resTx->key = proc->tti_tx; - processingData_L1tx_t *syncMsgTx = NotifiedFifoData(resTx); - *syncMsgTx = (processingData_L1tx_t){.gNB = gNB, - .frame = proc->frame_tx, - .slot = proc->tti_tx, - .frame_rx = proc->frame_rx, - .slot_rx = proc->tti_rx, - .timestamp_tx = proc->timestamp_tx}; - pushNotifiedFIFO(&gNB->L1_tx_out, resTx); + fhi->ul_slot_ready(gNB, proc->frame_tx, proc->tti_tx, proc->frame_rx, proc->tti_rx, proc->timestamp_tx); } ru_thread_status = 0; return &ru_thread_status; } -int start_streaming(RU_t *ru) { - LOG_I(PHY,"Starting streaming on third-party RRU\n"); - return ru->ifdevice.thirdparty_startstreaming(&ru->ifdevice); -} - -int nr_start_if(struct RU_t_s *ru) -{ - if (ru->if_south <= REMOTE_IF5) - for (int i = 0; i < ru->nb_rx; i++) - ru->openair0_cfg.rxbase[i] = ru->common.rxdata[i]; - ru->openair0_cfg.rxsize = ru->nr_frame_parms->samples_per_subframe*10; - return ru->ifdevice.trx_start_func(&ru->ifdevice); -} - -int start_rf(RU_t *ru) -{ - return(ru->rfdevice.trx_start_func(&ru->rfdevice)); -} - -int stop_rf(RU_t *ru) -{ - if (ru->rfdevice.trx_get_stats_func) { - ru->rfdevice.trx_get_stats_func(&ru->rfdevice); - } - ru->rfdevice.trx_end_func(&ru->rfdevice); - return 0; -} - -int start_write_thread(RU_t *ru) { - return ru->rfdevice.trx_write_init(&ru->rfdevice); -} - -void init_RU_proc(RU_t *ru) -{ - ru->proc = (RU_proc_t){.ru = ru, .first_rx = 1, .first_tx = 1}; - LOG_I(PHY, "Initialized RU proc %d (%s,%s),\n", ru->idx, NB_functions[ru->function], NB_timing[ru->if_timing]); -} - -void start_RU_proc(RU_t *ru) -{ - threadCreate(&ru->proc.pthread_FH, ru_thread, (void *)ru, "ru_thread", ru->ru_thread_core, OAI_PRIORITY_RT_MAX); -} - - void kill_NR_RU_proc(int inst) { RU_t *ru = RC.ru[inst]; RU_proc_t *proc = &ru->proc; @@ -1070,114 +719,36 @@ void kill_NR_RU_proc(int inst) { pthread_mutex_unlock(proc->mutex_fep); pthread_join(proc->pthread_FH, NULL); - // everything should be stopped now, we can safely stop the RF device - if (ru->stop_rf == NULL) { - LOG_W(PHY, "No stop_rf() for RU %d defined, cannot stop RF!\n", ru->idx); - return; - } - int rc = ru->stop_rf(ru); - if (rc != 0) { - LOG_W(PHY, "stop_rf() returned %d, RU %d RF device did not stop properly!\n", rc, ru->idx); - return; + /* stop trx devices, multiple carrier currently not supported by RU */ + if (ru->rfdevice.trx_get_stats_func) { + LOG_I(PHY, "Getting RU %d RF stats\n", ru->idx); + ru->rfdevice.trx_get_stats_func(&ru->rfdevice); } - LOG_I(PHY, "RU %d RF device stopped\n",ru->idx); -} -void set_function_spec_param(RU_t *ru) -{ - switch (ru->if_south) { - case LOCAL_RF: // this is an RU with integrated RF (RRU, gNB) - reset_meas(&ru->rx_fhaul); - if (ru->function == NGFI_RRU_IF5) { // IF5 RRU - ru->do_prach = 0; // no prach processing in RU - ru->fh_north_in = NULL; // no shynchronous incoming fronthaul from north - ru->fh_north_out = fh_if5_north_out; // need only to do send_IF5 reception - ru->fh_south_out = tx_rf; // send output to RF - ru->fh_north_asynch_in = fh_if5_north_asynch_in; // TX packets come asynchronously - ru->feprx = NULL; // nothing (this is a time-domain signal) - ru->feptx_ofdm = NULL; // nothing (this is a time-domain signal) - ru->feptx_prec = NULL; // nothing (this is a time-domain signal) - ru->nr_start_if = nr_start_if; // need to start the if interface for if5 - ru->ifdevice.host_type = RRU_HOST; - ru->rfdevice.host_type = RRU_HOST; - ru->ifdevice.eth_params = &ru->eth_params; - reset_meas(&ru->rx_fhaul); - reset_meas(&ru->tx_fhaul); - reset_meas(&ru->compression); - reset_meas(&ru->transport); - } else if (ru->function == NGFI_RRU_IF4p5) { - ru->do_prach = 1; // do part of prach processing in RU - ru->fh_north_in = NULL; // no synchronous incoming fronthaul from north - ru->fh_north_out = fh_if4p5_north_out; // send_IF4p5 on reception - ru->fh_south_out = tx_rf; // send output to RF - ru->fh_north_asynch_in = fh_if4p5_north_asynch_in; // TX packets come asynchronously - ru->feprx = nr_fep_tp; // this is frequency-shift + DFTs - ru->feptx_ofdm = nr_feptx_tp; // this is fep with idft only (no precoding in RRU) - ru->feptx_prec = NULL; - ru->nr_start_if = nr_start_if; // need to start the if interface for if4p5 - ru->ifdevice.host_type = RRU_HOST; - ru->rfdevice.host_type = RRU_HOST; - ru->ifdevice.eth_params = &ru->eth_params; - reset_meas(&ru->tx_fhaul); - reset_meas(&ru->compression); - reset_meas(&ru->transport); - } else if (ru->function == gNodeB_3GPP) { - ru->do_prach = 0; // no prach processing in RU - ru->feprx = nr_fep_tp; // this is frequency-shift + DFTs - ru->feptx_ofdm = nr_feptx_tp; // this is fep with idft and precoding - ru->feptx_prec = NULL; - ru->fh_north_in = NULL; // no incoming fronthaul from north - ru->fh_north_out = NULL; // no outgoing fronthaul to north - ru->nr_start_if = NULL; // no if interface - ru->rfdevice.host_type = RAU_HOST; - ru->fh_south_in = rx_rf; // local synchronous RF RX - ru->fh_south_out = tx_rf; // local synchronous RF TX - ru->start_rf = start_rf; // need to start the local RF interface - ru->stop_rf = stop_rf; - ru->start_write_thread = start_write_thread; // starting RF TX in different thread - } - break; + if (ru->rfdevice.trx_stop_func) { + LOG_I(PHY, "Stopping RU %d RF device\n", ru->idx); + ru->rfdevice.trx_stop_func(&ru->rfdevice); + } - case REMOTE_IF5: // the remote unit is IF5 RRU - ru->do_prach = 0; - ru->txfh_in_fep = 0; - ru->feprx = nr_fep_tp; // this is frequency-shift + DFTs - ru->feptx_prec = NULL; // need to do transmit Precoding + IDFTs - ru->feptx_ofdm = nr_feptx_tp; // need to do transmit Precoding + IDFTs - ru->fh_south_in = fh_if5_south_in; // synchronous IF5 reception - ru->fh_south_out = (ru->txfh_in_fep>0) ? NULL : fh_if5_south_out; // synchronous IF5 transmission - ru->fh_south_asynch_in = NULL; // no asynchronous UL - ru->start_rf = ru->eth_params.transp_preference == ETH_UDP_IF5_ECPRI_MODE ? start_streaming : NULL; - ru->stop_rf = NULL; - ru->start_write_thread = NULL; - ru->nr_start_if = nr_start_if; // need to start if interface for IF5 - ru->ifdevice.host_type = RAU_HOST; - ru->ifdevice.eth_params = &ru->eth_params; + if (ru->rfdevice.trx_end_func) { + LOG_I(PHY, "Ending RU %d RF device\n", ru->idx); + ru->rfdevice.trx_end_func(&ru->rfdevice); + } - break; + if (ru->ifdevice.trx_get_stats_func) { + LOG_I(PHY, "Getting RU %d IF stats\n", ru->idx); + ru->ifdevice.trx_get_stats_func(&ru->rfdevice); + } - case REMOTE_IF4p5: - ru->do_prach = 0; - ru->feprx = NULL; // DFTs - ru->feptx_prec = nr_feptx_prec; // Precoding operation - ru->feptx_ofdm = NULL; // no OFDM mod - ru->fh_south_in = fh_if4p5_south_in; // synchronous IF4p5 reception - ru->fh_south_out = fh_if4p5_south_out; // synchronous IF4p5 transmission - ru->fh_south_asynch_in = (ru->if_timing == synch_to_other) ? fh_if4p5_south_in : NULL; // asynchronous UL if synch_to_other - ru->fh_north_out = NULL; - ru->fh_north_asynch_in = NULL; - ru->start_rf = NULL; // no local RF - ru->stop_rf = NULL; - ru->start_write_thread = NULL; - ru->nr_start_if = nr_start_if; // need to start if interface for IF4p5 - ru->ifdevice.host_type = RAU_HOST; - ru->ifdevice.eth_params = &ru->eth_params; - break; + if (ru->ifdevice.trx_stop_func) { + LOG_I(PHY, "Stopping RU %d IF device\n", ru->idx); + ru->ifdevice.trx_stop_func(&ru->ifdevice); + } - default: - LOG_E(PHY,"RU with invalid or unknown southbound interface type %d\n",ru->if_south); - break; - } // switch on interface type + if (ru->ifdevice.trx_end_func) { + LOG_I(PHY, "Ending RU %d IF device\n", ru->idx); + ru->ifdevice.trx_end_func(&ru->ifdevice); + } } void init_NR_RU(configmodule_interface_t *cfg, char *rf_config_file) @@ -1232,8 +803,34 @@ void init_NR_RU(configmodule_interface_t *cfg, char *rf_config_file) } } } - set_function_spec_param(ru); - init_RU_proc(ru); + + if (RC.nb_nr_L1_inst > 0 && ru->num_gNB > 0 && ru->gNB_list[0] != NULL) { + nr_fhi_t *fhi = calloc(1, sizeof(*fhi)); + fhi->ul_slot_ready = nr_fhi_ul_slot_ready; + switch (ru->if_south) { + case LOCAL_RF: + reset_meas(&ru->rx_fhaul); + AssertFatal(ru->function == gNodeB_3GPP, "ru->function %d not supported for LOCAL_RF\n", ru->function); + fhi->ul_slot_receive = rx_rf; + fhi->dl_slot_send = nr_fhi_rf_dl_slot_send; + ru->rfdevice.fhi = fhi; + break; + case REMOTE_IF5: + ru->ifdevice.fhi = fhi; + break; + case REMOTE_IF4p5: + ru->ifdevice.fhi = fhi; + break; + default: + LOG_E(PHY, "RU with invalid or unknown southbound interface type %d\n", ru->if_south); + free(fhi); + break; + } + } + + // init RU_proc -> needed for timing alignment + ru->proc = (RU_proc_t){.ru = ru, .first_rx = 1, .first_tx = 1}; + if (ru->if_south != REMOTE_IF4p5) { int threadCnt = ru->num_tpcores; if (threadCnt < 2) @@ -1261,7 +858,7 @@ void init_NR_RU(configmodule_interface_t *cfg, char *rf_config_file) void start_NR_RU() { RU_t *ru = RC.ru[0]; - start_RU_proc(ru); + threadCreate(&ru->proc.pthread_FH, ru_thread, ru, "ru_thread", ru->ru_thread_core, OAI_PRIORITY_RT_MAX); } void stop_RU(int nb_ru) { @@ -1289,8 +886,6 @@ static void NRRCconfig_RU(configmodule_interface_t *cfg) RU_t *ru = RC.ru[j] = calloc(1, sizeof(*RC.ru[j])); ru->idx = j; ru->nr_frame_parms = calloc(1, sizeof(*ru->nr_frame_parms)); - ru->frame_parms = calloc(1, sizeof(*ru->frame_parms)); - ru->if_timing = synch_to_ext_device; paramdef_t *param = RUParamList.paramarray[j]; if (RC.nb_nr_L1_inst > 0) ru->num_gNB = param[RU_ENB_LIST_IDX].numelt; @@ -1369,47 +964,14 @@ static void NRRCconfig_RU(configmodule_interface_t *cfg) ru->openair0_cfg.tune_offset = get_softmodem_params()->tune_offset; if (strcmp(*param[RU_LOCAL_RF_IDX].strptr, "yes") == 0) { - if (!config_isparamset(param, RU_LOCAL_IF_NAME_IDX)) { - ru->if_south = LOCAL_RF; - ru->function = gNodeB_3GPP; - LOG_D(PHY, "Setting function for RU %d to gNodeB_3GPP\n", j); - } else { - ru->eth_params.local_if_name = strdup(*param[RU_LOCAL_IF_NAME_IDX].strptr); - ru->eth_params.my_addr = strdup(*param[RU_LOCAL_ADDRESS_IDX].strptr); - ru->eth_params.remote_addr = strdup(*param[RU_REMOTE_ADDRESS_IDX].strptr); - ru->eth_params.my_portc = *param[RU_LOCAL_PORTC_IDX].uptr; - ru->eth_params.remote_portc = *param[RU_REMOTE_PORTC_IDX].uptr; - ru->eth_params.my_portd = *param[RU_LOCAL_PORTD_IDX].uptr; - ru->eth_params.remote_portd = *param[RU_REMOTE_PORTD_IDX].uptr; - char *str = *param[RU_TRANSPORT_PREFERENCE_IDX].strptr; - if (strcmp(str, "udp") == 0) { - ru->if_south = LOCAL_RF; - ru->function = NGFI_RRU_IF5; - ru->eth_params.transp_preference = ETH_UDP_MODE; - LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF5 (udp)\n", j); - } else if (strcmp(str, "raw") == 0) { - ru->if_south = LOCAL_RF; - ru->function = NGFI_RRU_IF5; - ru->eth_params.transp_preference = ETH_RAW_MODE; - LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF5 (raw)\n", j); - } else if (strcmp(str, "udp_if4p5") == 0) { - ru->if_south = LOCAL_RF; - ru->function = NGFI_RRU_IF4p5; - ru->eth_params.transp_preference = ETH_UDP_IF4p5_MODE; - LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF4p5 (udp)\n", j); - } else if (strcmp(str, "raw_if4p5") == 0) { - ru->if_south = LOCAL_RF; - ru->function = NGFI_RRU_IF4p5; - ru->eth_params.transp_preference = ETH_RAW_IF4p5_MODE; - LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF4p5 (raw)\n", j); - } - } - + AssertFatal(!config_isparamset(param, RU_LOCAL_IF_NAME_IDX), "RU_TRANSPORT_PREFERENCE not supported for local RF\n"); + ru->if_south = LOCAL_RF; + ru->function = gNodeB_3GPP; + LOG_D(PHY, "Setting function for RU %d to gNodeB_3GPP\n", j); ru->max_pdschReferenceSignalPower = *param[RU_MAX_RS_EPRE_IDX].uptr; ru->max_rxgain = *param[RU_MAX_RXGAIN_IDX].uptr; ru->sf_extension = *param[RU_SF_EXTENSION_IDX].uptr; - } // strcmp(local_rf, "yes") == 0 - else { + } else { char *str = *param[RU_TRANSPORT_PREFERENCE_IDX].strptr; LOG_D(PHY, "RU %d: Transport %s\n", j, str); ru->eth_params.local_if_name = strdup(*param[RU_LOCAL_IF_NAME_IDX].strptr); @@ -1420,28 +982,16 @@ static void NRRCconfig_RU(configmodule_interface_t *cfg) ru->eth_params.my_portd = *param[RU_LOCAL_PORTD_IDX].uptr; ru->eth_params.remote_portd = *param[RU_REMOTE_PORTD_IDX].uptr; - if (strcmp(str, "udp") == 0) { - ru->if_south = REMOTE_IF5; - ru->function = NGFI_RAU_IF5; - ru->eth_params.transp_preference = ETH_UDP_MODE; - } else if (strcmp(str, "udp_ecpri_if5") == 0) { + if (strcmp(str, "udp_ecpri_if5") == 0) { ru->if_south = REMOTE_IF5; ru->function = NGFI_RAU_IF5; ru->eth_params.transp_preference = ETH_UDP_IF5_ECPRI_MODE; - } else if (strcmp(str, "raw") == 0) { - ru->if_south = REMOTE_IF5; - ru->function = NGFI_RAU_IF5; - ru->eth_params.transp_preference = ETH_RAW_MODE; - } else if (strcmp(str, "udp_if4p5") == 0) { - ru->if_south = REMOTE_IF4p5; - ru->function = NGFI_RAU_IF4p5; - ru->eth_params.transp_preference = ETH_UDP_IF4p5_MODE; } else if (strcmp(str, "raw_if4p5") == 0) { ru->if_south = REMOTE_IF4p5; ru->function = NGFI_RAU_IF4p5; ru->eth_params.transp_preference = ETH_RAW_IF4p5_MODE; } - } /* strcmp(local_rf, "yes") != 0 */ + } ru->nb_tx = *param[RU_NB_TX_IDX].uptr; ru->nb_rx = *param[RU_NB_RX_IDX].uptr; diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index c1bd360001..6ce2506090 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -363,23 +363,6 @@ int stop_L1(module_id_t gnb_id) if (RC.nb_nr_L1_inst > 0) stop_gNB(RC.nb_nr_L1_inst); - /* stop trx devices, multiple carrier currently not supported by RU */ - if (ru->rfdevice.trx_get_stats_func) { - ru->rfdevice.trx_get_stats_func(&ru->rfdevice); - } - if (ru->rfdevice.trx_stop_func) { - ru->rfdevice.trx_stop_func(&ru->rfdevice); - LOG_I(GNB_APP, "turned off RU rfdevice\n"); - } - - if (ru->ifdevice.trx_get_stats_func) { - ru->ifdevice.trx_get_stats_func(&ru->rfdevice); - } - if (ru->ifdevice.trx_stop_func) { - ru->ifdevice.trx_stop_func(&ru->ifdevice); - LOG_I(GNB_APP, "turned off RU ifdevice\n"); - } - if (RC.nb_RU > 0) stop_RU(RC.nb_RU); diff --git a/executables/softmodem-common.h b/executables/softmodem-common.h index de6169c1e5..ea9f576899 100644 --- a/executables/softmodem-common.h +++ b/executables/softmodem-common.h @@ -311,7 +311,6 @@ extern int usrp_tx_thread; extern int sf_ahead; extern int oai_exit; -void ru_tx_func(void *param); void configure_ru(void *, void *arg); void configure_rru(void *, void *arg); struct timespec timespec_add(struct timespec lhs, struct timespec rhs); diff --git a/openair1/PHY/defs_RU.h b/openair1/PHY/defs_RU.h index 7081b0820b..a09de2a43f 100644 --- a/openair1/PHY/defs_RU.h +++ b/openair1/PHY/defs_RU.h @@ -449,8 +449,6 @@ typedef struct RU_t_s { int sf_ahead; /// TX processing advance in slots (for NR) int sl_ahead; - /// flag to indicate TX FH is embedded in TX FEP - int txfh_in_fep; /// flag to indicate half-slot parallelization int half_slot_parallelization; /// FAPI confiuration @@ -487,8 +485,6 @@ typedef struct RU_t_s { /// function pointer to synchronous TX fronthaul function void (*fh_south_out)(struct RU_t_s *ru, int frame_tx, int tti_tx, uint64_t timestamp_tx); /// function pointer to synchronous RX fronthaul function (RRU) - void (*fh_north_in)(struct RU_t_s *ru, int *frame, int *subframe); - /// function pointer to synchronous RX fronthaul function (RRU) void (*fh_north_out)(struct RU_t_s *ru); /// function pointer to asynchronous fronthaul interface void (*fh_north_asynch_in)(struct RU_t_s *ru, int *frame, int *subframe); @@ -719,11 +715,4 @@ typedef struct RRU_config_s { MBSFN_config_t MBSFN_config[8]; } RRU_config_t; -typedef struct processingData_RU { - int frame_tx; - int slot_tx; - int next_slot; - openair0_timestamp_t timestamp_tx; - RU_t *ru; -} processingData_RU_t; #endif //__PHY_DEFS_RU__H__ diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index cfb869ada6..2ee6e6e0b3 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -337,6 +337,28 @@ typedef struct { // therefore, we can have up to "number of UE" UCI PDUs #define MAX_NUM_NR_UCI_PDUS MAX_MOBILES_PER_GNB +// Forward declaration — nr_fhi_t function pointers reference PHY_VARS_gNB +struct PHY_VARS_gNB_s; + +typedef void (*nr_fhi_ul_slot_ready_fn)(struct PHY_VARS_gNB_s *gNB, + int frame_tx, int slot_tx, + int frame_rx, int slot_rx, + uint64_t timestamp_tx); +typedef void (*nr_fhi_ul_slot_receive_fn)(struct PHY_VARS_gNB_s *gNB, + int *frame, int *slot); +typedef void (*nr_fhi_dl_slot_send_fn)(struct PHY_VARS_gNB_s *gNB, + int frame, int slot, + uint64_t timestamp); + +// NR fronthaul interface: abstracts per-slot DL send and UL-receive/ready notification +// across LOCAL_RF, IF5, IF4p5, and future 7.2 (xRAN) splits. +// Lives on openair0_device_t.fhi (rfdevice for LOCAL_RF, ifdevice for IF5/IF4p5). +typedef struct nr_fhi_s { + nr_fhi_ul_slot_ready_fn ul_slot_ready; // called by RU/xran when UL slot data is ready + nr_fhi_ul_slot_receive_fn ul_slot_receive; // called from ru_thread for all NR splits + nr_fhi_dl_slot_send_fn dl_slot_send; // called by tx_func after phy_procedures_gNB_TX +} nr_fhi_t; + /// Top-level PHY Data Structure for gNB typedef struct PHY_VARS_gNB_s { /// Module ID indicator for this instance diff --git a/radio/AW2SORI/oaiori.c b/radio/AW2SORI/oaiori.c index 2e1db159ab..79c64f5f7b 100644 --- a/radio/AW2SORI/oaiori.c +++ b/radio/AW2SORI/oaiori.c @@ -27,6 +27,8 @@ #include "ori.h" #include "radio/COMMON/common_lib.h" +#include "openair1/PHY/defs_gNB.h" +#include "openair1/SCHED_NR/sched_nr.h" typedef struct eutra_bandentry_s { int16_t band; @@ -884,9 +886,100 @@ int aw2s_oriinit(openair0_device_t *device) return 0; } +static void fh_if5_south_in(struct PHY_VARS_gNB_s *gNB, int *frame, int *tti) +{ + RU_t *ru = gNB->RU_list[0]; + NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; + RU_proc_t *proc = &ru->proc; + start_meas(&ru->rx_fhaul); + + ru->ifdevice.trx_read_func2(&ru->ifdevice, &proc->timestamp_rx, NULL, get_samples_per_slot(*tti, fp)); + if (proc->first_rx == 1) + ru->ts_offset = proc->timestamp_rx; + proc->frame_rx = ((proc->timestamp_rx - ru->ts_offset) / (fp->samples_per_subframe * 10)) & 1023; + proc->tti_rx = get_slot_from_timestamp(proc->timestamp_rx - ru->ts_offset, fp); + + if (proc->first_rx == 0) { + if (proc->tti_rx != *tti) { + LOG_E(PHY,"Received Timestamp doesn't correspond to the time we think it is (proc->tti_rx %d, subframe %d)\n",proc->tti_rx,*tti); + if (!oai_exit) + exit_fun("Exiting"); + return; + } + + if (proc->frame_rx != *frame) { + LOG_E(PHY,"Received Timestamp doesn't correspond to the time we think it is (proc->frame_rx %d frame %d proc->tti_rx %d tti %d)\n",proc->frame_rx,*frame,proc->tti_rx,*tti); + if (!oai_exit) + exit_fun("Exiting"); + return; + } + } else { + proc->first_rx = 0; + *frame = proc->frame_rx; + *tti = proc->tti_rx; + } + + stop_meas(&ru->rx_fhaul); + struct timespec rxmeas; + clock_gettime(CLOCK_MONOTONIC, &rxmeas); + double fhtime = ru->rx_fhaul.p_time/(cpu_freq_GHz*1000.0); + if (fhtime > 800) + LOG_W(PHY, + "IF5 %d.%d => RX %d.%d first_rx %d: time %f, rxstart %ld\n", + *frame, + *tti, + proc->frame_rx, + proc->tti_rx, + proc->first_rx, + ru->rx_fhaul.p_time / (cpu_freq_GHz * 1000.0), + rxmeas.tv_nsec); + else + LOG_D(PHY, + "IF5 %d.%d => RX %d.%d first_rx %d: time %f, rxstart %ld\n", + *frame, + *tti, + proc->frame_rx, + proc->tti_rx, + proc->first_rx, + ru->rx_fhaul.p_time / (cpu_freq_GHz * 1000.0), + rxmeas.tv_nsec); +} + +static void fh_if5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) +{ + int offset = get_samples_slot_timestamp(ru->nr_frame_parms, slot); + void *buffs[ru->nb_tx]; + for (int aid = 0; aid < ru->nb_tx; aid++) + buffs[aid] = (void*)&ru->common.txdata[aid][offset]; + struct timespec txmeas; + clock_gettime(CLOCK_MONOTONIC, &txmeas); + LOG_D(NR_PHY, + "IF5 TX %d.%d, TS %lu, buffs[0] %p, buffs[1] %p ener0 %f dB, tx start %d\n", + frame, + slot, + timestamp, + buffs[0], + buffs[1], + 10 * log10((double)signal_energy(buffs[0], get_samples_per_slot(slot, ru->nr_frame_parms))), + (int)txmeas.tv_nsec); + ru->ifdevice.trx_write_func2(&ru->ifdevice, timestamp, buffs, 0, get_samples_per_slot(slot, ru->nr_frame_parms), 0, ru->nb_tx); +} + +// IF5: IFFT+CP then write time-domain samples to IF5 Ethernet device +static void nr_fhi_if5_dl_slot_send(struct PHY_VARS_gNB_s *gNB, int frame, int slot, uint64_t timestamp) +{ + RU_t *ru = gNB->RU_list[0]; + nr_feptx_tp(ru, frame, slot); // Transmit Precoding + IDFTs + fh_if5_south_out(ru, frame, slot, timestamp); +} + int transport_init(openair0_device_t *device, openair0_config_t *openair0_cfg, eth_params_t *eth_params) { - printf("Initializing AW2S (%p,%p,%p)\n",aw2s_oriinit,aw2s_oricleanup,aw2s_startstreaming); + printf("Initializing AW2S (%p,%p,%p)\n",aw2s_oriinit,aw2s_oricleanup,aw2s_startstreaming); + device->fhi->ul_slot_receive = fh_if5_south_in; + device->fhi->dl_slot_send = nr_fhi_if5_dl_slot_send; + device->host_type = RAU_HOST; + device->eth_params = eth_params; device->thirdparty_init = aw2s_oriinit; device->thirdparty_cleanup = aw2s_oricleanup; device->thirdparty_startstreaming = aw2s_startstreaming; diff --git a/radio/COMMON/common_lib.h b/radio/COMMON/common_lib.h index 170837a29d..46a0831609 100644 --- a/radio/COMMON/common_lib.h +++ b/radio/COMMON/common_lib.h @@ -349,6 +349,9 @@ typedef struct { } queue[WRITE_QUEUE_SZ]; } re_order_t; +/* Forward declaration for NR fronthaul interface (defined in PHY/defs_gNB.h) */ +struct nr_fhi_s; + /*!\brief structure holds the parameters to configure RF devices */ struct openair0_device { /*!tx write thread*/ @@ -381,6 +384,9 @@ struct openair0_device { /*!brief Can be used by driver to hold internal structure*/ void *priv; + /*!brief NR fronthaul interface (dl_slot_send / ul_slot_ready callbacks) */ + struct nr_fhi_s *fhi; + /*!brief pointer to FH state, used in ECPRI split 8*/ fhstate_t fhstate; diff --git a/radio/USRP/usrp_lib.cpp b/radio/USRP/usrp_lib.cpp index 5b8b34c9ed..6c05069868 100644 --- a/radio/USRP/usrp_lib.cpp +++ b/radio/USRP/usrp_lib.cpp @@ -1056,6 +1056,7 @@ extern "C" { return 0; } + device->host_type = RAU_HOST; device->openair0_cfg = openair0_cfg; device->trx_start_func = trx_usrp_start; device->trx_get_stats_func = trx_usrp_get_stats; diff --git a/radio/fhi_72/oran.h b/radio/fhi_72/oran.h index d322f35f1e..896b8a0313 100644 --- a/radio/fhi_72/oran.h +++ b/radio/fhi_72/oran.h @@ -9,7 +9,7 @@ #include "common_lib.h" void oran_fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp); -void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot); +void oran_fh_if4p5_south_in(struct PHY_VARS_gNB_s *gNB, int *frame, int *slot); int transport_init(openair0_device_t *device, openair0_config_t *openair0_cfg, eth_params_t *eth_params); diff --git a/radio/fhi_72/oran_isolate.c b/radio/fhi_72/oran_isolate.c index 2d49c7726a..f54fe7b570 100644 --- a/radio/fhi_72/oran_isolate.c +++ b/radio/fhi_72/oran_isolate.c @@ -15,6 +15,7 @@ #include "openair1/PHY/defs_gNB.h" #include "oaioran.h" #include "oran-config.h" +#include "openair1/SCHED_NR/sched_nr.h" // needed for nr_feptx_prec(); maybe better move declaration and definition here in 7.2 since that's the only split which uses this function // include the following file for VERSIONX, version of xran lib, to print it during // startup. Only relevant for printing, if it ever makes problem, remove this @@ -27,9 +28,6 @@ #endif typedef struct { - eth_state_t e; - rru_config_msg_type_t last_msg; - int capabilities_sent; void *oran_priv; void *mplane_priv; uint32_t nCC; @@ -104,11 +102,13 @@ void trx_oran_end(openair0_device_t *device) oran_eth_state_t *s = device->priv; #if defined K_RELEASE xran_shutdown(s->oran_priv); -#endif - xran_close(s->oran_priv); -#if defined K_RELEASE + for (int32_t port_id = 0; port_id < s->num_ports; port_id++) { + xran_close(((void **)s->oran_priv)[port_id]); + } xran_cleanup(); xran_mem_mgr_leak_detector_destroy(); +#elif defined F_RELEASE + xran_close(s->oran_priv); #endif } @@ -143,18 +143,6 @@ int trx_oran_stop(openair0_device_t *device) return (0); } -int trx_oran_set_freq(openair0_device_t *device, openair0_config_t *openair0_cfg) -{ - printf("ORAN: %s\n", __FUNCTION__); - return (0); -} - -int trx_oran_set_gains(openair0_device_t *device, openair0_config_t *openair0_cfg) -{ - printf("ORAN: %s\n", __FUNCTION__); - return (0); -} - int trx_oran_get_stats(openair0_device_t *device) { uint64_t total_time, used_time; @@ -166,106 +154,9 @@ int trx_oran_get_stats(openair0_device_t *device) return (0); } -int trx_oran_reset_stats(openair0_device_t *device) -{ - printf("ORAN: %s\n", __FUNCTION__); - return (0); -} - -int ethernet_tune(openair0_device_t *device, unsigned int option, int value) -{ - printf("ORAN: %s\n", __FUNCTION__); - return 0; -} - -int trx_oran_write_raw(openair0_device_t *device, openair0_timestamp_t timestamp, void **buff, int nsamps, int cc, int flags) -{ - printf("ORAN: %s\n", __FUNCTION__); - return 0; -} - -int trx_oran_read_raw(openair0_device_t *device, openair0_timestamp_t *timestamp, void **buff, int nsamps, int cc) -{ - printf("ORAN: %s\n", __FUNCTION__); - return 0; -} - -char *msg_type(int t) -{ - static char *s[12] = { - "RAU_tick", - "RRU_capabilities", - "RRU_config", - "RRU_config_ok", - "RRU_start", - "RRU_stop", - "RRU_sync_ok", - "RRU_frame_resynch", - "RRU_MSG_max_num", - "RRU_check_sync", - "RRU_config_update", - "RRU_config_update_ok", - }; - - if (t < 0 || t > 11) - return "UNKNOWN"; - return s[t]; -} - -int trx_oran_ctlsend(openair0_device_t *device, void *msg, ssize_t msg_len) -{ - RRU_CONFIG_msg_t *rru_config_msg = msg; - oran_eth_state_t *s = device->priv; - - printf("ORAN: %s\n", __FUNCTION__); - - printf(" rru_config_msg->type %d [%s]\n", rru_config_msg->type, msg_type(rru_config_msg->type)); - - s->last_msg = rru_config_msg->type; - - return msg_len; -} - -int trx_oran_ctlrecv(openair0_device_t *device, void *msg, ssize_t msg_len) -{ - RRU_CONFIG_msg_t *rru_config_msg = msg; - oran_eth_state_t *s = device->priv; - - printf("ORAN: %s\n", __FUNCTION__); - - if (s->last_msg == RAU_tick && s->capabilities_sent == 0) { - printf("ORAN ctrlrcv RRU_tick received and send capabilities hard coded\n"); - RRU_capabilities_t *cap; - rru_config_msg->type = RRU_capabilities; - rru_config_msg->len = sizeof(RRU_CONFIG_msg_t) - MAX_RRU_CONFIG_SIZE + sizeof(RRU_capabilities_t); - // Fill RRU capabilities (see openair1/PHY/defs_RU.h) - // For now they are hard coded - try to retreive the params from openari device - - cap = (RRU_capabilities_t *)&rru_config_msg->msg[0]; - cap->FH_fmt = OAI_IF4p5_only; - cap->num_bands = 1; - cap->band_list[0] = 78; - // cap->num_concurrent_bands = 1; component carriers - cap->nb_rx[0] = 1; // device->openair0_cfg->rx_num_channels; - cap->nb_tx[0] = 1; // device->openair0_cfg->tx_num_channels; - cap->max_pdschReferenceSignalPower[0] = -27; - cap->max_rxgain[0] = 90; - cap->N_RB_DL[0] = 106; - cap->N_RB_UL[0] = 106; - - s->capabilities_sent = 1; - - return rru_config_msg->len; - } - if (s->last_msg == RRU_config) { - printf("Oran RRU_config\n"); - rru_config_msg->type = RRU_config_ok; - } - return 0; -} - -void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot) +void oran_fh_if4p5_south_in(struct PHY_VARS_gNB_s *gNB, int *frame, int *slot) { + RU_t *ru = gNB->RU_list[0]; int ret = 0; // return code for PUSCH/PRACH processing ru_info_t ru_info = { @@ -355,14 +246,22 @@ void oran_fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) stop_meas(&ru->tx_fhaul); } +// IF4p5: digital precoding on freq-domain txdataF (IFFT done at RRU). +// For ORAN/IF4p5, fh_south_out is set (via get_internal_parameter) to send +// the precoded frequency-domain samples over the fronthaul. +static void nr_fhi_if4p5_dl_slot_send(struct PHY_VARS_gNB_s *gNB, int frame, int slot, uint64_t timestamp) +{ + RU_t *ru = gNB->RU_list[0]; + nr_feptx_prec(ru, frame, slot); + oran_fh_if4p5_south_out(ru, frame, slot, timestamp); +} + void *get_internal_parameter(char *name) { printf("ORAN: %s\n", __FUNCTION__); if (!strcmp(name, "fh_if4p5_south_in")) return (void *)oran_fh_if4p5_south_in; - if (!strcmp(name, "fh_if4p5_south_out")) - return (void *)oran_fh_if4p5_south_out; return NULL; } @@ -450,25 +349,18 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device_t initNotifiedFIFO(&oran_sync_fifo_prach); #endif - eth->e.flags = ETH_RAW_IF4p5_MODE; - eth->e.compression = NO_COMPRESS; - eth->e.if_name = eth_params->local_if_name; - eth->last_msg = (rru_config_msg_type_t)-1; eth->nCC = fh_config->nCC; eth->num_ports = fh_init.xran_ports; + device->fhi->ul_slot_receive = oran_fh_if4p5_south_in; + device->fhi->dl_slot_send = nr_fhi_if4p5_dl_slot_send; + device->host_type = RAU_HOST; + device->eth_params = eth_params; device->transp_type = ETHERNET_TP; device->trx_start_func = trx_oran_start; device->trx_get_stats_func = trx_oran_get_stats; - device->trx_reset_stats_func = trx_oran_reset_stats; device->trx_end_func = trx_oran_end; device->trx_stop_func = trx_oran_stop; - device->trx_set_freq_func = trx_oran_set_freq; - device->trx_set_gains_func = trx_oran_set_gains; - device->trx_write_func = trx_oran_write_raw; - device->trx_read_func = trx_oran_read_raw; - device->trx_ctlsend_func = trx_oran_ctlsend; - device->trx_ctlrecv_func = trx_oran_ctlrecv; device->get_internal_parameter = get_internal_parameter; device->priv = eth; device->openair0_cfg = &openair0_cfg[0]; diff --git a/radio/rfsimulator/simulator.cpp b/radio/rfsimulator/simulator.cpp index 0acde168f0..4b34c59838 100644 --- a/radio/rfsimulator/simulator.cpp +++ b/radio/rfsimulator/simulator.cpp @@ -1627,6 +1627,7 @@ extern "C" __attribute__((__visibility__("default"))) int device_init(openair0_d } /* let's pretend to be a b2x0 */ device->type = RFSIMULATOR; + device->host_type = RAU_HOST; openair0_cfg->rx_gain[0] = 0; device->openair0_cfg = openair0_cfg; device->priv = rfsimulator;