nr-ue.c 34.8 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
/*
 * 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.0  (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
 */
21
#include "executables/thread-common.h"
laurent's avatar
laurent committed
22 23
#include "executables/nr-uesoftmodem.h"

24
#include "NR_MAC_UE/mac.h"
laurent's avatar
laurent committed
25 26 27 28 29 30 31 32 33 34
//#include "RRC/LTE/rrc_extern.h"
#include "PHY_INTERFACE/phy_interface_extern.h"

#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

#include "fapi_nr_ue_l1.h"
#include "PHY/phy_extern_nr_ue.h"
#include "PHY/INIT/phy_init.h"
#include "PHY/MODULATION/modulation_UE.h"
35
#include "NR_MAC_UE/mac_proto.h"
laurent's avatar
laurent committed
36 37
#include "RRC/NR_UE/rrc_proto.h"

cig's avatar
cig committed
38
#include "SCHED_NR_UE/phy_frame_config_nr.h"
laurent's avatar
laurent committed
39 40 41 42 43
#include "SCHED_NR_UE/defs.h"

#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"

#include "common/utils/LOG/log.h"
laurent's avatar
laurent committed
44
#include "common/utils/system.h"
laurent's avatar
laurent committed
45
#include "common/utils/LOG/vcd_signal_dumper.h"
46
#include "executables/nr-softmodem.h"
laurent's avatar
laurent committed
47 48 49 50 51 52 53 54 55

#include "T.h"

#ifdef XFORMS
  #include "PHY/TOOLS/nr_phy_scope.h"

  extern char do_forms;
#endif

56 57 58
// Missing stuff?
int next_ra_frame = 0;
module_id_t next_Mod_id = 0;
laurent's avatar
laurent committed
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123

extern double cpuf;
//static  nfapi_nr_config_request_t config_t;
//static  nfapi_nr_config_request_t* config =&config_t;

/*
 *  NR SLOT PROCESSING SEQUENCE
 *
 *  Processing occurs with following steps for connected mode:
 *
 *  - Rx samples for a slot are received,
 *  - PDCCH processing (including DCI extraction for downlink and uplink),
 *  - PDSCH processing (including transport blocks decoding),
 *  - PUCCH/PUSCH (transmission of acknowledgements, CSI, ... or data).
 *
 *  Time between reception of the slot and related transmission depends on UE processing performance.
 *  It is defined by the value NR_UE_CAPABILITY_SLOT_RX_TO_TX.
 *
 *  In NR, network gives the duration between Rx slot and Tx slot in the DCI:
 *  - for reception of a PDSCH and its associated acknowledgment slot (with a PUCCH or a PUSCH),
 *  - for reception of an uplink grant and its associated PUSCH slot.
 *
 *  So duration between reception and it associated transmission depends on its transmission slot given in the DCI.
 *  NR_UE_CAPABILITY_SLOT_RX_TO_TX means the minimum duration but higher duration can be given by the network because UE can support it.
 *
 *                                                                                                    Slot k
 *                                                                                  -------+------------+--------
 *                Frame                                                                    | Tx samples |
 *                Subframe                                                                 |   buffer   |
 *                Slot n                                                            -------+------------+--------
 *       ------ +------------+--------                                                     |
 *              | Rx samples |                                                             |
 *              |   buffer   |                                                             |
 *       -------+------------+--------                                                     |
 *                           |                                                             |
 *                           V                                                             |
 *                           +------------+                                                |
 *                           |   PDCCH    |                                                |
 *                           | processing |                                                |
 *                           +------------+                                                |
 *                           |            |                                                |
 *                           |            v                                                |
 *                           |            +------------+                                   |
 *                           |            |   PDSCH    |                                   |
 *                           |            | processing | decoding result                   |
 *                           |            +------------+    -> ACK/NACK of PDSCH           |
 *                           |                         |                                   |
 *                           |                         v                                   |
 *                           |                         +-------------+------------+        |
 *                           |                         | PUCCH/PUSCH | Tx samples |        |
 *                           |                         |  processing | transfer   |        |
 *                           |                         +-------------+------------+        |
 *                           |                                                             |
 *                           |/___________________________________________________________\|
 *                            \  duration between reception and associated transmission   /
 *
 * Remark: processing is done slot by slot, it can be distribute on different threads which are executed in parallel.
 * This is an architecture optimization in order to cope with real time constraints.
 * By example, for LTE, subframe processing is spread over 4 different threads.
 *
 */

#ifndef NO_RAT_NR
  #define DURATION_RX_TO_TX           (NR_UE_CAPABILITY_SLOT_RX_TO_TX)  /* for NR this will certainly depends to such UE capability which is not yet defined */
#else
124
  #define DURATION_RX_TO_TX           (6)   /* For LTE, this duration is fixed to 4 and it is linked to LTE standard for both modes FDD/TDD */
laurent's avatar
laurent committed
125 126 127 128 129 130 131 132 133 134 135 136
#endif

#define FRAME_PERIOD    100000000ULL
#define DAQ_PERIOD      66667ULL

typedef enum {
  pss=0,
  pbch=1,
  si=2
} sync_mode_t;


137 138 139
void init_nr_ue_vars(PHY_VARS_NR_UE *ue,
                     uint8_t UE_id,
                     uint8_t abstraction_flag)
laurent's avatar
laurent committed
140
{
141

142 143
  int nb_connected_gNB = 1, gNB_id;

laurent's avatar
laurent committed
144 145
  ue->Mod_id      = UE_id;
  ue->mac_enabled = 1;
146
  ue->if_inst     = nr_ue_if_module_init(0);
147

148 149 150 151 152 153
  // Setting UE mode to NOT_SYNCHED by default
  for (gNB_id = 0; gNB_id < nb_connected_gNB; gNB_id++){
    ue->UE_mode[gNB_id] = NOT_SYNCHED;
    ue->prach_resources[gNB_id] = (NR_PRACH_RESOURCES_t *)malloc16_clear(sizeof(NR_PRACH_RESOURCES_t));
  }

laurent's avatar
laurent committed
154
  // initialize all signal buffers
155
  init_nr_ue_signal(ue, nb_connected_gNB, abstraction_flag);
156

laurent's avatar
laurent committed
157
  // intialize transport
158
  init_nr_ue_transport(ue, abstraction_flag);
159 160 161

  // init N_TA offset
  init_N_TA_offset(ue);
laurent's avatar
laurent committed
162 163 164 165 166 167 168 169
}

