nr-ue.c 33.1 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
/*
 * 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
 */

cig's avatar
cig committed
22
#include "executables/nr-uesoftmodem.h"
laurent's avatar
laurent committed
23 24
#include "PHY/phy_extern_nr_ue.h"
#include "PHY/INIT/phy_init.h"
25
#include "NR_MAC_UE/mac_proto.h"
laurent's avatar
laurent committed
26
#include "RRC/NR_UE/rrc_proto.h"
cig's avatar
cig committed
27
#include "SCHED_NR_UE/phy_frame_config_nr.h"
laurent's avatar
laurent committed
28 29
#include "SCHED_NR_UE/defs.h"
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
30
#include "executables/softmodem-common.h"
Sakthivel Velumani's avatar
Sakthivel Velumani committed
31
#include "SCHED_NR_UE/pucch_uci_ue_nr.h"
laurent's avatar
laurent committed
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 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

/*
 *  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
93
  #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
94
#endif
Sakthivel Velumani's avatar
Sakthivel Velumani committed
95 96
#define RX_JOB_ID 0x1010
#define TX_JOB_ID 100
laurent's avatar
laurent committed
97

98 99 100 101 102 103
typedef enum {
  pss = 0,
  pbch = 1,
  si = 2
} sync_mode_t;

104 105 106
void init_nr_ue_vars(PHY_VARS_NR_UE *ue,
                     uint8_t UE_id,
                     uint8_t abstraction_flag)
laurent's avatar
laurent committed
107
{
108

109 110
  int nb_connected_gNB = 1, gNB_id;

laurent's avatar
laurent committed
111
  ue->Mod_id      = UE_id;
112
  ue->mac_enabled = 1;
113
  ue->if_inst     = nr_ue_if_module_init(0);
114
  ue->dci_thres   = 0;
115

116 117 118 119 120 121
  // 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
122
  // initialize all signal buffers
123
  init_nr_ue_signal(ue, nb_connected_gNB, abstraction_flag);
124

laurent's avatar
laurent committed
125
  // intialize transport
126
  init_nr_ue_transport(ue, abstraction_flag);
127 128 129

  // init N_TA offset
  init_N_TA_offset(ue);
laurent's avatar
laurent committed
130 131 132 133 134 135 136
}

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

Sakthivel Velumani's avatar
Sakthivel Velumani committed
137
typedef nr_rxtx_thread_data_t syncData_t;
138

laurent's avatar
laurent committed
139 140 141 142 143
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;
144
  //int CC_id = UE->CC_id;
145
  static int freq_offset=0;
laurent's avatar
laurent committed
146 147 148 149 150 151
  UE->is_synchronized = 0;

  if (UE->UE_scan == 0) {

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

152
      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",
153 154 155 156 157 158 159
        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
160 161 162 163
    }

    sync_mode = pbch;
  } else {
164 165
    LOG_E(PHY,"Fixme!\n");
    /*
laurent's avatar
laurent committed
166 167 168 169 170 171 172 173 174
    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;
    }
175
    */
