nr-gnb.c 26.9 KB
Newer Older
laurent's avatar
laurent committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
/*
 * 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 lte-enb.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
#include <pthread.h>

#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all

#include "assertions.h"
Laurent's avatar
Laurent committed
39 40
#include <common/utils/LOG/log.h>
#include <common/utils/system.h>
41
#include "rt_profiling.h"
laurent's avatar
laurent committed
42 43 44

#include "PHY/types.h"

45
#include "PHY/INIT/nr_phy_init.h"
laurent's avatar
laurent committed
46 47 48 49 50

#include "PHY/defs_gNB.h"
#include "SCHED/sched_eNB.h"
#include "SCHED_NR/sched_nr.h"
#include "SCHED_NR/fapi_nr_l1.h"
cig's avatar
cig committed
51
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
52
#include "PHY/MODULATION/nr_modulation.h"
53
#include "PHY/NR_TRANSPORT/nr_dlsch.h"
54
#include "openair2/NR_PHY_INTERFACE/nr_sched_response.h"
laurent's avatar
laurent committed
55 56 57 58

#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all
//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all

francescomani's avatar
francescomani committed
59
#include "radio/COMMON/common_lib.h"
laurent's avatar
laurent committed
60 61 62 63 64 65 66

//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all

#include "PHY/LTE_TRANSPORT/if4_tools.h"

#include "PHY/phy_extern.h"

67
#include "common/ran_context.h"
laurent's avatar
laurent committed
68 69 70 71 72 73 74 75 76
#include "RRC/LTE/rrc_extern.h"
#include "PHY_INTERFACE/phy_interface.h"
#include "common/utils/LOG/log_extern.h"
#include "UTIL/OTG/otg_tx.h"
#include "UTIL/OTG/otg_externs.h"
#include "UTIL/MATH/oml.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
#include "UTIL/OPT/opt.h"
#include "enb_config.h"
77
#include "gnb_paramdef.h"
laurent's avatar
laurent committed
78

79 80
#include "s1ap_eNB.h"
#include "SIMULATION/ETH_TRANSPORT/proto.h"
81
#include <executables/softmodem-common.h>
laurent's avatar
laurent committed
82 83

#include "T.h"
Mahesh's avatar
Mahesh committed
84
#include "nfapi/oai_integration/vendor_ext.h"
Sakthivel Velumani's avatar
Sakthivel Velumani committed
85
#include "executables/softmodem-common.h"
Laurent THOMAS's avatar
Laurent THOMAS committed
86
#include <nfapi/oai_integration/nfapi_pnf.h>
87
#include <openair1/PHY/NR_TRANSPORT/nr_ulsch.h>
rmagueta's avatar
rmagueta committed
88
#include <openair1/PHY/NR_TRANSPORT/nr_dlsch.h>
rmagueta's avatar
rmagueta committed
89
#include <PHY/NR_ESTIMATION/nr_ul_estimation.h>
laurent's avatar
laurent committed
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104

//#define USRP_DEBUG 1
// Fix per CC openair rf/if device update
// extern openair0_device openair0;


//pthread_t                       main_gNB_thread;

time_stats_t softmodem_stats_mt; // main thread
time_stats_t softmodem_stats_hw; //  hw acquisition
time_stats_t softmodem_stats_rxtx_sf; // total tx time
time_stats_t nfapi_meas; // total tx time
time_stats_t softmodem_stats_rx_sf; // total rx time


105
#include "executables/thread-common.h"
laurent's avatar
laurent committed
106 107 108 109


//#define TICK_TO_US(ts) (ts.diff)
#define TICK_TO_US(ts) (ts.trials==0?0:ts.diff/ts.trials)
110
#define L1STATSSTRLEN 16384
laurent's avatar
laurent committed
111 112


113 114
void tx_func(void *param) 
{
115
  processingData_L1tx_t *info = (processingData_L1tx_t *) param;
116
  PHY_VARS_gNB *gNB = info->gNB;
Sakthivel Velumani's avatar
Sakthivel Velumani committed
117 118
  int frame_tx = info->frame;
  int slot_tx = info->slot;
119
  int cumul_samples = gNB->frame_parms.get_samples_per_slot(0, &gNB->frame_parms);
120 121
  int i = 1;
  for (; i < gNB->frame_parms.slots_per_subframe / 2; i++)
122
    cumul_samples += gNB->frame_parms.get_samples_per_slot(i, &gNB->frame_parms);
123
  int samples = cumul_samples / i;
124 125
  int absslot_tx = info->timestamp_tx / samples;
  int absslot_rx = absslot_tx - gNB->RU_list[0]->sl_ahead;
126
  int rt_prof_idx = absslot_rx % RT_PROF_DEPTH;
127
  start_meas(&gNB->phy_proc_tx);
128

129
  clock_gettime(CLOCK_MONOTONIC, &gNB->rt_L1_profiling.start_L1_TX[rt_prof_idx]);
130 131 132 133
  phy_procedures_gNB_TX(info,
                        frame_tx,
                        slot_tx,
                        1);
134
  clock_gettime(CLOCK_MONOTONIC, &gNB->rt_L1_profiling.return_L1_TX[rt_prof_idx]);
135

136 137 138 139 140 141 142 143 144
  if (get_softmodem_params()->reorder_thread_disable) {
    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);
  }
145 146
  /* this thread is done with the sched_info, decrease the reference counter */
  deref_sched_response(info->sched_response_id);