/*!
 * It performs band scanning and synchonization.
 * \param arg is a pointer to a \ref PHY_VARS_NR_UE structure.
 */

typedef struct syncData_s {
170
  UE_nr_rxtx_proc_t proc;
laurent's avatar
laurent committed
171 172 173 174 175 176 177 178
  PHY_VARS_NR_UE *UE;
} syncData_t;

static void UE_synch(void *arg) {
  syncData_t *syncD=(syncData_t *) arg;
  int i, hw_slot_offset;
  PHY_VARS_NR_UE *UE = syncD->UE;
  sync_mode_t sync_mode = pbch;
179
  //int CC_id = UE->CC_id;
180
  static int freq_offset=0;
laurent's avatar
laurent committed
181 182 183 184
  UE->is_synchronized = 0;

  if (UE->UE_scan == 0) {

185
    #ifdef FR2_TEST
186 187 188 189 190
    // Overwrite DL frequency (for FR2 testing)
    if (downlink_frequency[0][0]!=0){
       UE->frame_parms.dl_CarrierFreq = downlink_frequency[0][0];
       UE->frame_parms.ul_CarrierFreq = downlink_frequency[0][0];
    }
191
    #endif
laurent's avatar
laurent committed
192 193 194

    for (i=0; i<openair0_cfg[UE->rf_map.card].rx_num_channels; i++) {

195
      LOG_I( PHY, "[SCHED][UE] Check absolute frequency DL %f, UL %f (RF card %d, oai_exit %d, channel %d, rx_num_channels %d)\n",
196 197 198 199 200 201 202
        openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i],
        openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i],
        UE->rf_map.card,
        oai_exit,
        i,
        openair0_cfg[0].rx_num_channels);

laurent's avatar
laurent committed
203 204 205 206
    }

    sync_mode = pbch;
  } else {
207 208
    LOG_E(PHY,"Fixme!\n");
    /*
laurent's avatar
laurent committed
209 210 211 212 213 214 215 216 217
    for (i=0; i<openair0_cfg[UE->rf_map.card].rx_num_channels; i++) {
      downlink_frequency[UE->rf_map.card][UE->rf_map.chain+i] = bands_to_scan.band_info[CC_id].dl_min;
      uplink_frequency_offset[UE->rf_map.card][UE->rf_map.chain+i] =
        bands_to_scan.band_info[CC_id].ul_min-bands_to_scan.band_info[CC_id].dl_min;
      openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] = downlink_frequency[CC_id][i];
      openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i] =
        downlink_frequency[CC_id][i]+uplink_frequency_offset[CC_id][i];
      openair0_cfg[UE->rf_map.card].rx_gain[UE->rf_map.chain+i] = UE->rx_total_gain_dB;
    }
218
    */
laurent's avatar
laurent committed
219 220 221 222 223
  }

  LOG_W(PHY, "Starting sync detection\n");

  switch (sync_mode) {
224
    /*
laurent's avatar
laurent committed
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
    case pss:
      LOG_I(PHY,"[SCHED][UE] Scanning band %d (%d), freq %u\n",bands_to_scan.band_info[current_band].band, current_band,bands_to_scan.band_info[current_band].dl_min+current_offset);
      //lte_sync_timefreq(UE,current_band,bands_to_scan.band_info[current_band].dl_min+current_offset);
      current_offset += 20000000; // increase by 20 MHz

      if (current_offset > bands_to_scan.band_info[current_band].dl_max-bands_to_scan.band_info[current_band].dl_min) {
        current_band++;
        current_offset=0;
      }

      if (current_band==bands_to_scan.nbands) {
        current_band=0;
        oai_exit=1;
      }

      for (i=0; i<openair0_cfg[UE->rf_map.card].rx_num_channels; i++) {
        downlink_frequency[UE->rf_map.card][UE->rf_map.chain+i] = bands_to_scan.band_info[current_band].dl_min+current_offset;
        uplink_frequency_offset[UE->rf_map.card][UE->rf_map.chain+i] = bands_to_scan.band_info[current_band].ul_min-bands_to_scan.band_info[0].dl_min + current_offset;
        openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] = downlink_frequency[CC_id][i];
        openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i] = downlink_frequency[CC_id][i]+uplink_frequency_offset[CC_id][i];
        openair0_cfg[UE->rf_map.card].rx_gain[UE->rf_map.chain+i] = UE->rx_total_gain_dB;

        if (UE->UE_scan_carrier) {
          openair0_cfg[UE->rf_map.card].autocal[UE->rf_map.chain+i] = 1;
        }
      }

      break;
253
    */
laurent's avatar
laurent committed
254 255 256
    case pbch:
      LOG_I(PHY, "[UE thread Synch] Running Initial Synch (mode %d)\n",UE->mode);

257 258 259 260
      uint64_t dl_carrier, ul_carrier;
      double rx_gain_off = 0;
      nr_get_carrier_frequencies(&UE->frame_parms, &dl_carrier, &ul_carrier);

261
      if (nr_initial_sync( &syncD->proc, UE, UE->mode,2) == 0) {
laurent's avatar
laurent committed
262
        freq_offset = UE->common_vars.freq_offset; // frequency offset computed with pss in initial sync
263
        hw_slot_offset = ((UE->rx_offset<<1) / UE->frame_parms.samples_per_subframe * UE->frame_parms.slots_per_subframe) +
Sakthivel Velumani's avatar
Sakthivel Velumani committed
264
                         round((float)((UE->rx_offset<<1) % UE->frame_parms.samples_per_subframe)/UE->frame_parms.samples_per_slot0);
laurent's avatar
laurent committed
265 266

        // rerun with new cell parameters and frequency-offset
267 268
        // todo: the freq_offset computed on DL shall be scaled before being applied to UL
        nr_rf_card_config(&openair0_cfg[UE->rf_map.card], rx_gain_off, ul_carrier, dl_carrier, freq_offset);
laurent's avatar
laurent committed
269

270
        LOG_I(PHY,"Got synch: hw_slot_offset %d, carrier off %d Hz, rxgain %f (DL %f Hz, UL %f Hz)\n",
271 272
              hw_slot_offset,
              freq_offset,
273
              openair0_cfg[UE->rf_map.card].rx_gain[0],
274
              openair0_cfg[UE->rf_map.card].rx_freq[0],
275
              openair0_cfg[UE->rf_map.card].tx_freq[0]);
276

laurent's avatar
laurent committed
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
        // reconfigure for potentially different bandwidth
        switch(UE->frame_parms.N_RB_DL) {
          case 6:
            openair0_cfg[UE->rf_map.card].sample_rate =1.92e6;
            openair0_cfg[UE->rf_map.card].rx_bw          =.96e6;
            openair0_cfg[UE->rf_map.card].tx_bw          =.96e6;
            //            openair0_cfg[0].rx_gain[0] -= 12;
            break;

          case 25:
            openair0_cfg[UE->rf_map.card].sample_rate =7.68e6;
            openair0_cfg[UE->rf_map.card].rx_bw          =2.5e6;
            openair0_cfg[UE->rf_map.card].tx_bw          =2.5e6;
            //            openair0_cfg[0].rx_gain[0] -= 6;
            break;

          case 50:
            openair0_cfg[UE->rf_map.card].sample_rate =15.36e6;
            openair0_cfg[UE->rf_map.card].rx_bw          =5.0e6;
            openair0_cfg[UE->rf_map.card].tx_bw          =5.0e6;
            //            openair0_cfg[0].rx_gain[0] -= 3;
            break;

          case 100:
            openair0_cfg[UE->rf_map.card].sample_rate=30.72e6;
            openair0_cfg[UE->rf_map.card].rx_bw=10.0e6;
            openair0_cfg[UE->rf_map.card].tx_bw=10.0e6;
            //            openair0_cfg[0].rx_gain[0] -= 0;
            break;
306 307 308 309 310 311

          case 66:
            openair0_cfg[UE->rf_map.card].sample_rate=122.88e6;
            openair0_cfg[UE->rf_map.card].rx_bw=100.e6;
            openair0_cfg[UE->rf_map.card].tx_bw=100.e6;
            break;
laurent's avatar
laurent committed
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
        }

        if (UE->mode != loop_through_memory) {
          UE->rfdevice.trx_set_freq_func(&UE->rfdevice,&openair0_cfg[0],0);
          //UE->rfdevice.trx_set_gains_func(&openair0,&openair0_cfg[0]);
          //UE->rfdevice.trx_stop_func(&UE->rfdevice);
          // sleep(1);
          /*if (UE->rfdevice.trx_start_func(&UE->rfdevice) != 0 ) {
            LOG_E(HW,"Could not start the device\n");
            oai_exit=1;
            }*/
        }

        if (UE->UE_scan_carrier == 1) {
          UE->UE_scan_carrier = 0;
        } else {
          UE->is_synchronized = 1;
        }
      } else {
331

332
        if (UE->UE_scan_carrier == 1) {
333

laurent's avatar
laurent committed
334 335 336 337
          if (freq_offset >= 0)
            freq_offset += 100;

          freq_offset *= -1;
338

339
          nr_rf_card_config(&openair0_cfg[UE->rf_map.card], rx_gain_off, ul_carrier, dl_carrier, freq_offset);
laurent's avatar
laurent committed
340

341
          LOG_I(PHY, "Initial sync failed: trying carrier off %d Hz\n", freq_offset);
laurent's avatar
laurent committed
342 343 344

          if (UE->mode != loop_through_memory)
            UE->rfdevice.trx_set_freq_func(&UE->rfdevice,&openair0_cfg[0],0);
345
        }
laurent's avatar
laurent committed
346 347 348 349 350 351 352 353 354 355

        break;

      case si:
      default:
        break;
      }
  }
}