laurent's avatar
laurent committed
176 177 178 179 180
  }

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

  switch (sync_mode) {
181
    /*
laurent's avatar
laurent committed
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
    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;
210
    */
laurent's avatar
laurent committed
211 212 213
    case pbch:
      LOG_I(PHY, "[UE thread Synch] Running Initial Synch (mode %d)\n",UE->mode);

214
      uint64_t dl_carrier, ul_carrier;
215
      nr_get_carrier_frequencies(UE, &dl_carrier, &ul_carrier);
216

217
      if (nr_initial_sync(&syncD->proc, UE, 2, get_softmodem_params()->sa, get_nrUE_params()->nr_dlsch_parallel) == 0) {
laurent's avatar
laurent committed
218
        freq_offset = UE->common_vars.freq_offset; // frequency offset computed with pss in initial sync
219
        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
220
                         round((float)((UE->rx_offset<<1) % UE->frame_parms.samples_per_subframe)/UE->frame_parms.samples_per_slot0);
laurent's avatar
laurent committed
221 222

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

226
        LOG_I(PHY,"Got synch: hw_slot_offset %d, carrier off %d Hz, rxgain %f (DL %f Hz, UL %f Hz)\n",
227 228
              hw_slot_offset,
              freq_offset,
229
              openair0_cfg[UE->rf_map.card].rx_gain[0],
230
              openair0_cfg[UE->rf_map.card].rx_freq[0],
231
              openair0_cfg[UE->rf_map.card].tx_freq[0]);
232

laurent's avatar
laurent committed
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
        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 {
250

251
        if (UE->UE_scan_carrier == 1) {
252

laurent's avatar
laurent committed
253 254 255 256
          if (freq_offset >= 0)
            freq_offset += 100;

          freq_offset *= -1;
257

francescomani's avatar
francescomani committed
258
          nr_rf_card_config_freq(&openair0_cfg[UE->rf_map.card], ul_carrier, dl_carrier, freq_offset);
laurent's avatar
laurent committed
259

260
          LOG_I(PHY, "Initial sync failed: trying carrier off %d Hz\n", freq_offset);
laurent's avatar
laurent committed
261 262 263

          if (UE->mode != loop_through_memory)
            UE->rfdevice.trx_set_freq_func(&UE->rfdevice,&openair0_cfg[0],0);
264
        }
laurent's avatar
laurent committed
265 266 267 268 269 270 271 272 273 274

        break;

      case si:
      default:
        break;
      }
  }
}

Sakthivel Velumani's avatar
Sakthivel Velumani committed
275 276
void processSlotTX(void *arg) {

277
  nr_rxtx_thread_data_t *rxtxD = (nr_rxtx_thread_data_t *) arg;
Sakthivel Velumani's avatar
Sakthivel Velumani committed
278 279
  UE_nr_rxtx_proc_t *proc = &rxtxD->proc;
  PHY_VARS_NR_UE    *UE   = rxtxD->UE;
280
  fapi_nr_config_request_t *cfg = &UE->nrUE_config;
281
  int tx_slot_type = nr_ue_slot_select(cfg, proc->frame_tx, proc->nr_slot_tx);
282
  uint8_t gNB_id = 0;
283

284
  LOG_D(PHY,"%d.%d => slot type %d\n",proc->frame_tx,proc->nr_slot_tx,tx_slot_type);
285
  if (tx_slot_type == NR_UPLINK_SLOT || tx_slot_type == NR_MIXED_SLOT){
Florian Kaltenberger's avatar
Florian Kaltenberger committed
286

287 288 289 290 291 292 293 294 295 296
    // 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;
297
      ul_indication.slot_rx   = proc->nr_slot_rx;
298
      ul_indication.frame_tx  = proc->frame_tx;
299 300
      ul_indication.slot_tx   = proc->nr_slot_tx;
      ul_indication.thread_id = proc->thread_id;
301
      ul_indication.ue_sched_mode = rxtxD->ue_sched_mode;
Florian Kaltenberger's avatar
Florian Kaltenberger committed
302

303 304
      UE->if_inst->ul_indication(&ul_indication);
    }
305

Sakthivel Velumani's avatar
Sakthivel Velumani committed
306
    if ((UE->mode != loop_through_memory) && (rxtxD->ue_sched_mode != NOT_PUSCH)) {
307
      phy_procedures_nrUE_TX(UE,proc,0);
Florian Kaltenberger's avatar
Florian Kaltenberger committed
308 309 310 311
    }
  }
}