147
  stop_meas(&gNB->phy_proc_tx);
148 149 150
}


151 152
void *L1_rx_thread(void *arg) 
{
153 154 155 156 157 158 159 160 161
  PHY_VARS_gNB *gNB = (PHY_VARS_gNB*)arg;

  while (oai_exit == 0) {
     notifiedFIFO_elt_t *res = pullNotifiedFIFO(&gNB->resp_L1);
     processingData_L1_t *info = (processingData_L1_t *)NotifiedFifoData(res);
     rx_func(info);
     delNotifiedFIFO_elt(res);
  }
  return NULL;
162
}
163
/* to be added for URLLC, requires MAC scheduling to be split from UL indication 
164 165 166 167 168 169 170 171 172 173 174
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);
     processingData_L1tx_t *info = (processingData_L1tx_t *)NotifiedFifoData(res);
     tx_func(info);
     delNotifiedFIFO_elt(res);
  }
  return NULL;
}
175
*/
176 177
void rx_func(void *param)
{
178 179 180 181 182 183
  processingData_L1_t *info = (processingData_L1_t *) param;
  PHY_VARS_gNB *gNB = info->gNB;
  int frame_rx = info->frame_rx;
  int slot_rx = info->slot_rx;
  int frame_tx = info->frame_tx;
  int slot_tx = info->slot_tx;
184
  nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config;
185
  int cumul_samples = gNB->frame_parms.get_samples_per_slot(0, &gNB->frame_parms);
186 187
  int i = 1;
  for (; i < gNB->frame_parms.slots_per_subframe / 2; i++)
188
    cumul_samples += gNB->frame_parms.get_samples_per_slot(i, &gNB->frame_parms);
189
  int samples = cumul_samples / i;
190
  int absslot_tx = info->timestamp_tx / samples;
191 192 193
  int absslot_rx = absslot_tx - gNB->RU_list[0]->sl_ahead;
  int rt_prof_idx = absslot_rx % RT_PROF_DEPTH;
  clock_gettime(CLOCK_MONOTONIC,&info->gNB->rt_L1_profiling.start_L1_RX[rt_prof_idx]);
laurent's avatar
laurent committed
194 195 196
  start_meas(&softmodem_stats_rxtx_sf);

  // *******************************************************************
197

198
  if (NFAPI_MODE == NFAPI_MODE_PNF) {
laurent's avatar
laurent committed
199
    // I am a PNF and I need to let nFAPI know that we have a (sub)frame tick
200
    //LOG_D(PHY, "oai_nfapi_slot_ind(frame:%u, slot:%d) ********\n", frame_rx, slot_rx);
laurent's avatar
laurent committed
201
    start_meas(&nfapi_meas);
202
    handle_nr_slot_ind(frame_rx, slot_rx);
laurent's avatar
laurent committed
203 204
    stop_meas(&nfapi_meas);

205
    /*if (gNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus||
laurent's avatar
laurent committed
206 207
        gNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs ||
        gNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs ||
208
        gNB->UL_INFO.rach_ind.number_of_pdus ||
laurent's avatar
laurent committed
209 210
        gNB->UL_INFO.cqi_ind.number_of_cqis
       ) {
211
      LOG_D(PHY, "UL_info[rx_ind:%05d:%d harqs:%05d:%d crcs:%05d:%d rach_pdus:%0d.%d:%d cqis:%d] RX:%04d%d TX:%04d%d \n",
laurent's avatar
laurent committed
212 213 214
            NFAPI_SFNSF2DEC(gNB->UL_INFO.rx_ind.sfn_sf),   gNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus,
            NFAPI_SFNSF2DEC(gNB->UL_INFO.harq_ind.sfn_sf), gNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs,
            NFAPI_SFNSF2DEC(gNB->UL_INFO.crc_ind.sfn_sf),  gNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs,
215
            gNB->UL_INFO.rach_ind.sfn, gNB->UL_INFO.rach_ind.slot,gNB->UL_INFO.rach_ind.number_of_pdus,
laurent's avatar
laurent committed
216
            gNB->UL_INFO.cqi_ind.number_of_cqis,
217 218
            frame_rx, slot_rx,
            frame_tx, slot_tx);
219
    }*/
laurent's avatar
laurent committed
220 221
  }
  // ****************************************
222

223
  T(T_GNB_PHY_DL_TICK, T_INT(gNB->Mod_id), T_INT(frame_tx), T_INT(slot_tx));
224

francescomani's avatar
francescomani committed
225 226
  reset_active_stats(gNB, frame_tx);
  reset_active_ulsch(gNB, frame_tx);
227

228
  // RX processing
francescomani's avatar
francescomani committed
229
  int rx_slot_type = nr_slot_select(cfg, frame_rx, slot_rx);
230 231 232
  if (rx_slot_type == NR_UPLINK_SLOT || rx_slot_type == NR_MIXED_SLOT) {
    // UE-specific RX processing for subframe n
    // TODO: check if this is correct for PARALLEL_RU_L1_TRX_SPLIT
233 234

    // Do PRACH RU processing
235
    L1_nr_prach_procedures(gNB,frame_rx,slot_rx);
236

237 238 239
    //WA: comment rotation in tx/rx
    if((gNB->num_RU == 1) && (gNB->RU_list[0]->if_south != REMOTE_IF4p5)) {
      //apply the rx signal rotation here
240
      int soffset = (slot_rx & 3) * gNB->frame_parms.symbols_per_slot * gNB->frame_parms.ofdm_symbol_size;
241
      for (int aa = 0; aa < gNB->frame_parms.nb_antennas_rx; aa++) {
242 243 244 245 246 247 248 249
        apply_nr_rotation_RX(&gNB->frame_parms,
                             gNB->common_vars.rxdataF[aa],
                             gNB->frame_parms.symbol_rotation[1],
                             slot_rx,
                             gNB->frame_parms.N_RB_UL,
                             soffset,
                             0,
                             gNB->frame_parms.Ncp == EXTENDED ? 12 : 14);
250
      }
251
    }
252 253 254
    phy_procedures_gNB_uespec_RX(gNB, frame_rx, slot_rx);
  }

255
  stop_meas( &softmodem_stats_rxtx_sf );
256
  LOG_D(PHY,"%s() Exit proc[rx:%d%d tx:%d%d]\n", __FUNCTION__, frame_rx, slot_rx, frame_tx, slot_tx);
257
  clock_gettime(CLOCK_MONOTONIC,&info->gNB->rt_L1_profiling.return_L1_RX[rt_prof_idx]);
laurent's avatar
laurent committed
258

259 260
  // Call the scheduler
  start_meas(&gNB->ul_indication_stats);
261
//  pthread_mutex_lock(&gNB->UL_INFO_mutex);
262 263 264 265 266
  gNB->UL_INFO.frame     = frame_rx;
  gNB->UL_INFO.slot      = slot_rx;
  gNB->UL_INFO.module_id = gNB->Mod_id;
  gNB->UL_INFO.CC_id     = gNB->CC_id;
  gNB->if_inst->NR_UL_indication(&gNB->UL_INFO);
267
//  pthread_mutex_unlock(&gNB->UL_INFO_mutex);
268
  stop_meas(&gNB->ul_indication_stats);
269

270
  int tx_slot_type = nr_slot_select(cfg,frame_tx,slot_tx);
271
  if ((tx_slot_type == NR_DOWNLINK_SLOT || tx_slot_type == NR_MIXED_SLOT) && NFAPI_MODE != NFAPI_MODE_PNF) {
272
    notifiedFIFO_elt_t *res;
273 274 275
    processingData_L1tx_t *syncMsg;
    // Its a FIFO so it maitains the order in which the MAC fills the messages
    // so no need for checking for right slot
276 277 278 279 280 281 282
    if (get_softmodem_params()->reorder_thread_disable) {
      // call the TX function directly from this thread
      syncMsg = gNB->msgDataTx;
      syncMsg->gNB = gNB; 
      syncMsg->timestamp_tx = info->timestamp_tx;
      tx_func(syncMsg);
    } else {
283
      res = pullTpool(&gNB->L1_tx_filled, &gNB->threadPool);
284 285 286 287 288 289 290 291
      if (res == NULL)
        return; // Tpool has been stopped
      syncMsg = (processingData_L1tx_t *)NotifiedFifoData(res);
      syncMsg->gNB = gNB;
      syncMsg->timestamp_tx = info->timestamp_tx;
      res->key = slot_tx;
      pushTpool(&gNB->threadPool, res);
    }
292
  } else if (get_softmodem_params()->continuous_tx) {
293
    notifiedFIFO_elt_t *res = pullNotifiedFIFO(&gNB->L1_tx_free);
294 295
    if (res == NULL)
      return; // Tpool has been stopped
296 297 298 299 300 301
    processingData_L1tx_t *syncMsg = (processingData_L1tx_t *)NotifiedFifoData(res);
    syncMsg->gNB = gNB;
    syncMsg->timestamp_tx = info->timestamp_tx;
    syncMsg->frame = frame_tx;
    syncMsg->slot = slot_tx;
    res->key = slot_tx;
302
    pushNotifiedFIFO(&gNB->L1_tx_out, res);
laurent's avatar
laurent committed
303
  }
304

laurent's avatar
laurent committed
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
#if 0
  LOG_D(PHY, "rxtx:%lld nfapi:%lld phy:%lld tx:%lld rx:%lld prach:%lld ofdm:%lld ",
        softmodem_stats_rxtx_sf.diff_now, nfapi_meas.diff_now,
        TICK_TO_US(gNB->phy_proc),
        TICK_TO_US(gNB->phy_proc_tx),
        TICK_TO_US(gNB->phy_proc_rx),
        TICK_TO_US(gNB->rx_prach),
        TICK_TO_US(gNB->ofdm_mod_stats),
        softmodem_stats_rxtx_sf.diff_now, nfapi_meas.diff_now);
  LOG_D(PHY,
        "dlsch[enc:%lld mod:%lld scr:%lld rm:%lld t:%lld i:%lld] rx_dft:%lld ",
        TICK_TO_US(gNB->dlsch_encoding_stats),
        TICK_TO_US(gNB->dlsch_modulation_stats),
        TICK_TO_US(gNB->dlsch_scrambling_stats),
        TICK_TO_US(gNB->dlsch_rate_matching_stats),
        TICK_TO_US(gNB->dlsch_turbo_encoding_stats),
        TICK_TO_US(gNB->dlsch_interleaving_stats),
        TICK_TO_US(gNB->rx_dft_stats));
  LOG_D(PHY," ulsch[ch:%lld freq:%lld dec:%lld demod:%lld ru:%lld ",
        TICK_TO_US(gNB->ulsch_channel_estimation_stats),
        TICK_TO_US(gNB->ulsch_freq_offset_estimation_stats),
        TICK_TO_US(gNB->ulsch_decoding_stats),
        TICK_TO_US(gNB->ulsch_demodulation_stats),
        TICK_TO_US(gNB->ulsch_rate_unmatching_stats));
  LOG_D(PHY, "td:%lld dei:%lld dem:%lld llr:%lld tci:%lld ",
        TICK_TO_US(gNB->ulsch_turbo_decoding_stats),
        TICK_TO_US(gNB->ulsch_deinterleaving_stats),
        TICK_TO_US(gNB->ulsch_demultiplexing_stats),
        TICK_TO_US(gNB->ulsch_llr_stats),
        TICK_TO_US(gNB->ulsch_tc_init_stats));
  LOG_D(PHY, "tca:%lld tcb:%lld tcg:%lld tce:%lld l1:%lld l2:%lld]\n\n",
        TICK_TO_US(gNB->ulsch_tc_alpha_stats),
        TICK_TO_US(gNB->ulsch_tc_beta_stats),
        TICK_TO_US(gNB->ulsch_tc_gamma_stats),
        TICK_TO_US(gNB->ulsch_tc_ext_stats),
        TICK_TO_US(gNB->ulsch_tc_intl1_stats),
        TICK_TO_US(gNB->ulsch_tc_intl2_stats)
       );
#endif
}
345 346 347 348 349
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->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);
350 351 352 353 354
  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_layer_mapping_stats, "DLSCH layer mapping", 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);