Florian Kaltenberger's avatar
Florian Kaltenberger committed
356
void processSlotTX( PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc) {
357
  fapi_nr_config_request_t *cfg = &UE->nrUE_config;
358
  int tx_slot_type = nr_ue_slot_select(cfg, proc->frame_tx, proc->nr_slot_tx);
359
  uint8_t gNB_id = 0;
360 361

  if (tx_slot_type == NR_UPLINK_SLOT || tx_slot_type == NR_MIXED_SLOT){
Florian Kaltenberger's avatar
Florian Kaltenberger committed
362

363 364 365 366 367 368 369 370 371 372
    // trigger L2 to run ue_scheduler thru IF module
    // [TODO] mapping right after NR initial sync
    if(UE->if_inst != NULL && UE->if_inst->ul_indication != NULL) {
      nr_uplink_indication_t ul_indication;
      memset((void*)&ul_indication, 0, sizeof(ul_indication));

      ul_indication.module_id = UE->Mod_id;
      ul_indication.gNB_index = gNB_id;
      ul_indication.cc_id     = UE->CC_id;
      ul_indication.frame_rx  = proc->frame_rx;
373
      ul_indication.slot_rx   = proc->nr_slot_rx;
374
      ul_indication.frame_tx  = proc->frame_tx;
375 376
      ul_indication.slot_tx   = proc->nr_slot_tx;
      ul_indication.thread_id = proc->thread_id;
Florian Kaltenberger's avatar
Florian Kaltenberger committed
377

378 379
      UE->if_inst->ul_indication(&ul_indication);
    }
380

Florian Kaltenberger's avatar
Florian Kaltenberger committed
381
    if (UE->mode != loop_through_memory) {
382
      phy_procedures_nrUE_TX(UE,proc,0);
Florian Kaltenberger's avatar
Florian Kaltenberger committed
383 384 385 386 387 388
    }
  }
}