Sakthivel Velumani's avatar
Sakthivel Velumani committed
312
void processSlotRX(void *arg) {
Florian Kaltenberger's avatar
Florian Kaltenberger committed
313

314
  nr_rxtx_thread_data_t *rxtxD = (nr_rxtx_thread_data_t *) arg;
Sakthivel Velumani's avatar
Sakthivel Velumani committed
315 316
  UE_nr_rxtx_proc_t *proc = &rxtxD->proc;
  PHY_VARS_NR_UE    *UE   = rxtxD->UE;
317
  fapi_nr_config_request_t *cfg = &UE->nrUE_config;
318
  int rx_slot_type = nr_ue_slot_select(cfg, proc->frame_rx, proc->nr_slot_rx);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
319
  int tx_slot_type = nr_ue_slot_select(cfg, proc->frame_tx, proc->nr_slot_tx);
cig's avatar
cig committed
320
  uint8_t gNB_id = 0;
Florian Kaltenberger's avatar
Florian Kaltenberger committed
321

322
  if (rx_slot_type == NR_DOWNLINK_SLOT || rx_slot_type == NR_MIXED_SLOT){
Florian Kaltenberger's avatar
Florian Kaltenberger committed
323

cig's avatar
cig committed
324
    if(UE->if_inst != NULL && UE->if_inst->dl_indication != NULL) {
325
      nr_downlink_indication_t dl_indication;
cig's avatar
cig committed
326
      nr_fill_dl_indication(&dl_indication, NULL, NULL, proc, UE, gNB_id);
327 328
      UE->if_inst->dl_indication(&dl_indication, NULL);
    }
329

Florian Kaltenberger's avatar
Florian Kaltenberger committed
330
  // Process Rx data for one sub-frame
laurent's avatar
laurent committed
331
#ifdef UE_SLOT_PARALLELISATION
cig's avatar
cig committed
332
    phy_procedures_slot_parallelization_nrUE_RX( UE, proc, 0, 0, 1, no_relay, NULL );
laurent's avatar
laurent committed
333
#else
laurent's avatar
laurent committed
334
    uint64_t a=rdtsc();
335
    phy_procedures_nrUE_RX(UE, proc, gNB_id, get_nrUE_params()->nr_dlsch_parallel, &rxtxD->txFifo);
cig's avatar
cig committed
336
    LOG_D(PHY, "In %s: slot %d, time %lu\n", __FUNCTION__, proc->nr_slot_rx, (rdtsc()-a)/3500);
laurent's avatar
laurent committed
337
#endif
Raymond Knopp's avatar
Raymond Knopp committed
338

339
    if(IS_SOFTMODEM_NOS1 || get_softmodem_params()->sa){
cig's avatar
cig committed
340
      NR_UE_MAC_INST_t *mac = get_mac_inst(0);
Florian Kaltenberger's avatar
Florian Kaltenberger committed
341
      protocol_ctxt_t ctxt;
cig's avatar
cig committed
342
      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
343
      pdcp_run(&ctxt);
344 345 346 347 348 349 350 351

      /* send tick to RLC and PDCP every ms */
      if (proc->nr_slot_rx % UE->frame_parms.slots_per_subframe == 0) {
        void nr_rlc_tick(int frame, int subframe);
        void nr_pdcp_tick(int frame, int subframe);
        nr_rlc_tick(proc->frame_rx, proc->nr_slot_rx / UE->frame_parms.slots_per_subframe);
        nr_pdcp_tick(proc->frame_rx, proc->nr_slot_rx / UE->frame_parms.slots_per_subframe);
      }
Florian Kaltenberger's avatar
Florian Kaltenberger committed
352
    }
353 354 355
    // calling UL_indication to schedule things other than PUSCH (eg, PUCCH)
    rxtxD->ue_sched_mode = NOT_PUSCH;
    processSlotTX(rxtxD);
laurent's avatar
laurent committed
356

357
    // Wait for PUSCH processing to finish
358 359 360
    notifiedFIFO_elt_t *res;
    res = pullTpool(&rxtxD->txFifo,&(get_nrUE_params()->Tpool));
    delNotifiedFIFO_elt(res);
laurent's avatar
laurent committed
361

362
  } else {
363
    rxtxD->ue_sched_mode = SCHED_ALL;
364
    processSlotTX(rxtxD);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
365
  }
laurent's avatar
laurent committed
366

Sakthivel Velumani's avatar
Sakthivel Velumani committed
367
  if (tx_slot_type == NR_UPLINK_SLOT || tx_slot_type == NR_MIXED_SLOT){
Sakthivel Velumani's avatar
Sakthivel Velumani committed
368 369 370 371
    if (UE->UE_mode[gNB_id] <= PUSCH) {
      if (get_softmodem_params()->usim_test==0) {
        pucch_procedures_ue_nr(UE,
                               gNB_id,
372
                               proc);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
373
      }
laurent's avatar
laurent committed
374

Sakthivel Velumani's avatar
Sakthivel Velumani committed
375 376 377 378 379
      LOG_D(PHY, "Sending Uplink data \n");
      nr_ue_pusch_common_procedures(UE,
                                    proc->nr_slot_tx,
                                    &UE->frame_parms,1);
    }
laurent's avatar
laurent committed
380

Sakthivel Velumani's avatar
Sakthivel Velumani committed
381 382 383 384
    if (UE->UE_mode[gNB_id] > NOT_SYNCHED && UE->UE_mode[gNB_id] < PUSCH) {
      nr_ue_prach_procedures(UE, proc, gNB_id);
    }
    LOG_D(PHY,"****** end TX-Chain for AbsSubframe %d.%d ******\n", proc->frame_tx, proc->nr_slot_tx);
385
  }
386

Sakthivel Velumani's avatar
Sakthivel Velumani committed
387
  ue_ta_procedures(UE, proc->nr_slot_tx, proc->frame_tx);
laurent's avatar
laurent committed
388 389
}