355 356 357 358 359 360 361
  output += print_meas_log(&gNB->phy_proc_rx, "L1 Rx processing", 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->rx_pusch_stats, "PUSCH inner-receiver", NULL, NULL, output, end - output);
  output += print_meas_log(&gNB->ulsch_decoding_stats, "PUSCH decoding", NULL, NULL, output, end - output);
  output += print_meas_log(&gNB->schedule_response_stats, "Schedule Response", NULL, NULL, output, end - output);
  if (ru->feprx)
    output += print_meas_log(&ru->ofdm_demod_stats, "feprx", NULL, NULL, output, end - output);
362 363

  if (ru->feptx_ofdm) {
364 365 366 367
    output += print_meas_log(&ru->precoding_stats,"feptx_prec",NULL,NULL, output, end - output);
    output += print_meas_log(&ru->txdataF_copy_stats,"txdataF_copy",NULL,NULL, output, end - output);
    output += print_meas_log(&ru->ofdm_mod_stats,"feptx_ofdm",NULL,NULL, output, end - output);
    output += print_meas_log(&ru->ofdm_total_stats,"feptx_total",NULL,NULL, output, end - output);
368
  }
369

370 371
  if (ru->fh_north_asynch_in)
    output += print_meas_log(&ru->rx_fhaul,"rx_fhaul",NULL,NULL, output, end - output);