void processSlotRX( PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc) {

389
  fapi_nr_config_request_t *cfg = &UE->nrUE_config;
390
  int rx_slot_type = nr_ue_slot_select(cfg, proc->frame_rx, proc->nr_slot_rx);
cig's avatar
cig committed
391
  uint8_t gNB_id = 0;
Florian Kaltenberger's avatar
Florian Kaltenberger committed
392

393
  if (rx_slot_type == NR_DOWNLINK_SLOT || rx_slot_type == NR_MIXED_SLOT){
Florian Kaltenberger's avatar
Florian Kaltenberger committed
394

cig's avatar
cig committed
395
    if(UE->if_inst != NULL && UE->if_inst->dl_indication != NULL) {
396 397 398
      nr_downlink_indication_t dl_indication;
      memset((void*)&dl_indication, 0, sizeof(dl_indication));

cig's avatar
cig committed
399 400 401 402
      dl_indication.module_id = UE->Mod_id;
      dl_indication.gNB_index = gNB_id;
      dl_indication.cc_id     = UE->CC_id;
      dl_indication.frame     = proc->frame_rx;
403 404
      dl_indication.slot      = proc->nr_slot_rx;
      dl_indication.thread_id = proc->thread_id;
Florian Kaltenberger's avatar
Florian Kaltenberger committed
405

406 407
      UE->if_inst->dl_indication(&dl_indication, NULL);
    }
408

Florian Kaltenberger's avatar
Florian Kaltenberger committed
409
  // Process Rx data for one sub-frame
laurent's avatar
laurent committed
410 411 412
#ifdef UE_SLOT_PARALLELISATION
    phy_procedures_slot_parallelization_nrUE_RX( UE, proc, 0, 0, 1, UE->mode, no_relay, NULL );
#else
laurent's avatar
laurent committed
413
    uint64_t a=rdtsc();
414
    phy_procedures_nrUE_RX( UE, proc, 0, UE->mode,get_nrUE_params()->nr_dlsch_parallel);
415
    LOG_D(PHY,"phy_procedures_nrUE_RX: slot:%d, time %lu\n", proc->nr_slot_rx, (rdtsc()-a)/3500);
416
    //printf(">>> nr_ue_pdcch_procedures ended\n");
laurent's avatar
laurent committed
417
#endif
Raymond Knopp's avatar
Raymond Knopp committed
418

cig's avatar
cig committed
419 420
    if(IS_SOFTMODEM_NOS1){
      NR_UE_MAC_INST_t *mac = get_mac_inst(0);
Florian Kaltenberger's avatar
Florian Kaltenberger committed
421
      protocol_ctxt_t ctxt;
cig's avatar
cig committed
422
      PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, UE->Mod_id, ENB_FLAG_NO, mac->crnti, proc->frame_rx, proc->nr_slot_rx, 0);
Florian Kaltenberger's avatar
Florian Kaltenberger committed
423 424
      pdcp_run(&ctxt);
    }
laurent's avatar
laurent committed
425 426
  }

427 428
  // no UL for now
  /*
laurent's avatar
laurent committed
429 430 431 432 433 434 435 436
  if (UE->mac_enabled==1) {
    //  trigger L2 to run ue_scheduler thru IF module
    //  [TODO] mapping right after NR initial sync
    if(UE->if_inst != NULL && UE->if_inst->ul_indication != NULL) {
      UE->ul_indication.module_id = 0;
      UE->ul_indication.gNB_index = 0;
      UE->ul_indication.cc_id = 0;
      UE->ul_indication.frame = proc->frame_rx;
437 438
      UE->ul_indication.slot = proc->nr_slot_rx;
      UE->ul_indication.thread_id = proc->thread_id;
laurent's avatar
laurent committed
439 440 441
      UE->if_inst->ul_indication(&UE->ul_indication);
    }
  }
442
  */
443

laurent's avatar
laurent committed
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
}

/*!
 * \brief This is the UE thread for RX subframe n and TX subframe n+4.
 * This thread performs the phy_procedures_UE_RX() on every received slot.
 * then, if TX is enabled it performs TX for n+4.
 * \param arg is a pointer to a \ref PHY_VARS_NR_UE structure.
 * \returns a pointer to an int. The storage is not on the heap and must not be freed.
 */

typedef struct processingData_s {
  UE_nr_rxtx_proc_t proc;
  PHY_VARS_NR_UE    *UE;
}  processingData_t;

void UE_processing(void *arg) {
460
  processingData_t *rxtxD = (processingData_t *) arg;
laurent's avatar
laurent committed
461 462
  UE_nr_rxtx_proc_t *proc = &rxtxD->proc;
  PHY_VARS_NR_UE    *UE   = rxtxD->UE;
463 464
  int slot_tx = proc->nr_slot_tx;
  int frame_tx = proc->frame_tx;
laurent's avatar
laurent committed
465

466 467
  processSlotRX(UE, proc);
  processSlotTX(UE, proc);
468
  ue_ta_procedures(UE, slot_tx, frame_tx);
469

laurent's avatar
laurent committed
470 471
}

472
void dummyWrite(PHY_VARS_NR_UE *UE,openair0_timestamp timestamp, int writeBlockSize) {
laurent's avatar
laurent committed
473 474 475
  void *dummy_tx[UE->frame_parms.nb_antennas_tx];

  for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
476
    dummy_tx[i]=malloc16_clear(writeBlockSize*4);
laurent's avatar
laurent committed
477

478 479 480 481 482 483 484
  AssertFatal( writeBlockSize ==
               UE->rfdevice.trx_write_func(&UE->rfdevice,
               timestamp,
               dummy_tx,
               writeBlockSize,
               UE->frame_parms.nb_antennas_tx,
               4),"");
laurent's avatar
laurent committed
485 486 487 488 489

  for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
    free(dummy_tx[i]);
}