390
void dummyWrite(PHY_VARS_NR_UE *UE,openair0_timestamp timestamp, int writeBlockSize) {
laurent's avatar
laurent committed
391 392 393
  void *dummy_tx[UE->frame_parms.nb_antennas_tx];

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

396 397 398 399 400 401 402
  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
403 404 405 406 407

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

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

410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
  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]);
435
    }
laurent's avatar
laurent committed
436 437 438 439 440
  }

}

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

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

Sakthivel Velumani's avatar
Sakthivel Velumani committed
444
    *timestamp += UE->frame_parms.get_samples_per_slot(1,&UE->frame_parms);
laurent's avatar
laurent committed
445 446
    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
447 448 449
      // 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
450 451 452 453 454 455
      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
456
      *timestamp += unitTransfer; // this does not affect the read but needed for RFSIM write
laurent's avatar
laurent committed
457 458 459 460 461 462 463
    }

}

int computeSamplesShift(PHY_VARS_NR_UE *UE) {

  // compute TO compensation that should be applied for this frame
464 465 466
  if ( UE->rx_offset < UE->frame_parms.samples_per_frame/2  &&
       UE->rx_offset > 0 ) {
    //LOG_I(PHY,"!!!adjusting -1 samples!!!\n");
467 468
    UE->rx_offset   = 0; // reset so that it is not applied falsely in case of SSB being only in every second frame
    UE->max_pos_fil = 0; // reset IIR filter when sample shift is applied
laurent's avatar
laurent committed
469
    return -1 ;
470
  }
laurent's avatar
laurent committed
471

472 473 474
  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");
475 476
    UE->rx_offset   = 0; // reset so that it is not applied falsely in case of SSB being only in every second frame
    UE->max_pos_fil = 0; // reset IIR filter when sample shift is applied
laurent's avatar
laurent committed
477
    return 1;
478
  }
laurent's avatar
laurent committed
479

laurent's avatar
laurent committed
480 481 482
  return 0;
}