372

373
  output += print_meas_log(&ru->tx_fhaul,"tx_fhaul",NULL,NULL, output, end - output);
374

375
  if (ru->fh_north_out) {
376 377
    output += print_meas_log(&ru->compression,"compression",NULL,NULL, output, end - output);
    output += print_meas_log(&ru->transport,"transport",NULL,NULL, output, end - output);
378
  }
379
  return output - begin;
380 381
}

382 383
void *nrL1_stats_thread(void *param) {
  PHY_VARS_gNB     *gNB      = (PHY_VARS_gNB *)param;
384 385 386
  RU_t *ru = RC.ru[0];
  char output[L1STATSSTRLEN];
  memset(output,0,L1STATSSTRLEN);
387 388
  wait_sync("L1_stats_thread");
  FILE *fd;
389 390 391
  fd=fopen("nrL1_stats.log","w");
  AssertFatal(fd!=NULL,"Cannot open nrL1_stats.log\n");

392
  reset_meas(&gNB->phy_proc_tx);
393 394 395 396 397
  reset_meas(&gNB->dlsch_encoding_stats);
  reset_meas(&gNB->phy_proc_rx);
  reset_meas(&gNB->ul_indication_stats);
  reset_meas(&gNB->rx_pusch_stats);
  reset_meas(&gNB->ulsch_decoding_stats);
398
  reset_meas(&gNB->schedule_response_stats);
399 400 401 402 403
  reset_meas(&gNB->dlsch_scrambling_stats);
  reset_meas(&gNB->dlsch_modulation_stats);
  reset_meas(&gNB->dlsch_layer_mapping_stats);
  reset_meas(&gNB->dlsch_resource_mapping_stats);
  reset_meas(&gNB->dlsch_precoding_stats);
404 405 406
  while (!oai_exit) {
    sleep(1);
    dump_nr_I0_stats(fd,gNB);
407
    dump_pdsch_stats(fd,gNB);
408
    dump_pusch_stats(fd,gNB);
409
    dump_L1_meas_stats(gNB, ru, output, L1STATSSTRLEN);
410 411 412
    fprintf(fd,"%s\n",output);
    fflush(fd);
    fseek(fd,0,SEEK_SET);
413
  }
414
  fclose(fd);
415 416 417
  return(NULL);
}