490
void readFrame(PHY_VARS_NR_UE *UE,  openair0_timestamp *timestamp, bool toTrash) {
laurent's avatar
laurent committed
491

492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
  void *rxp[NB_ANTENNAS_RX];

  for(int x=0; x<20; x++) {  // two frames for initial sync
    for (int slot=0; slot<UE->frame_parms.slots_per_subframe; slot ++ ) {
      for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++) {
        if (toTrash)
          rxp[i]=malloc16(UE->frame_parms.get_samples_per_slot(slot,&UE->frame_parms)*4);
        else
          rxp[i] = ((void *)&UE->common_vars.rxdata[i][0]) +
                   4*((x*UE->frame_parms.samples_per_subframe)+
                   UE->frame_parms.get_samples_slot_timestamp(slot,&UE->frame_parms,0));
      }
        
      AssertFatal( UE->frame_parms.get_samples_per_slot(slot,&UE->frame_parms) ==
                   UE->rfdevice.trx_read_func(&UE->rfdevice,
                   timestamp,
                   rxp,
                   UE->frame_parms.get_samples_per_slot(slot,&UE->frame_parms),
                   UE->frame_parms.nb_antennas_rx), "");

      if (IS_SOFTMODEM_RFSIM)
        dummyWrite(UE,*timestamp, UE->frame_parms.get_samples_per_slot(slot,&UE->frame_parms));
      if (toTrash)
        for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++)
          free(rxp[i]);
517
    }
laurent's avatar
laurent committed
518 519 520 521 522
  }

}

void syncInFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp) {
523

laurent's avatar
laurent committed
524 525
    LOG_I(PHY,"Resynchronizing RX by %d samples (mode = %d)\n",UE->rx_offset,UE->mode);

Sakthivel Velumani's avatar
Sakthivel Velumani committed
526
    *timestamp += UE->frame_parms.get_samples_per_slot(1,&UE->frame_parms);
laurent's avatar
laurent committed
527 528
    for ( int size=UE->rx_offset ; size > 0 ; size -= UE->frame_parms.samples_per_subframe ) {
      int unitTransfer=size>UE->frame_parms.samples_per_subframe ? UE->frame_parms.samples_per_subframe : size ;
Sakthivel Velumani's avatar
Sakthivel Velumani committed
529 530 531
      // we write before read becasue gNB waits for UE to write and both executions halt
      // this happens here as the read size is samples_per_subframe which is very much larger than samp_per_slot
      if (IS_SOFTMODEM_RFSIM) dummyWrite(UE,*timestamp, unitTransfer);
laurent's avatar
laurent committed
532 533 534 535 536 537
      AssertFatal(unitTransfer ==
                  UE->rfdevice.trx_read_func(&UE->rfdevice,
                                             timestamp,
                                             (void **)UE->common_vars.rxdata,
                                             unitTransfer,
                                             UE->frame_parms.nb_antennas_rx),"");
Sakthivel Velumani's avatar
Sakthivel Velumani committed
538
      *timestamp += unitTransfer; // this does not affect the read but needed for RFSIM write
laurent's avatar
laurent committed
539 540 541 542 543 544 545
    }

}

int computeSamplesShift(PHY_VARS_NR_UE *UE) {

  // compute TO compensation that should be applied for this frame
546 547 548
  if ( UE->rx_offset < UE->frame_parms.samples_per_frame/2  &&
       UE->rx_offset > 0 ) {
    //LOG_I(PHY,"!!!adjusting -1 samples!!!\n");
laurent's avatar
laurent committed
549
    return -1 ;
550
  }
laurent's avatar
laurent committed
551

552 553 554
  if ( UE->rx_offset > UE->frame_parms.samples_per_frame/2 &&
       UE->rx_offset < UE->frame_parms.samples_per_frame ) {
    //LOG_I(PHY,"!!!adjusting +1 samples!!!\n");
laurent's avatar
laurent committed
555
    return 1;
556
  }
laurent's avatar
laurent committed
557

laurent's avatar
laurent committed
558 559 560
  return 0;
}

561
static inline int get_firstSymSamp(uint16_t slot, NR_DL_FRAME_PARMS *fp) {
Sakthivel Velumani's avatar
Sakthivel Velumani committed
562 563 564 565 566 567 568
  if (fp->numerology_index == 0)
    return fp->nb_prefix_samples0 + fp->ofdm_symbol_size;
  int num_samples = (slot%(fp->slots_per_subframe/2)) ? fp->nb_prefix_samples : fp->nb_prefix_samples0;
  num_samples += fp->ofdm_symbol_size;
  return num_samples;
}

569
static inline int get_readBlockSize(uint16_t slot, NR_DL_FRAME_PARMS *fp) {
Sakthivel Velumani's avatar
Sakthivel Velumani committed
570 571 572 573 574 575 576
  int rem_samples = fp->get_samples_per_slot(slot, fp) - get_firstSymSamp(slot, fp);
  int next_slot_first_symbol = 0;
  if (slot < (fp->slots_per_frame-1))
    next_slot_first_symbol = get_firstSymSamp(slot+1, fp);
  return rem_samples + next_slot_first_symbol;
}