483
static inline int get_firstSymSamp(uint16_t slot, NR_DL_FRAME_PARMS *fp) {
Sakthivel Velumani's avatar
Sakthivel Velumani committed
484 485 486 487 488 489 490
  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;
}

491
static inline int get_readBlockSize(uint16_t slot, NR_DL_FRAME_PARMS *fp) {
Sakthivel Velumani's avatar
Sakthivel Velumani committed
492 493 494 495 496 497 498
  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
499
void *UE_thread(void *arg) {
laurent's avatar
laurent committed
500
  //this thread should be over the processing thread to keep in real time
laurent's avatar
laurent committed
501 502
  PHY_VARS_NR_UE *UE = (PHY_VARS_NR_UE *) arg;
  //  int tx_enabled = 0;
503
  openair0_timestamp timestamp, writeTimestamp;
laurent's avatar
laurent committed
504 505 506 507
  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;
508 509
  UE->lost_sync = 0;
  UE->is_synchronized = 0;
laurent's avatar
laurent committed
510
  AssertFatal(UE->rfdevice.trx_start_func(&UE->rfdevice) == 0, "Could not start the device\n");
Sakthivel Velumani's avatar
Sakthivel Velumani committed
511

laurent's avatar
laurent committed
512 513
  notifiedFIFO_t nf;
  initNotifiedFIFO(&nf);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
514

515 516
  notifiedFIFO_t freeBlocks;
  initNotifiedFIFO_nothreadSafe(&freeBlocks);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
517

518
  int nbSlotProcessing=0;
laurent's avatar
laurent committed
519
  int thread_idx=0;
520
  NR_UE_MAC_INST_t *mac = get_mac_inst(0);
521
  int timing_advance = UE->timing_advance;
laurent's avatar
laurent committed
522

laurent's avatar
fixes  
laurent committed
523
  bool syncRunning=false;
524
  const int nb_slot_frame = UE->frame_parms.slots_per_frame;
525
  int absolute_slot=0, decoded_frame_rx=INT_MAX, trashed_frames=0;
laurent's avatar
laurent committed
526

527
  for (int i=0; i<NR_RX_NB_TH+1; i++) {// NR_RX_NB_TH working + 1 we are making to be pushed
528 529 530 531
    notifiedFIFO_elt_t *newElt = newNotifiedFIFO_elt(sizeof(nr_rxtx_thread_data_t), RX_JOB_ID,&nf,processSlotRX);
    nr_rxtx_thread_data_t *curMsg=(nr_rxtx_thread_data_t *)NotifiedFifoData(newElt);
    initNotifiedFIFO(&curMsg->txFifo);
    pushNotifiedFIFO_nothreadSafe(&freeBlocks, newElt);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
532 533
  }

laurent's avatar
laurent committed
534
  while (!oai_exit) {
535
    if (UE->lost_sync) {
536 537 538
      int nb = abortTpool(&(get_nrUE_params()->Tpool),RX_JOB_ID);
      nb += abortNotifiedFIFO(&nf, RX_JOB_ID);
      LOG_I(PHY,"Number of aborted slots %d\n",nb);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
539
      for (int i=0; i<nb; i++)
540 541
        pushNotifiedFIFO_nothreadSafe(&freeBlocks, newNotifiedFIFO_elt(sizeof(nr_rxtx_thread_data_t), RX_JOB_ID,&nf,processSlotRX));
      nbSlotProcessing = 0;
542 543 544 545
      UE->is_synchronized = 0;
      UE->lost_sync = 0;
    }

546
    if (syncRunning) {
547
      notifiedFIFO_elt_t *res=tryPullTpool(&nf,&(get_nrUE_params()->Tpool));
548 549 550 551

      if (res) {
        syncRunning=false;
        syncData_t *tmp=(syncData_t *)NotifiedFifoData(res);
552 553 554
        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
555
          decoded_frame_rx=(decoded_frame_rx + UE->init_sync_frame + trashed_frames) % MAX_FRAME_NUMBER;
556
        }
557
        delNotifiedFIFO_elt(res);
558
        start_rx_stream=0;
laurent's avatar
laurent committed
559
      } else {
560
        readFrame(UE, &timestamp, true);
561
        trashed_frames+=2;
562
        continue;
laurent's avatar
laurent committed
563
      }
564
    }
laurent's avatar
laurent committed
565

566
    AssertFatal( !syncRunning, "At this point synchronization can't be running\n");
567 568

    if (!UE->is_synchronized) {
569
      readFrame(UE, &timestamp, false);
570 571 572 573
      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));
574
      pushTpool(&(get_nrUE_params()->Tpool), Msg);
575 576
      trashed_frames=0;
      syncRunning=true;
laurent's avatar
laurent committed
577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
      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
592 593
      // we have the decoded frame index in the return of the synch process
      // and we shifted above to the first slot of next frame
594
      decoded_frame_rx++;
595
      // we do ++ first in the regular processing, so it will be begin of frame;
596
      absolute_slot=decoded_frame_rx*nb_slot_frame -1;
laurent's avatar
laurent committed
597 598 599
      continue;
    }