418 419 420 421 422
// This thread reads the finished L1 tx jobs from threaPool
// and pushes RU tx thread in the right order. It works only
// two parallel L1 tx threads.
void *tx_reorder_thread(void* param) {
  PHY_VARS_gNB *gNB = (PHY_VARS_gNB *)param;
423
  
424
  notifiedFIFO_elt_t *resL1Reserve = pullNotifiedFIFO(&gNB->L1_tx_out);
425
  AssertFatal(resL1Reserve != NULL, "pullTpool() did not return start message in %s\n", __func__);
426 427
  int next_tx_slot=((processingData_L1tx_t *)NotifiedFifoData(resL1Reserve))->slot;
  
428 429
  LOG_I(PHY,"tx_reorder_thread started\n");
  
430
  while (!oai_exit) {
431
    notifiedFIFO_elt_t *resL1;
432
    if (resL1Reserve) {
433 434
       resL1=resL1Reserve;
       if (((processingData_L1tx_t *)NotifiedFifoData(resL1))->slot != next_tx_slot) {
435
         LOG_E(PHY,"order mistake\n");
436
         resL1Reserve = NULL;
437
         resL1 = pullNotifiedFIFO(&gNB->L1_tx_out);
438
       }
439 440
     } else {
       resL1 = pullNotifiedFIFO(&gNB->L1_tx_out);
441
       if (resL1 != NULL && ((processingData_L1tx_t *)NotifiedFifoData(resL1))->slot != next_tx_slot) {
442 443
          if (resL1Reserve)
              LOG_E(PHY,"error, have a stored packet, then a second one\n");
444
          resL1Reserve = resL1;
445
          resL1 = pullNotifiedFIFO(&gNB->L1_tx_out);
446
          if (((processingData_L1tx_t *)NotifiedFifoData(resL1))->slot != next_tx_slot)
447
            LOG_E(PHY,"error, pull two msg, none is good\n");
448
       }
449
    }
450 451
    if (resL1 == NULL)
      break; // Tpool has been stopped
452 453 454 455 456 457
    processingData_L1tx_t *syncMsgL1= (processingData_L1tx_t *)NotifiedFifoData(resL1);
    processingData_RU_t syncMsgRU;
    syncMsgRU.frame_tx = syncMsgL1->frame;
    syncMsgRU.slot_tx = syncMsgL1->slot;
    syncMsgRU.timestamp_tx = syncMsgL1->timestamp_tx;
    syncMsgRU.ru = gNB->RU_list[0];
458 459 460 461 462
    if (get_softmodem_params()->continuous_tx) {
      int slots_per_frame = gNB->frame_parms.slots_per_frame;
      next_tx_slot = (syncMsgRU.slot_tx + 1) % slots_per_frame;
    } else
      next_tx_slot = get_next_downlink_slot(gNB, &gNB->gNB_config, syncMsgRU.frame_tx, syncMsgRU.slot_tx);
463
    pushNotifiedFIFO(&gNB->L1_tx_free, resL1);
464 465
    if (resL1==resL1Reserve)
       resL1Reserve=NULL;
466
    LOG_D(PHY,"gNB: %d.%d : calling RU TX function\n",syncMsgL1->frame,syncMsgL1->slot);
467
    ru_tx_func((void*)&syncMsgRU);
468 469 470 471
  }
  return(NULL);
}