laurent's avatar
laurent committed
577
void *UE_thread(void *arg) {
laurent's avatar
laurent committed
578
  //this thread should be over the processing thread to keep in real time
laurent's avatar
laurent committed
579 580
  PHY_VARS_NR_UE *UE = (PHY_VARS_NR_UE *) arg;
  //  int tx_enabled = 0;
581
  openair0_timestamp timestamp, writeTimestamp;
laurent's avatar
laurent committed
582 583 584 585 586 587 588 589 590
  void *rxp[NB_ANTENNAS_RX], *txp[NB_ANTENNAS_TX];
  int start_rx_stream = 0;
  AssertFatal(0== openair0_device_load(&(UE->rfdevice), &openair0_cfg[0]), "");
  UE->rfdevice.host_type = RAU_HOST;
  AssertFatal(UE->rfdevice.trx_start_func(&UE->rfdevice) == 0, "Could not start the device\n");
  notifiedFIFO_t nf;
  initNotifiedFIFO(&nf);
  int nbSlotProcessing=0;
  int thread_idx=0;
591 592
  notifiedFIFO_t freeBlocks;
  initNotifiedFIFO_nothreadSafe(&freeBlocks);
593
  NR_UE_MAC_INST_t *mac = get_mac_inst(0);
594
  int timing_advance = UE->timing_advance;
laurent's avatar
laurent committed
595

596 597 598
  for (int i=0; i<RX_NB_TH+1; i++)  // RX_NB_TH working + 1 we are making to be pushed
    pushNotifiedFIFO_nothreadSafe(&freeBlocks,
                                  newNotifiedFIFO_elt(sizeof(processingData_t), 0,&nf,UE_processing));
laurent's avatar
laurent committed
599

laurent's avatar
fixes  
laurent committed
600
  bool syncRunning=false;
601
  const int nb_slot_frame = UE->frame_parms.slots_per_frame;
602
  int absolute_slot=0, decoded_frame_rx=INT_MAX, trashed_frames=0;
laurent's avatar
laurent committed
603 604

  while (!oai_exit) {
605
    if (syncRunning) {
606
      notifiedFIFO_elt_t *res=tryPullTpool(&nf,&(get_nrUE_params()->Tpool));
607 608 609 610

      if (res) {
        syncRunning=false;
        syncData_t *tmp=(syncData_t *)NotifiedFifoData(res);
611 612 613 614 615
        if (UE->is_synchronized) {
          decoded_frame_rx=(((mac->mib->systemFrameNumber.buf[0] >> mac->mib->systemFrameNumber.bits_unused)<<4) | tmp->proc.decoded_frame_rx);
          // shift the frame index with all the frames we trashed meanwhile we perform the synch search
          decoded_frame_rx=(decoded_frame_rx + (!UE->init_sync_frame) + trashed_frames) % MAX_FRAME_NUMBER;
        }
616
        delNotifiedFIFO_elt(res);
laurent's avatar
laurent committed
617
      } else {
618
        readFrame(UE, &timestamp, true);
619
        trashed_frames+=2;
620
        continue;
laurent's avatar
laurent committed
621
      }
622
    }
laurent's avatar
laurent committed
623

624
    AssertFatal( !syncRunning, "At this point synchronization can't be running\n");
625 626

    if (!UE->is_synchronized) {
627
      readFrame(UE, &timestamp, false);
628 629 630 631
      notifiedFIFO_elt_t *Msg=newNotifiedFIFO_elt(sizeof(syncData_t),0,&nf,UE_synch);
      syncData_t *syncMsg=(syncData_t *)NotifiedFifoData(Msg);
      syncMsg->UE=UE;
      memset(&syncMsg->proc, 0, sizeof(syncMsg->proc));
632
      pushTpool(&(get_nrUE_params()->Tpool), Msg);
633 634
      trashed_frames=0;
      syncRunning=true;
laurent's avatar
laurent committed
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649
      continue;
    }

    if (start_rx_stream==0) {
      start_rx_stream=1;
      syncInFrame(UE, &timestamp);
      UE->rx_offset=0;
      UE->time_sync_cell=0;
      // read in first symbol
      AssertFatal (UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0 ==
                   UE->rfdevice.trx_read_func(&UE->rfdevice,
                                              &timestamp,
                                              (void **)UE->common_vars.rxdata,
                                              UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0,
                                              UE->frame_parms.nb_antennas_rx),"");
laurent's avatar
fixes  
laurent committed
650 651
      // we have the decoded frame index in the return of the synch process
      // and we shifted above to the first slot of next frame
652
      decoded_frame_rx++;
653
      // we do ++ first in the regular processing, so it will be begin of frame;
654
      absolute_slot=decoded_frame_rx*nb_slot_frame -1;
laurent's avatar
laurent committed
655 656 657
      continue;
    }

658

laurent's avatar
laurent committed
659
    absolute_slot++;
660

661 662 663 664
    // whatever means thread_idx
    // Fix me: will be wrong when slot 1 is slow, as slot 2 finishes
    // Slot 3 will overlap if RX_NB_TH is 2
    // this is general failure in UE !!!
laurent's avatar
laurent committed
665
    thread_idx = absolute_slot % RX_NB_TH;
laurent's avatar
fixes  
laurent committed
666
    int slot_nr = absolute_slot % nb_slot_frame;
667 668 669 670
    notifiedFIFO_elt_t *msgToPush;
    AssertFatal((msgToPush=pullNotifiedFIFO_nothreadSafe(&freeBlocks)) != NULL,"chained list failure");
    processingData_t *curMsg=(processingData_t *)NotifiedFifoData(msgToPush);
    curMsg->UE=UE;
laurent's avatar
laurent committed
671
    // update thread index for received subframe
672 673 674 675 676 677
    curMsg->proc.thread_id   = thread_idx;
    curMsg->proc.CC_id       = UE->CC_id;
    curMsg->proc.nr_slot_rx  = slot_nr;
    curMsg->proc.nr_slot_tx  = (absolute_slot + DURATION_RX_TO_TX) % nb_slot_frame;
    curMsg->proc.frame_rx    = (absolute_slot/nb_slot_frame) % MAX_FRAME_NUMBER;
    curMsg->proc.frame_tx    = ((absolute_slot+DURATION_RX_TO_TX)/nb_slot_frame) % MAX_FRAME_NUMBER;
678
    curMsg->proc.decoded_frame_rx=-1;
Hongzhi Wang's avatar
Hongzhi Wang committed
679 680 681
    //LOG_I(PHY,"Process slot %d thread Idx %d total gain %d\n", slot_nr, thread_idx, UE->rx_total_gain_dB);

#ifdef OAI_ADRV9371_ZC706
Hongzhi Wang's avatar
Hongzhi Wang committed
682
    /*uint32_t total_gain_dB_prev = 0;
Hongzhi Wang's avatar
Hongzhi Wang committed
683
    if (total_gain_dB_prev != UE->rx_total_gain_dB) {
Thomas Schlichter's avatar
Thomas Schlichter committed
684
        total_gain_dB_prev = UE->rx_total_gain_dB;
Hongzhi Wang's avatar
Hongzhi Wang committed
685
        openair0_cfg[0].rx_gain[0] = UE->rx_total_gain_dB;
Hongzhi Wang's avatar
Hongzhi Wang committed
686
        UE->rfdevice.trx_set_gains_func(&UE->rfdevice,&openair0_cfg[0]);
Hongzhi Wang's avatar
Hongzhi Wang committed
687
    }*/
Hongzhi Wang's avatar
Hongzhi Wang committed
688
#endif
laurent's avatar
laurent committed
689

Sakthivel Velumani's avatar
Sakthivel Velumani committed
690
    int firstSymSamp = get_firstSymSamp(slot_nr, &UE->frame_parms);
laurent's avatar
laurent committed
691
    for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++)
Sakthivel Velumani's avatar
Sakthivel Velumani committed
692
      rxp[i] = (void *)&UE->common_vars.rxdata[i][firstSymSamp+
693
               UE->frame_parms.get_samples_slot_timestamp(slot_nr,&UE->frame_parms,0)];
laurent's avatar
laurent committed
694 695

    for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
696
      txp[i] = (void *)&UE->common_vars.txdata[i][UE->frame_parms.get_samples_slot_timestamp(
697
               ((slot_nr + DURATION_RX_TO_TX - RX_NB_TH)%nb_slot_frame),&UE->frame_parms,0)];
laurent's avatar
laurent committed
698 699 700 701

    int readBlockSize, writeBlockSize;

    if (slot_nr<(nb_slot_frame - 1)) {
Sakthivel Velumani's avatar
Sakthivel Velumani committed
702
      readBlockSize=get_readBlockSize(slot_nr, &UE->frame_parms);
703
      writeBlockSize=UE->frame_parms.get_samples_per_slot((slot_nr + DURATION_RX_TO_TX - RX_NB_TH) % nb_slot_frame, &UE->frame_parms);
laurent's avatar
laurent committed
704 705
    } else {
      UE->rx_offset_diff = computeSamplesShift(UE);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
706
      readBlockSize=get_readBlockSize(slot_nr, &UE->frame_parms) -
laurent's avatar
laurent committed
707
                    UE->rx_offset_diff;
708
      writeBlockSize=UE->frame_parms.get_samples_per_slot((slot_nr + DURATION_RX_TO_TX - RX_NB_TH) % nb_slot_frame, &UE->frame_parms)-
laurent's avatar
laurent committed
709 710 711 712 713 714 715 716 717
                     UE->rx_offset_diff;
    }

    AssertFatal(readBlockSize ==
                UE->rfdevice.trx_read_func(&UE->rfdevice,
                                           &timestamp,
                                           rxp,
                                           readBlockSize,
                                           UE->frame_parms.nb_antennas_rx),"");
718

laurent's avatar
laurent committed
719 720
    if( slot_nr==(nb_slot_frame-1)) {
      // read in first symbol of next frame and adjust for timing drift
Sakthivel Velumani's avatar
Sakthivel Velumani committed
721
      int first_symbols=UE->frame_parms.ofdm_symbol_size+UE->frame_parms.nb_prefix_samples0; // first symbol of every frames
laurent's avatar
laurent committed
722

723 724
      if ( first_symbols > 0 ) {
        openair0_timestamp ignore_timestamp;
laurent's avatar
laurent committed
725 726
        AssertFatal(first_symbols ==
                    UE->rfdevice.trx_read_func(&UE->rfdevice,
727
                                               &ignore_timestamp,
laurent's avatar
laurent committed
728 729 730
                                               (void **)UE->common_vars.rxdata,
                                               first_symbols,
                                               UE->frame_parms.nb_antennas_rx),"");
731
      } else
laurent's avatar
laurent committed
732 733 734
        LOG_E(PHY,"can't compensate: diff =%d\n", first_symbols);
    }

735
    curMsg->proc.timestamp_tx = timestamp+
736
                                UE->frame_parms.get_samples_slot_timestamp(slot_nr,
Sakthivel Velumani's avatar
Sakthivel Velumani committed
737 738
                                &UE->frame_parms,DURATION_RX_TO_TX) - firstSymSamp;

laurent's avatar
fixes  
laurent committed
739
    notifiedFIFO_elt_t *res;
laurent's avatar
laurent committed
740

741
    while (nbSlotProcessing >= RX_NB_TH) {
742
      res=pullTpool(&nf, &(get_nrUE_params()->Tpool));
743 744
      nbSlotProcessing--;
      processingData_t *tmp=(processingData_t *)res->msgData;
laurent's avatar
fixes  
laurent committed
745

746 747 748
      if (tmp->proc.decoded_frame_rx != -1)
        decoded_frame_rx=(((mac->mib->systemFrameNumber.buf[0] >> mac->mib->systemFrameNumber.bits_unused)<<4) | tmp->proc.decoded_frame_rx);
        //decoded_frame_rx=tmp->proc.decoded_frame_rx;
laurent's avatar
laurent committed
749

750
      pushNotifiedFIFO_nothreadSafe(&freeBlocks,res);
laurent's avatar
laurent committed
751 752
    }

Sakthivel Velumani's avatar
Sakthivel Velumani committed
753 754 755
    if (  (decoded_frame_rx != curMsg->proc.frame_rx) &&
          (((decoded_frame_rx+1) % MAX_FRAME_NUMBER) != curMsg->proc.frame_rx) &&
          (((decoded_frame_rx+2) % MAX_FRAME_NUMBER) != curMsg->proc.frame_rx))
laurent's avatar
laurent committed
756
      LOG_E(PHY,"Decoded frame index (%d) is not compatible with current context (%d), UE should go back to synch mode\n",
757
            decoded_frame_rx, curMsg->proc.frame_rx  );
laurent's avatar
laurent committed
758

759 760 761 762 763 764 765 766 767 768
    // use previous timing_advance value to compute writeTimestamp
    writeTimestamp = timestamp + UE->frame_parms.get_samples_slot_timestamp(slot_nr, &UE->frame_parms,DURATION_RX_TO_TX - RX_NB_TH) -
                     firstSymSamp - openair0_cfg[0].tx_sample_advance - UE->N_TA_offset - timing_advance;

    // but use current UE->timing_advance value to compute writeBlockSize
    if (UE->timing_advance != timing_advance) {
      writeBlockSize -= UE->timing_advance - timing_advance;
      timing_advance = UE->timing_advance;
    }

769 770
    AssertFatal( writeBlockSize ==
                 UE->rfdevice.trx_write_func(&UE->rfdevice,
771
                     writeTimestamp,
772 773 774 775 776
                     txp,
                     writeBlockSize,
                     UE->frame_parms.nb_antennas_tx,
                     1),"");

777 778 779
    for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
      memset(txp[i], 0, writeBlockSize);

780
    nbSlotProcessing++;
781
    msgToPush->key=slot_nr;
782
    pushTpool(&(get_nrUE_params()->Tpool), msgToPush);
laurent's avatar
laurent committed
783

784
    if (IS_SOFTMODEM_RFSIM || IS_SOFTMODEM_NOS1) {  //getenv("RFSIMULATOR")
laurent's avatar
laurent committed
785 786 787
      // FixMe: Wait previous thread is done, because race conditions seems too bad
      // in case of actual RF board, the overlap between threads mitigate the issue
      // We must receive one message, that proves the slot processing is done
788
      res=pullTpool(&nf, &(get_nrUE_params()->Tpool));
laurent's avatar
laurent committed
789
      nbSlotProcessing--;
laurent's avatar
fixes  
laurent committed
790 791 792
      processingData_t *tmp=(processingData_t *)res->msgData;

      if (tmp->proc.decoded_frame_rx != -1)
793 794
        decoded_frame_rx=(((mac->mib->systemFrameNumber.buf[0] >> mac->mib->systemFrameNumber.bits_unused)<<4) | tmp->proc.decoded_frame_rx);
        //decoded_frame_rx=tmp->proc.decoded_frame_rx;
laurent's avatar
fixes  
laurent committed
795

796
      pushNotifiedFIFO_nothreadSafe(&freeBlocks,res);
laurent's avatar
laurent committed
797
    }
798

laurent's avatar
laurent committed
799 800 801 802 803
  } // while !oai_exit

  return NULL;
}