600

laurent's avatar
laurent committed
601
    absolute_slot++;
602

603 604
    // whatever means thread_idx
    // Fix me: will be wrong when slot 1 is slow, as slot 2 finishes
605
    // Slot 3 will overlap if NR_RX_NB_TH is 2
606
    // this is general failure in UE !!!
607
    thread_idx = absolute_slot % NR_RX_NB_TH;
laurent's avatar
fixes  
laurent committed
608
    int slot_nr = absolute_slot % nb_slot_frame;
609 610
    notifiedFIFO_elt_t *msgToPush;
    AssertFatal((msgToPush=pullNotifiedFIFO_nothreadSafe(&freeBlocks)) != NULL,"chained list failure");
611
    nr_rxtx_thread_data_t *curMsg=(nr_rxtx_thread_data_t *)NotifiedFifoData(msgToPush);
612
    curMsg->UE=UE;
laurent's avatar
laurent committed
613
    // update thread index for received subframe
614 615 616 617 618 619
    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;
620
    curMsg->proc.decoded_frame_rx=-1;
Hongzhi Wang's avatar
Hongzhi Wang committed
621 622 623
    //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
624
    /*uint32_t total_gain_dB_prev = 0;
Hongzhi Wang's avatar
Hongzhi Wang committed
625
    if (total_gain_dB_prev != UE->rx_total_gain_dB) {
Thomas Schlichter's avatar
Thomas Schlichter committed
626
        total_gain_dB_prev = UE->rx_total_gain_dB;
Hongzhi Wang's avatar
Hongzhi Wang committed
627
        openair0_cfg[0].rx_gain[0] = UE->rx_total_gain_dB;
Hongzhi Wang's avatar
Hongzhi Wang committed
628
        UE->rfdevice.trx_set_gains_func(&UE->rfdevice,&openair0_cfg[0]);
Hongzhi Wang's avatar
Hongzhi Wang committed
629
    }*/
Hongzhi Wang's avatar
Hongzhi Wang committed
630
#endif
laurent's avatar
laurent committed
631

Sakthivel Velumani's avatar
Sakthivel Velumani committed
632
    int firstSymSamp = get_firstSymSamp(slot_nr, &UE->frame_parms);
laurent's avatar
laurent committed
633
    for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++)
Sakthivel Velumani's avatar
Sakthivel Velumani committed
634
      rxp[i] = (void *)&UE->common_vars.rxdata[i][firstSymSamp+
635
               UE->frame_parms.get_samples_slot_timestamp(slot_nr,&UE->frame_parms,0)];
laurent's avatar
laurent committed
636 637

    for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