Sakthivel Velumani's avatar
Sakthivel Velumani committed
472
void init_gNB_Tpool(int inst) {
laurent's avatar
laurent committed
473
  PHY_VARS_gNB *gNB;
474
  gNB = RC.gNB[inst];
475
  gNB_L1_proc_t *proc = &gNB->proc;
Tsung-Yu Chan's avatar
Tsung-Yu Chan committed
476 477
  // PUSCH symbols per thread need to be calculated by how many threads we have
  gNB->num_pusch_symbols_per_thread = 1;
478 479
  // ULSCH decoding threadpool
  initTpool(get_softmodem_params()->threadPoolConfig, &gNB->threadPool, cpumeas(CPUMEAS_GETSTATE));
480
  // ULSCH decoder result FIFO
481
  initNotifiedFIFO(&gNB->respPuschSymb);
482
  initNotifiedFIFO(&gNB->respDecode);
laurent's avatar
laurent committed
483

484
  // L1 RX result FIFO 
485
  initNotifiedFIFO(&gNB->resp_L1);
486 487 488 489
  if (!get_softmodem_params()->reorder_thread_disable) {
    notifiedFIFO_elt_t *msg = newNotifiedFIFO_elt(sizeof(processingData_L1_t), 0, &gNB->resp_L1, rx_func);
    pushNotifiedFIFO(&gNB->resp_L1, msg); // to unblock the process in the beginning
  }
490
  // L1 TX result FIFO 
491 492 493
  initNotifiedFIFO(&gNB->L1_tx_free);
  initNotifiedFIFO(&gNB->L1_tx_filled);
  initNotifiedFIFO(&gNB->L1_tx_out);
494 495
 
  if (get_softmodem_params()->reorder_thread_disable) {
496 497 498 499 500 501 502
    // create the RX thread responsible for triggering RX processing and then TX processing if a single thread is used	  
    threadCreate(&gNB->L1_rx_thread, L1_rx_thread, (void *)gNB, "L1_rx_thread",
                 gNB->L1_rx_thread_core, OAI_PRIORITY_RT_MAX);
    // if separate threads are used for RX and TX, create the TX thread
 // threadCreate(&gNB->L1_tx_thread, L1_tx_thread, (void *)gNB, "L1_tx_thread",
 //              gNB->L1_tx_thread_core, OAI_PRIORITY_RT_MAX);

503
    notifiedFIFO_elt_t *msgL1Tx = newNotifiedFIFO_elt(sizeof(processingData_L1tx_t), 0, &gNB->L1_tx_out, tx_func);
Laurent THOMAS's avatar
Laurent THOMAS committed
504
    processingData_L1tx_t *msgDataTx = (processingData_L1tx_t *)NotifiedFifoData(msgL1Tx);
505
    memset(msgDataTx, 0, sizeof(processingData_L1tx_t));
Laurent THOMAS's avatar
Laurent THOMAS committed
506 507
    init_DLSCH_struct(gNB, msgDataTx);
    memset(msgDataTx->ssb, 0, 64*sizeof(NR_gNB_SSB_t));
508
    // this will be removed when the msgDataTx is not necessary anymore
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
    gNB->msgDataTx = msgDataTx;
  } else {
    // we create 2 threads for L1 tx processing
    for (int i=0; i < 2; i++) {
      notifiedFIFO_elt_t *msgL1Tx = newNotifiedFIFO_elt(sizeof(processingData_L1tx_t), 0, &gNB->L1_tx_out, tx_func);
      processingData_L1tx_t *msgDataTx = (processingData_L1tx_t *)NotifiedFifoData(msgL1Tx);
      memset(msgDataTx, 0, sizeof(processingData_L1tx_t));
      init_DLSCH_struct(gNB, msgDataTx);
      memset(msgDataTx->ssb, 0, 64*sizeof(NR_gNB_SSB_t));
      pushNotifiedFIFO(&gNB->L1_tx_free, msgL1Tx); // to unblock the process in the beginning
    }
  
    LOG_I(PHY,"Creating thread for TX reordering and dispatching to RU\n");
    threadCreate(&proc->pthread_tx_reorder, tx_reorder_thread, (void *)gNB, "thread_tx_reorder",
                  gNB->RU_list[0] ? gNB->RU_list[0]->tpcores[1] : -1, OAI_PRIORITY_RT_MAX);
Laurent THOMAS's avatar
Laurent THOMAS committed
524
  }
Sakthivel Velumani's avatar
Sakthivel Velumani committed
525

526
  if ((!get_softmodem_params()->emulate_l1) && (!IS_SOFTMODEM_NOSTATS_BIT) && (NFAPI_MODE!=NFAPI_MODE_VNF))
Laurent THOMAS's avatar
Laurent THOMAS committed
527 528
     threadCreate(&proc->L1_stats_thread,nrL1_stats_thread,(void*)gNB,"L1_stats",-1,OAI_PRIORITY_RT_LOW);

Sakthivel Velumani's avatar
Sakthivel Velumani committed
529
}
laurent's avatar
laurent committed
530 531