804
void init_NR_UE(int nb_inst, char* rrc_config_path) {
laurent's avatar
laurent committed
805 806
  int inst;
  NR_UE_MAC_INST_t *mac_inst;
Florian Kaltenberger's avatar
Florian Kaltenberger committed
807 808
  NR_UE_RRC_INST_t* rrc_inst;
  
laurent's avatar
laurent committed
809
  for (inst=0; inst < nb_inst; inst++) {
Florian Kaltenberger's avatar
Florian Kaltenberger committed
810 811 812
    AssertFatal((rrc_inst = nr_l3_init_ue(rrc_config_path)) != NULL, "can not initialize RRC module\n");
    AssertFatal((mac_inst = nr_l2_init_ue(rrc_inst)) != NULL, "can not initialize L2 module\n");
    AssertFatal((mac_inst->if_module = nr_ue_if_module_init(inst)) != NULL, "can not initialize IF module\n");
813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829

    NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = NULL;
    if (mac_inst->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup->pusch_TimeDomainAllocationList) {
      pusch_TimeDomainAllocationList = mac_inst->ULbwp[0]->bwp_Dedicated->pusch_Config->choice.setup->pusch_TimeDomainAllocationList->choice.setup;
    }
    else if (mac_inst->ULbwp[0]->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList) {
      pusch_TimeDomainAllocationList = mac_inst->ULbwp[0]->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList;
    }
    	
    if (pusch_TimeDomainAllocationList) {
      for(int i = 0; i < pusch_TimeDomainAllocationList->list.count; i++) {
        AssertFatal(*pusch_TimeDomainAllocationList->list.array[i]->k2 >= DURATION_RX_TO_TX, 
                    "Slot offset K2 (%ld) cannot be less than DURATION_RX_TO_TX (%d)\n", 
                    *pusch_TimeDomainAllocationList->list.array[i]->k2,
                    DURATION_RX_TO_TX);
      }
    }
830 831 832 833 834 835 836 837 838 839 840
  }
}