638
      txp[i] = (void *)&UE->common_vars.txdata[i][UE->frame_parms.get_samples_slot_timestamp(
639
               ((slot_nr + DURATION_RX_TO_TX - NR_RX_NB_TH)%nb_slot_frame),&UE->frame_parms,0)];
laurent's avatar
laurent committed
640 641 642 643

    int readBlockSize, writeBlockSize;

    if (slot_nr<(nb_slot_frame - 1)) {
Sakthivel Velumani's avatar
Sakthivel Velumani committed
644
      readBlockSize=get_readBlockSize(slot_nr, &UE->frame_parms);
645
      writeBlockSize=UE->frame_parms.get_samples_per_slot((slot_nr + DURATION_RX_TO_TX - NR_RX_NB_TH) % nb_slot_frame, &UE->frame_parms);
laurent's avatar
laurent committed
646 647
    } else {
      UE->rx_offset_diff = computeSamplesShift(UE);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
648
      readBlockSize=get_readBlockSize(slot_nr, &UE->frame_parms) -
laurent's avatar
laurent committed
649
                    UE->rx_offset_diff;
650
      writeBlockSize=UE->frame_parms.get_samples_per_slot((slot_nr + DURATION_RX_TO_TX - NR_RX_NB_TH) % nb_slot_frame, &UE->frame_parms)- UE->rx_offset_diff;
laurent's avatar
laurent committed
651 652 653 654 655 656 657 658
    }

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

laurent's avatar
laurent committed
660 661
    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
662
      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
663

664 665
      if ( first_symbols > 0 ) {
        openair0_timestamp ignore_timestamp;
laurent's avatar
laurent committed
666 667
        AssertFatal(first_symbols ==
                    UE->rfdevice.trx_read_func(&UE->rfdevice,
668
                                               &ignore_timestamp,
laurent's avatar
laurent committed
669 670 671
                                               (void **)UE->common_vars.rxdata,
                                               first_symbols,
                                               UE->frame_parms.nb_antennas_rx),"");
672
      } else
laurent's avatar
laurent committed
673 674 675
        LOG_E(PHY,"can't compensate: diff =%d\n", first_symbols);
    }

676
    curMsg->proc.timestamp_tx = timestamp+
677
      UE->frame_parms.get_samples_slot_timestamp(slot_nr,&UE->frame_parms,DURATION_RX_TO_TX) 
678
      - firstSymSamp;
Sakthivel Velumani's avatar
Sakthivel Velumani committed
679

laurent's avatar
fixes  
laurent committed
680
    notifiedFIFO_elt_t *res;
laurent's avatar
laurent committed
681

682
    while (nbSlotProcessing >= NR_RX_NB_TH) {
683
      res=pullTpool(&nf, &(get_nrUE_params()->Tpool));
684
      nbSlotProcessing--;
Sakthivel Velumani's avatar
Sakthivel Velumani committed
685
      nr_rxtx_thread_data_t *tmp=(nr_rxtx_thread_data_t *)res->msgData;
laurent's avatar
fixes  
laurent committed
686

687 688
      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);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
689
      else
Laurent's avatar
Laurent committed
690
         decoded_frame_rx=-1;
laurent's avatar
laurent committed
691

692
      pushNotifiedFIFO_nothreadSafe(&freeBlocks,res);
laurent's avatar
laurent committed
693 694
    }

695
    if (decoded_frame_rx>0 && decoded_frame_rx != curMsg->proc.frame_rx)
laurent's avatar
laurent committed
696
      LOG_E(PHY,"Decoded frame index (%d) is not compatible with current context (%d), UE should go back to synch mode\n",
697
            decoded_frame_rx, curMsg->proc.frame_rx);
laurent's avatar
laurent committed
698

699
    // use previous timing_advance value to compute writeTimestamp
700 701
    writeTimestamp = timestamp+
      UE->frame_parms.get_samples_slot_timestamp(slot_nr,&UE->frame_parms,DURATION_RX_TO_TX
Sakthivel Velumani's avatar
Sakthivel Velumani committed
702
      - NR_RX_NB_TH) - firstSymSamp - openair0_cfg[0].tx_sample_advance -