Robert Schmidt's avatar
Robert Schmidt committed
532 533 534
void term_gNB_Tpool(int inst) {
  PHY_VARS_gNB *gNB = RC.gNB[inst];
  abortTpool(&gNB->threadPool);
535 536 537 538 539
  abortNotifiedFIFO(&gNB->respDecode);
  abortNotifiedFIFO(&gNB->resp_L1);
  abortNotifiedFIFO(&gNB->L1_tx_free);
  abortNotifiedFIFO(&gNB->L1_tx_filled);
  abortNotifiedFIFO(&gNB->L1_tx_out);
540 541 542 543 544

  gNB_L1_proc_t *proc = &gNB->proc;
  if (!get_softmodem_params()->emulate_l1)
    pthread_join(proc->L1_stats_thread, NULL);
  pthread_join(proc->pthread_tx_reorder, NULL);
Robert Schmidt's avatar
Robert Schmidt committed
545 546
}

laurent's avatar
laurent committed
547 548 549 550 551 552
/*!
 * \brief Terminate gNB TX and RX threads.
 */
void kill_gNB_proc(int inst) {
  PHY_VARS_gNB *gNB;

553 554 555 556 557
  gNB=RC.gNB[inst];
  
  LOG_I(PHY, "Destroying UL_INFO mutex\n");
  pthread_mutex_destroy(&gNB->UL_INFO_mutex);
  
laurent's avatar
laurent committed
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585
}

void reset_opp_meas(void) {
  int sfn;
  reset_meas(&softmodem_stats_mt);
  reset_meas(&softmodem_stats_hw);

  for (sfn=0; sfn < 10; sfn++) {
    reset_meas(&softmodem_stats_rxtx_sf);
    reset_meas(&softmodem_stats_rx_sf);
  }
}


void print_opp_meas(void) {
  int sfn=0;
  print_meas(&softmodem_stats_mt, "Main gNB Thread", NULL, NULL);
  print_meas(&softmodem_stats_hw, "HW Acquisation", NULL, NULL);

  for (sfn=0; sfn < 10; sfn++) {
    print_meas(&softmodem_stats_rxtx_sf,"[gNB][total_phy_proc_rxtx]",NULL, NULL);
    print_meas(&softmodem_stats_rx_sf,"[gNB][total_phy_proc_rx]",NULL,NULL);
  }
}


