Note: after this commit, monolithic works but nFAPI operation is broken and fixed in the next commit, to keep the changes small(er). All simulators work. This commit removes the use of msgDataTx's intermediate buffers for FAPI messages and the call of the "Schedule response". The latter incurs an additional copy of FAPI messages for the TX chain (for the RX chain, it is and will remain there) which we can avoid. Instead, it uses an NR_Sched_Rsp_t-typed variable sched_response to store the results of the scheduler when called from tx_func(). Thus, the scheduler remains unchanged (it gets a pointer to where to put FAPI messages), but we don't call nr_schedule_response() to then copy FAPI messages into the L1, but have them in a local variable sched_response. sched_response on on the data segment, as it is big and would overflow the stack; at the same time, this is ok because only one tx_func() runs at a time. Since we don't use allocate_sched_response() anymore, we don't need deref_sched_response(). clear_slot_beamid() is moved to tx_func(), as it was called in nr_schedule_response(). Since the "intermediate" NR_gNB_DLSCH_t structure groups both the DL_tti_pdsch and TX_data.req structures, a pointer has been created to point to pdsch_pdu. This affects a number of simulators, as they have to put some messages on the stack: - nr_dlschsim: put the corresponding variable on the stack - nr_pbchsim: a new array for the SSB PDUs has been introduced Further, these changes are now necessary: - nr_dlsim: there were variables "rel15" and "pdsch_pdu_rel15" that point to the same PDSCH PDU. At least "rel15" would not exist, as the corresponding pointer is now populated in phy_procedures_gNB_TX(), and we therefore refer to the single PDSCH PDU variable with "pdsch_pdu_rel15", but at the place where "rel15" used to be initialized. - nr_ulsim: use nr_save_ul_tti_req() to load PDUs into the RX chain instead of nr_schedule_response(), which does not exist anymore.
461 lines
18 KiB
C
461 lines
18 KiB
C
/*
|
|
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership.
|
|
* The OpenAirInterface Software Alliance licenses this file to You under
|
|
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.openairinterface.org/?page_id=698
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*-------------------------------------------------------------------------------
|
|
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
|
* contact@openairinterface.org
|
|
*/
|
|
|
|
/*! \file nr-gnb.c
|
|
* \brief Top-level threads for gNodeB
|
|
* \author R. Knopp, F. Kaltenberger, Navid Nikaein
|
|
* \date 2012
|
|
* \version 0.1
|
|
* \company Eurecom
|
|
* \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr, navid.nikaein@eurecom.fr
|
|
* \note
|
|
* \warning
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all
|
|
|
|
#include <fcntl.h> // for SEEK_SET
|
|
#include <pthread.h> // for pthread_join
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#include "common/utils/LOG/log.h"
|
|
#include "common/utils/system.h"
|
|
#include "PHY/NR_ESTIMATION/nr_ul_estimation.h"
|
|
#include "openair1/PHY/NR_TRANSPORT/nr_dlsch.h"
|
|
#include "openair1/PHY/NR_TRANSPORT/nr_ulsch.h"
|
|
#include "NR_PHY_INTERFACE/NR_IF_Module.h"
|
|
#include "PHY/INIT/nr_phy_init.h"
|
|
#include "PHY/MODULATION/nr_modulation.h"
|
|
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
|
|
#include "PHY/TOOLS/tools_defs.h"
|
|
#include "PHY/defs_RU.h"
|
|
#include "PHY/defs_common.h"
|
|
#include "PHY/defs_gNB.h"
|
|
#include "PHY/defs_nr_common.h"
|
|
#include "PHY/impl_defs_nr.h"
|
|
#include "SCHED_NR/fapi_nr_l1.h"
|
|
#include "SCHED_NR/phy_frame_config_nr.h"
|
|
#include "SCHED_NR/sched_nr.h"
|
|
#include "assertions.h"
|
|
#include "common/ran_context.h"
|
|
#include "common/utils/LOG/log.h"
|
|
#include "executables/softmodem-common.h"
|
|
#include "nfapi/oai_integration/vendor_ext.h"
|
|
#include "nfapi_nr_interface_scf.h"
|
|
#include "notified_fifo.h"
|
|
#include "openair2/NR_PHY_INTERFACE/nr_sched_response.h"
|
|
#include "thread-pool.h"
|
|
#include "time_meas.h"
|
|
#include "utils.h"
|
|
|
|
#define TICK_TO_US(ts) (ts.trials==0?0:ts.diff/ts.trials)
|
|
#define L1STATSSTRLEN 16384
|
|
static void rx_func(processingData_L1_t *param);
|
|
|
|
static void tx_func(processingData_L1tx_t *info)
|
|
{
|
|
int frame_tx = info->frame;
|
|
int slot_tx = info->slot;
|
|
int frame_rx = info->frame_rx;
|
|
int slot_rx = info->slot_rx;
|
|
LOG_D(NR_PHY, "%d.%d running tx_func\n", frame_tx, slot_tx);
|
|
PHY_VARS_gNB *gNB = info->gNB;
|
|
NR_IF_Module_t *ifi = gNB->if_inst;
|
|
nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config;
|
|
|
|
T(T_GNB_PHY_DL_TICK, T_INT(gNB->Mod_id), T_INT(frame_tx), T_INT(slot_tx));
|
|
|
|
if (slot_rx == 0) {
|
|
reset_active_stats(gNB, frame_rx);
|
|
reset_active_ulsch(gNB, frame_rx);
|
|
}
|
|
|
|
clear_slot_beamid(gNB, slot_tx);
|
|
|
|
nfapi_nr_slot_indication_scf_t ind = {.sfn = frame_tx, .slot = slot_tx};
|
|
start_meas(&gNB->slot_indication_stats);
|
|
// this variable is very big (multiple MB), so we put it into static storage
|
|
// to not overflow the stack while still having it in local (function) scope
|
|
// also, tx_func() is only executed by one thread, serially
|
|
static NR_Sched_Rsp_t sched_response;
|
|
ifi->NR_slot_indication(&ind, &sched_response);
|
|
stop_meas(&gNB->slot_indication_stats);
|
|
|
|
info->gNB = gNB;
|
|
|
|
// At this point, MAC scheduler just ran, including scheduling
|
|
// PRACH/PUCCH/PUSCH, so trigger RX chain processing
|
|
nr_save_ul_tti_req(gNB, &sched_response.UL_tti_req);
|
|
LOG_D(NR_PHY, "Trigger RX for %d.%d\n", frame_rx, slot_rx);
|
|
notifiedFIFO_elt_t *res = newNotifiedFIFO_elt(sizeof(processingData_L1_t), 0, &gNB->resp_L1, NULL);
|
|
processingData_L1_t *syncMsg = NotifiedFifoData(res);
|
|
syncMsg->gNB = gNB;
|
|
syncMsg->frame_rx = frame_rx;
|
|
syncMsg->slot_rx = slot_rx;
|
|
syncMsg->timestamp_tx = info->timestamp_tx;
|
|
res->key = slot_rx;
|
|
pushNotifiedFIFO(&gNB->resp_L1, res);
|
|
|
|
int tx_slot_type = nr_slot_select(cfg, frame_tx, slot_tx);
|
|
// TODO check for analog_beam_list is a workaround while no beam API for beam
|
|
// selection is implemented
|
|
if (tx_slot_type == NR_DOWNLINK_SLOT || tx_slot_type == NR_MIXED_SLOT || get_softmodem_params()->continuous_tx || IS_SOFTMODEM_RFSIM
|
|
|| cfg->analog_beamforming_ve.analog_beam_list) {
|
|
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,
|
|
1);
|
|
|
|
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);
|
|
stop_meas(&info->gNB->phy_proc_tx);
|
|
}
|
|
}
|
|
|
|
void *L1_rx_thread(void *arg)
|
|
{
|
|
PHY_VARS_gNB *gNB = (PHY_VARS_gNB*)arg;
|
|
|
|
while (oai_exit == 0) {
|
|
notifiedFIFO_elt_t *res = pullNotifiedFIFO(&gNB->resp_L1);
|
|
if (res == NULL)
|
|
break;
|
|
processingData_L1_t *info = (processingData_L1_t *)NotifiedFifoData(res);
|
|
start_meas(&gNB->l1_rx_proc);
|
|
rx_func(info);
|
|
stop_meas(&gNB->l1_rx_proc);
|
|
delNotifiedFIFO_elt(res);
|
|
}
|
|
return NULL;
|
|
}
|
|
// Added for URLLC, requires MAC scheduling to be split from UL indication
|
|
void *L1_tx_thread(void *arg) {
|
|
PHY_VARS_gNB *gNB = (PHY_VARS_gNB*)arg;
|
|
|
|
while (oai_exit == 0) {
|
|
notifiedFIFO_elt_t *res = pullNotifiedFIFO(&gNB->L1_tx_out);
|
|
if (res == NULL) // stopping condition, happens only when queue is freed
|
|
break;
|
|
processingData_L1tx_t *info = (processingData_L1tx_t *)NotifiedFifoData(res);
|
|
start_meas(&gNB->l1_tx_proc);
|
|
tx_func(info);
|
|
stop_meas(&gNB->l1_tx_proc);
|
|
delNotifiedFIFO_elt(res);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void rx_func(processingData_L1_t *info)
|
|
{
|
|
PHY_VARS_gNB *gNB = info->gNB;
|
|
int frame_rx = info->frame_rx;
|
|
int slot_rx = info->slot_rx;
|
|
nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config;
|
|
|
|
T(T_GNB_PHY_UL_TICK, T_INT(gNB->Mod_id), T_INT(frame_rx), T_INT(slot_rx));
|
|
|
|
// RX processing
|
|
int rx_slot_type = nr_slot_select(cfg, frame_rx, slot_rx);
|
|
if (rx_slot_type == NR_UPLINK_SLOT || rx_slot_type == NR_MIXED_SLOT) {
|
|
LOG_D(NR_PHY, "%d.%d Starting RX processing\n", frame_rx, slot_rx);
|
|
|
|
// UE-specific RX processing for subframe n
|
|
NR_UL_IND_t UL_INFO = {.frame = frame_rx, .slot = slot_rx, .module_id = gNB->Mod_id, .CC_id = gNB->CC_id};
|
|
// Do PRACH RU processing
|
|
UL_INFO.rach_ind.pdu_list = UL_INFO.prach_pdu_indication_list;
|
|
L1_nr_prach_procedures(gNB, frame_rx, slot_rx, &UL_INFO.rach_ind);
|
|
|
|
//WA: comment rotation in tx/rx
|
|
if (gNB->phase_comp) {
|
|
//apply the rx signal rotation here
|
|
int soffset = (slot_rx % RU_RX_SLOT_DEPTH) * gNB->frame_parms.symbols_per_slot * gNB->frame_parms.ofdm_symbol_size;
|
|
for (int bb = 0; bb < gNB->common_vars.num_beams_period; bb++) {
|
|
for (int aa = 0; aa < gNB->frame_parms.nb_antennas_rx; aa++) {
|
|
const uint max_symb = (gNB->frame_parms.Ncp == EXTENDED) ? 12 : 14;
|
|
for (int sym = 0; sym < max_symb; sym++)
|
|
apply_nr_rotation_symbol_RX(&gNB->frame_parms,
|
|
gNB->common_vars.rxdataF[bb][aa] + soffset + sym * gNB->frame_parms.ofdm_symbol_size,
|
|
gNB->frame_parms.symbol_rotation[1],
|
|
gNB->frame_parms.N_RB_UL,
|
|
slot_rx,
|
|
sym);
|
|
}
|
|
}
|
|
}
|
|
phy_procedures_gNB_uespec_RX(gNB, frame_rx, slot_rx, &UL_INFO);
|
|
|
|
// Call the scheduler
|
|
start_meas(&gNB->ul_indication_stats);
|
|
gNB->if_inst->NR_UL_indication(&UL_INFO);
|
|
stop_meas(&gNB->ul_indication_stats);
|
|
|
|
notifiedFIFO_elt_t *res = newNotifiedFIFO_elt(sizeof(processingData_L1_t), 0, &gNB->L1_rx_out, NULL);
|
|
processingData_L1_t *syncMsg = NotifiedFifoData(res);
|
|
syncMsg->gNB = gNB;
|
|
syncMsg->frame_rx = frame_rx;
|
|
syncMsg->slot_rx = slot_rx;
|
|
res->key = slot_rx;
|
|
LOG_D(NR_PHY, "Signaling completion for %d.%d (mod_slot %d) on L1_rx_out\n", frame_rx, slot_rx, slot_rx % RU_RX_SLOT_DEPTH);
|
|
pushNotifiedFIFO(&gNB->L1_rx_out, res);
|
|
}
|
|
|
|
}
|
|
|
|
static size_t dump_L1_meas_stats(PHY_VARS_gNB *gNB, RU_t *ru, char *output, size_t outputlen) {
|
|
const char *begin = output;
|
|
const char *end = output + outputlen;
|
|
output += print_meas_log(&gNB->l1_tx_proc, "L1 Tx job", NULL, NULL, output, end - output);
|
|
output += print_meas_log(&gNB->l1_rx_proc, "L1 Rx job", NULL, NULL, output, end - output);
|
|
output += print_meas_log(&gNB->phy_proc_tx, "L1 Tx processing", NULL, NULL, output, end - output);
|
|
output += print_meas_log(&gNB->dlsch_encoding_stats, "DLSCH encoding", NULL, NULL, output, end - output);
|
|
output += print_meas_log(&gNB->dlsch_scrambling_stats, "DLSCH scrambling", NULL, NULL, output, end-output);
|
|
output += print_meas_log(&gNB->dlsch_modulation_stats, "DLSCH modulation", NULL, NULL, output, end - output);
|
|
output += print_meas_log(&gNB->dlsch_resource_mapping_stats, "DLSCH resource mapping", NULL, NULL, output,end-output);
|
|
output += print_meas_log(&gNB->dlsch_precoding_stats, "DLSCH precoding", NULL, NULL, output,end-output);
|
|
output += print_meas_log(&gNB->phy_proc_rx, "L1 Rx processing", NULL, NULL, output, end - output);
|
|
output += print_meas_log(&gNB->ts_deinterleave, "UL segment deinterleaving", NULL, NULL, output, end - output);
|
|
output += print_meas_log(&gNB->ts_rate_unmatch, "UL segment rate recovery", NULL, NULL, output, end - output);
|
|
output += print_meas_log(&gNB->ts_ldpc_decode, "UL segments decoding", NULL, NULL, output, end - output);
|
|
output += print_meas_log(&gNB->ul_indication_stats, "UL Indication", NULL, NULL, output, end - output);
|
|
output += print_meas_log(&gNB->slot_indication_stats, "Slot Indication", NULL, NULL, output, end - output);
|
|
output += print_meas_log(&gNB->rx_pusch_stats, "PUSCH inner-receiver", NULL, NULL, output, end - output);
|
|
output += print_meas_log(&gNB->schedule_response_stats, "Schedule Response", NULL, NULL, output, end - output);
|
|
output += print_meas_log(&gNB->rx_prach, "PRACH RX", NULL, NULL, output, end - output);
|
|
if (ru->feprx)
|
|
output += print_meas_log(&ru->ofdm_demod_stats, "feprx", NULL, NULL, output, end - output);
|
|
|
|
bool full_slot = ru->half_slot_parallelization == 0;
|
|
if (ru->feptx_prec) {
|
|
output += print_meas_log(&ru->precoding_stats,
|
|
full_slot ? "feptx_prec (per port)" : "feptx_prec (per port, half_slot)",
|
|
NULL,
|
|
NULL,
|
|
output,
|
|
end - output);
|
|
}
|
|
|
|
if (ru->feptx_ofdm) {
|
|
output += print_meas_log(&ru->txdataF_copy_stats,"txdataF_copy",NULL,NULL, output, end - output);
|
|
output += print_meas_log(&ru->ofdm_mod_stats,
|
|
full_slot ? "feptx_ofdm (per port)" : "feptx_ofdm (per port, half_slot)",
|
|
NULL,
|
|
NULL,
|
|
output,
|
|
end - output);
|
|
output += print_meas_log(&ru->ofdm_total_stats,"feptx_total",NULL,NULL, output, end - output);
|
|
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;
|
|
}
|
|
|
|
void *nrL1_stats_thread(void *param) {
|
|
PHY_VARS_gNB *gNB = (PHY_VARS_gNB *)param;
|
|
RU_t *ru = RC.ru[0];
|
|
char output[L1STATSSTRLEN];
|
|
memset(output,0,L1STATSSTRLEN);
|
|
wait_sync("L1_stats_thread");
|
|
FILE *fd=fopen("nrL1_stats.log","w");
|
|
if (!fd) {
|
|
LOG_W(NR_PHY, "Cannot open nrL1_stats.log: %d, %s\n", errno, strerror(errno));
|
|
return NULL;
|
|
}
|
|
|
|
reset_meas(&gNB->l1_tx_proc);
|
|
reset_meas(&gNB->l1_rx_proc);
|
|
reset_meas(&gNB->phy_proc_tx);
|
|
reset_meas(&gNB->dlsch_encoding_stats);
|
|
reset_meas(&gNB->phy_proc_rx);
|
|
reset_meas(&gNB->ts_deinterleave);
|
|
reset_meas(&gNB->ts_rate_unmatch);
|
|
reset_meas(&gNB->ts_ldpc_decode);
|
|
reset_meas(&gNB->ul_indication_stats);
|
|
reset_meas(&gNB->slot_indication_stats);
|
|
reset_meas(&gNB->rx_pusch_stats);
|
|
reset_meas(&gNB->schedule_response_stats);
|
|
reset_meas(&gNB->dlsch_scrambling_stats);
|
|
reset_meas(&gNB->dlsch_modulation_stats);
|
|
reset_meas(&gNB->dlsch_resource_mapping_stats);
|
|
reset_meas(&gNB->dlsch_precoding_stats);
|
|
while (!oai_exit) {
|
|
sleep(1);
|
|
if (ftruncate(fileno(fd), 0) != 0 || fseek(fd, 0, SEEK_SET) != 0) {
|
|
LOG_E(NR_MAC, "error while writing nrL1_stats.log: %d, %s\n", errno, strerror(errno));
|
|
break;
|
|
}
|
|
dump_nr_I0_stats(fd,gNB);
|
|
dump_pdsch_stats(fd,gNB);
|
|
dump_pusch_stats(fd,gNB);
|
|
dump_L1_meas_stats(gNB, ru, output, L1STATSSTRLEN);
|
|
fprintf(fd,"%s\n",output);
|
|
fflush(fd);
|
|
}
|
|
fclose(fd);
|
|
return(NULL);
|
|
}
|
|
|
|
void init_gNB_Tpool(int inst)
|
|
{
|
|
AssertFatal(NFAPI_MODE == NFAPI_MODE_PNF || NFAPI_MODE == NFAPI_MONOLITHIC,
|
|
"illegal NFAPI_MODE %d (%s): it cannot have an L1\n",
|
|
NFAPI_MODE,
|
|
nfapi_get_strmode());
|
|
|
|
PHY_VARS_gNB *gNB;
|
|
gNB = RC.gNB[inst];
|
|
gNB_L1_proc_t *proc = &gNB->proc;
|
|
// PUSCH symbols per thread need to be calculated by how many threads we have
|
|
gNB->num_pusch_symbols_per_thread = 1;
|
|
// ULSCH decoding threadpool
|
|
initTpool(get_softmodem_params()->threadPoolConfig, &gNB->threadPool, cpumeas(CPUMEAS_GETSTATE));
|
|
|
|
// L1 RX result FIFO
|
|
initNotifiedFIFO(&gNB->resp_L1);
|
|
// L1 TX result FIFO
|
|
initNotifiedFIFO(&gNB->L1_tx_out);
|
|
initNotifiedFIFO(&gNB->L1_rx_out);
|
|
|
|
// create the RX thread responsible for RX processing start event (resp_L1 msg queue), then launch rx_func()
|
|
threadCreate(&gNB->L1_rx_thread, L1_rx_thread, (void *)gNB, "L1_rx_thread", gNB->L1_rx_thread_core, OAI_PRIORITY_RT_MAX);
|
|
// create the TX thread responsible for TX processing start event (L1_tx_out msg queue), then launch tx_func()
|
|
threadCreate(&gNB->L1_tx_thread, L1_tx_thread, (void *)gNB, "L1_tx_thread", gNB->L1_tx_thread_core, OAI_PRIORITY_RT_MAX);
|
|
|
|
notifiedFIFO_elt_t *msgL1Tx = newNotifiedFIFO_elt(sizeof(processingData_L1tx_t), 0, &gNB->L1_tx_out, NULL);
|
|
processingData_L1tx_t *msgDataTx = (processingData_L1tx_t *)NotifiedFifoData(msgL1Tx);
|
|
memset(msgDataTx, 0, sizeof(processingData_L1tx_t));
|
|
// this will be removed when the msgDataTx is not necessary anymore
|
|
gNB->msgDataTx = msgDataTx;
|
|
|
|
if (!IS_SOFTMODEM_NOSTATS)
|
|
threadCreate(&proc->L1_stats_thread, nrL1_stats_thread, (void *)gNB, "L1_stats", -1, OAI_PRIORITY_RT_LOW);
|
|
}
|
|
|
|
void term_gNB_Tpool(int inst) {
|
|
PHY_VARS_gNB *gNB = RC.gNB[inst];
|
|
abortNotifiedFIFO(&gNB->resp_L1);
|
|
pthread_join(gNB->L1_rx_thread, NULL);
|
|
abortNotifiedFIFO(&gNB->L1_tx_out);
|
|
pthread_join(gNB->L1_tx_thread, NULL);
|
|
|
|
abortTpool(&gNB->threadPool);
|
|
abortNotifiedFIFO(&gNB->L1_rx_out);
|
|
|
|
gNB_L1_proc_t *proc = &gNB->proc;
|
|
pthread_join(proc->L1_stats_thread, NULL);
|
|
}
|
|
|
|
/// eNB kept in function name for nffapi calls, TO FIX
|
|
void init_eNB_afterRU(void)
|
|
{
|
|
for (int inst = 0; inst < RC.nb_nr_L1_inst; inst++) {
|
|
PHY_VARS_gNB *gNB = RC.gNB[inst];
|
|
phy_init_nr_gNB(gNB);
|
|
|
|
// map antennas and PRACH signals to gNB RX
|
|
if (0) AssertFatal(gNB->num_RU>0,"Number of RU attached to gNB %d is zero\n",gNB->Mod_id);
|
|
|
|
LOG_D(NR_PHY, "Mapping RX ports from %d RUs to gNB %d\n", gNB->num_RU, gNB->Mod_id);
|
|
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);
|
|
for (int i = 0; i < gNB->RU_list[ru_id]->nb_rx; aa++, i++) {
|
|
LOG_I(PHY, "Attaching RU %d antenna %d to gNB antenna %d\n", gNB->RU_list[ru_id]->idx, i, aa);
|
|
for (int b = 0; b < gNB->RU_list[ru_id]->num_beams_period; b++) {
|
|
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];
|
|
}
|
|
}
|
|
}
|
|
/* TODO: review this code, there is something wrong.
|
|
* In monolithic mode, we come here with nb_antennas_rx == 0
|
|
* (not tested in other modes).
|
|
*/
|
|
//init_precoding_weights(RC.gNB[inst]);
|
|
init_gNB_Tpool(inst);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Initialize gNB struct in RAN context
|
|
*/
|
|
void init_gNB()
|
|
{
|
|
LOG_I(NR_PHY, "Initializing gNB RAN context: RC.nb_nr_L1_inst = %d \n", RC.nb_nr_L1_inst);
|
|
if (RC.gNB == NULL) {
|
|
RC.gNB = (PHY_VARS_gNB **)calloc_or_fail(RC.nb_nr_L1_inst, sizeof(PHY_VARS_gNB *));
|
|
LOG_D(NR_PHY, "gNB L1 structure RC.gNB allocated @ %p\n", RC.gNB);
|
|
}
|
|
|
|
for (int inst = 0; inst < RC.nb_nr_L1_inst; inst++) {
|
|
// Allocate L1 instance
|
|
if (RC.gNB[inst] == NULL) {
|
|
RC.gNB[inst] = (PHY_VARS_gNB *)calloc_or_fail(1, sizeof(PHY_VARS_gNB));
|
|
LOG_D(NR_PHY, "[nr-gnb.c] gNB structure RC.gNB[%d] allocated @ %p\n", inst, RC.gNB[inst]);
|
|
}
|
|
PHY_VARS_gNB *gNB = RC.gNB[inst];
|
|
LOG_D(NR_PHY, "Initializing gNB %d\n", inst);
|
|
|
|
// Init module ID
|
|
gNB->Mod_id = inst;
|
|
|
|
// Register MAC interface module
|
|
AssertFatal((gNB->if_inst = NR_IF_Module_init(inst)) != NULL, "Cannot register interface");
|
|
|
|
LOG_I(NR_PHY, "Registered with MAC interface module (%p)\n", gNB->if_inst);
|
|
gNB->if_inst->NR_Schedule_response = nr_schedule_response;
|
|
gNB->if_inst->NR_PHY_config_req = nr_phy_config_request;
|
|
|
|
gNB->prach_energy_counter = 0;
|
|
gNB->chest_time = get_softmodem_params()->chest_time;
|
|
gNB->chest_freq = get_softmodem_params()->chest_freq;
|
|
}
|
|
}
|
|
|
|
void stop_gNB(int nb_inst) {
|
|
for (int inst=0; inst<nb_inst; inst++) {
|
|
LOG_I(PHY,"Killing gNB %d processing threads\n",inst);
|
|
term_gNB_Tpool(inst);
|
|
}
|
|
}
|