void init_NR_UE_threads(int nb_inst) {
  int inst;

  pthread_t threads[nb_inst];

  for (inst=0; inst < nb_inst; inst++) {
    PHY_VARS_NR_UE *UE = PHY_vars_UE_g[inst][0];

laurent's avatar
laurent committed
841
    LOG_I(PHY,"Intializing UE Threads for instance %d (%p,%p)...\n",inst,PHY_vars_UE_g[inst],PHY_vars_UE_g[inst][0]);
laurent's avatar
laurent committed
842
    threadCreate(&threads[inst], UE_thread, (void *)UE, "UEthread", -1, OAI_PRIORITY_RT_MAX);
843

844
     if(get_nrUE_params()->nr_dlsch_parallel)
845 846 847 848
     {
       pthread_t dlsch0_threads;
       threadCreate(&dlsch0_threads, dlsch_thread, (void *)UE, "DLthread", -1, OAI_PRIORITY_RT_MAX-1);
     }
laurent's avatar
laurent committed
849 850 851
  }
}

852 853 854 855 856 857 858 859 860 861 862
/* HACK: this function is needed to compile the UE
 * fix it somehow
 */
int8_t find_dlsch(uint16_t rnti,
                  PHY_VARS_eNB *eNB,
                  find_type_t type)
{
  printf("you cannot read this\n");
  abort();
}

863
void multicast_link_write_sock(int groupP, char *dataP, uint32_t sizeP) {}