703
      UE->N_TA_offset - timing_advance;
704 705 706 707 708 709 710

    // 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;
    }

711
    int flags = 0;
712
    int slot_tx_usrp = slot_nr + DURATION_RX_TO_TX - NR_RX_NB_TH;
713

714
    if (openair0_cfg[0].duplex_mode == duplex_mode_TDD) {
cig's avatar
cig committed
715

716 717
      uint8_t tdd_period = mac->phy_config.config_req.tdd_table.tdd_period_in_slots;
      int nrofUplinkSlots, nrofUplinkSymbols;
francescomani's avatar
francescomani committed
718 719 720 721 722 723 724 725 726
      if (mac->scc) {
        nrofUplinkSlots = mac->scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots;
        nrofUplinkSymbols = mac->scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols;
      }
      else {
        nrofUplinkSlots = mac->scc_SIB->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots;
        nrofUplinkSymbols = mac->scc_SIB->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols;
      }
      uint8_t  num_UL_slots = nrofUplinkSlots + (nrofUplinkSymbols != 0);
727

cig's avatar
cig committed
728 729
      uint8_t first_tx_slot = tdd_period - num_UL_slots;

730 731 732 733 734 735 736
      if (slot_tx_usrp % tdd_period == first_tx_slot)
        flags = 2;
      else if (slot_tx_usrp % tdd_period == first_tx_slot + num_UL_slots - 1)
        flags = 3;
      else if (slot_tx_usrp % tdd_period > first_tx_slot)
        flags = 1;
    } else {
737
      flags = 1;
738
    }
739 740

    if (flags || IS_SOFTMODEM_RFSIM)
741 742 743 744 745 746 747
      AssertFatal(writeBlockSize ==
                  UE->rfdevice.trx_write_func(&UE->rfdevice,
                                              writeTimestamp,
                                              txp,
                                              writeBlockSize,
                                              UE->frame_parms.nb_antennas_tx,
                                              flags),"");
748
    
749 750 751
    for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
      memset(txp[i], 0, writeBlockSize);

752
    nbSlotProcessing++;
Sakthivel Velumani's avatar
Sakthivel Velumani committed
753
    LOG_D(PHY,"Number of slots being processed at the moment: %d\n",nbSlotProcessing);
754
    pushTpool(&(get_nrUE_params()->Tpool), msgToPush);
laurent's avatar
laurent committed
755

laurent's avatar
laurent committed
756 757 758 759 760
  } // while !oai_exit

  return NULL;
}

761
void init_NR_UE(int nb_inst, char* rrc_config_path) {
laurent's avatar
laurent committed
762 763
  int inst;
  NR_UE_MAC_INST_t *mac_inst;
Florian Kaltenberger's avatar
Florian Kaltenberger committed
764 765
  NR_UE_RRC_INST_t* rrc_inst;
  
laurent's avatar
laurent committed
766
  for (inst=0; inst < nb_inst; inst++) {
Florian Kaltenberger's avatar
Florian Kaltenberger committed
767 768 769
    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");
770 771 772 773 774 775 776 777 778 779 780
  }
}

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
781
    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
782
    threadCreate(&threads[inst], UE_thread, (void *)UE, "UEthread", -1, OAI_PRIORITY_RT_MAX);
783

784
     if(get_nrUE_params()->nr_dlsch_parallel)
785 786 787 788
     {
       pthread_t dlsch0_threads;
       threadCreate(&dlsch0_threads, dlsch_thread, (void *)UE, "DLthread", -1, OAI_PRIORITY_RT_MAX-1);
     }
laurent's avatar
laurent committed
789 790 791
  }
}

792 793 794 795 796 797 798 799 800 801 802
/* 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();
}

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