/// eNB kept in function name for nffapi calls, TO FIX
void init_eNB_afterRU(void) {
586
  int inst,ru_id,i,aa;
laurent's avatar
laurent committed
587 588 589
  PHY_VARS_gNB *gNB;
  LOG_I(PHY,"%s() RC.nb_nr_inst:%d\n", __FUNCTION__, RC.nb_nr_inst);

590 591
  if(NFAPI_MODE == NFAPI_MODE_PNF)
    RC.nb_nr_inst = 1;
laurent's avatar
laurent committed
592
  for (inst=0; inst<RC.nb_nr_inst; inst++) {
593
    LOG_I(PHY,"RC.nb_nr_CC[inst:%d]:%p\n", inst, RC.gNB[inst]);
594

595
    gNB = RC.gNB[inst];
596
    gNB->ldpc_offload_flag = ldpc_offload_flag;
597
    gNB->reorder_thread_disable = get_softmodem_params()->reorder_thread_disable;
598

599
    phy_init_nr_gNB(gNB);
600

601 602
    // 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);
603

604 605
    LOG_I(PHY,"Mapping RX ports from %d RUs to gNB %d\n",gNB->num_RU,gNB->Mod_id);
    LOG_I(PHY,"gNB->num_RU:%d\n", gNB->num_RU);
606

607 608 609 610 611 612 613 614 615
    for (ru_id=0,aa=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 (i=0; i<gNB->RU_list[ru_id]->nb_rx; aa++,i++) {
616 617
        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];
618
        gNB->common_vars.rxdataF[aa]     =  (c16_t *)gNB->RU_list[ru_id]->common.rxdataF[i];
619
      }
laurent's avatar
laurent committed
620
    }
621

622 623 624 625 626
    /* 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]);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
627
    init_gNB_Tpool(inst);
laurent's avatar
laurent committed
628 629 630 631 632
  }

}

void init_gNB(int single_thread_flag,int wait_for_sync) {
633

laurent's avatar
laurent committed
634 635 636
  int inst;
  PHY_VARS_gNB *gNB;

Raymond Knopp's avatar
Raymond Knopp committed
637
  if (RC.gNB == NULL) {
638
    RC.gNB = (PHY_VARS_gNB **) calloc(1+RC.nb_nr_L1_inst, sizeof(PHY_VARS_gNB *));
639
    LOG_I(PHY,"gNB L1 structure RC.gNB allocated @ %p\n",RC.gNB);
Raymond Knopp's avatar
Raymond Knopp committed
640
  }
laurent's avatar
laurent committed
641 642

  for (inst=0; inst<RC.nb_nr_L1_inst; inst++) {
Raymond Knopp's avatar
Raymond Knopp committed
643

644
    if (RC.gNB[inst] == NULL) {
645
      RC.gNB[inst] = (PHY_VARS_gNB *) calloc(1, sizeof(PHY_VARS_gNB));
646
      LOG_I(PHY,"[nr-gnb.c] gNB structure RC.gNB[%d] allocated @ %p\n",inst,RC.gNB[inst]);
647
    }
648 649 650 651 652 653 654 655 656
    gNB                     = RC.gNB[inst];
    gNB->abstraction_flag   = 0;
    gNB->single_thread_flag = single_thread_flag;
    /*nr_polar_init(&gNB->nrPolar_params,
      NR_POLAR_PBCH_MESSAGE_TYPE,
      NR_POLAR_PBCH_PAYLOAD_BITS,
      NR_POLAR_PBCH_AGGREGATION_LEVEL);*/
    LOG_I(PHY,"Initializing gNB %d single_thread_flag:%d\n",inst,gNB->single_thread_flag);
    LOG_I(PHY,"Initializing gNB %d\n",inst);
657

658 659 660 661 662 663 664
    LOG_I(PHY,"Registering with MAC interface module (before %p)\n",gNB->if_inst);
    AssertFatal((gNB->if_inst         = NR_IF_Module_init(inst))!=NULL,"Cannot register interface");
    LOG_I(PHY,"Registering with MAC interface module (after %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;
    memset((void *)&gNB->UL_INFO,0,sizeof(gNB->UL_INFO));
    LOG_I(PHY,"Setting indication lists\n");
665

666 667 668
    gNB->UL_INFO.rx_ind.pdu_list = gNB->rx_pdu_list;
    gNB->UL_INFO.crc_ind.crc_list = gNB->crc_pdu_list;
    /*gNB->UL_INFO.sr_ind.sr_indication_body.sr_pdu_list = gNB->sr_pdu_list;
669 670
    gNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list = gNB->harq_pdu_list;
    gNB->UL_INFO.cqi_ind.cqi_pdu_list = gNB->cqi_pdu_list;
671
    gNB->UL_INFO.cqi_ind.cqi_raw_pdu_list = gNB->cqi_raw_pdu_list;*/
672

673
    gNB->prach_energy_counter = 0;
674 675
    gNB->chest_time = get_softmodem_params()->chest_time;
    gNB->chest_freq = get_softmodem_params()->chest_freq;
676

laurent's avatar
laurent committed
677
  }
678
  
laurent's avatar
laurent committed
679

680
  LOG_I(PHY,"[nr-gnb.c] gNB structure allocated\n");
laurent's avatar
laurent committed
681 682 683 684 685 686
}


void stop_gNB(int nb_inst) {
  for (int inst=0; inst<nb_inst; inst++) {
    LOG_I(PHY,"Killing gNB %d processing threads\n",inst);
Robert Schmidt's avatar
Robert Schmidt committed
687
    term_gNB_Tpool(inst);
laurent's avatar
laurent committed
688 689 690
    kill_gNB_proc(inst);
  }
}