nr-ue.c 32.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
/*
 * 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 30 31 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
#include "SCHED_NR_UE/defs.h"
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"

/*
 *  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.
 *
 */

88 89 90 91 92 93 94 95 96 97 98 99
#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
  #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 */
#endif

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

100 101 102
void init_nr_ue_vars(PHY_VARS_NR_UE *ue,
                     uint8_t UE_id,
                     uint8_t abstraction_flag)
laurent's avatar
laurent committed
103
{
104

105 106
  int nb_connected_gNB = 1, gNB_id;

laurent's avatar
laurent committed
107
  ue->Mod_id      = UE_id;
108
  ue->mac_enabled = 1;
109
  ue->if_inst     = nr_ue_if_module_init(0);
110

111 112 113 114 115 116
  // 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
117
  // initialize all signal buffers
118
  init_nr_ue_signal(ue, nb_connected_gNB, abstraction_flag);
119

laurent's avatar
laurent committed
120
  // intialize transport
121
  init_nr_ue_transport(ue, abstraction_flag);
122 123 124

  // init N_TA offset
  init_N_TA_offset(ue);
laurent's avatar
laurent committed
125 126 127 128 129 130 131
}

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

132 133 134 135 136
typedef struct syncData_s {
  UE_nr_rxtx_proc_t proc;
  PHY_VARS_NR_UE *UE;
} syncData_t;

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

  if (UE->UE_scan == 0) {

148
    #ifdef FR2_TEST
149 150 151 152 153
    // 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];
    }
154
    #endif
laurent's avatar
laurent committed
155 156 157

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

158
      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",
159 160 161 162 163 164 165
        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
166 167 168 169
    }

    sync_mode = pbch;
  } else {
170 171
    LOG_E(PHY,"Fixme!\n");
    /*
laurent's avatar
laurent committed
172 173 174 175 176 177 178 179 180
    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;
    }
181
    */
laurent's avatar
laurent committed
182 183 184 185 186
  }

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

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

220 221 222 223
      uint64_t dl_carrier, ul_carrier;
      double rx_gain_off = 0;
      nr_get_carrier_frequencies(&UE->frame_parms, &dl_carrier, &ul_carrier);

cig's avatar
cig committed
224
      if (nr_initial_sync(&syncD->proc, UE, 2) == 0) {
laurent's avatar
laurent committed
225
        freq_offset = UE->common_vars.freq_offset; // frequency offset computed with pss in initial sync
226
        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
227
                         round((float)((UE->rx_offset<<1) % UE->frame_parms.samples_per_subframe)/UE->frame_parms.samples_per_slot0);
laurent's avatar
laurent committed
228 229

        // rerun with new cell parameters and frequency-offset
230 231
        // 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
232

233
        LOG_I(PHY,"Got synch: hw_slot_offset %d, carrier off %d Hz, rxgain %f (DL %f Hz, UL %f Hz)\n",
234 235
              hw_slot_offset,
              freq_offset,
236
              openair0_cfg[UE->rf_map.card].rx_gain[0],
237
              openair0_cfg[UE->rf_map.card].rx_freq[0],
238
              openair0_cfg[UE->rf_map.card].tx_freq[0]);
239

laurent's avatar
laurent committed
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
        // 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;
269 270 271 272 273 274

          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
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
        }

        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 {
294

295
        if (UE->UE_scan_carrier == 1) {
296

laurent's avatar
laurent committed
297 298 299 300
          if (freq_offset >= 0)
            freq_offset += 100;

          freq_offset *= -1;
301

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

304
          LOG_I(PHY, "Initial sync failed: trying carrier off %d Hz\n", freq_offset);
laurent's avatar
laurent committed
305 306 307

          if (UE->mode != loop_through_memory)
            UE->rfdevice.trx_set_freq_func(&UE->rfdevice,&openair0_cfg[0],0);
308
        }
laurent's avatar
laurent committed
309 310 311 312 313 314 315 316 317 318

        break;

      case si:
      default:
        break;
      }
  }
}

Florian Kaltenberger's avatar
Florian Kaltenberger committed
319
void processSlotTX( PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc) {
320
  fapi_nr_config_request_t *cfg = &UE->nrUE_config;
321
  int tx_slot_type = nr_ue_slot_select(cfg, proc->frame_tx, proc->nr_slot_tx);
322
  uint8_t gNB_id = 0;
323 324

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

326 327 328 329 330 331 332 333 334 335
    // 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;
336
      ul_indication.slot_rx   = proc->nr_slot_rx;
337
      ul_indication.frame_tx  = proc->frame_tx;
338 339
      ul_indication.slot_tx   = proc->nr_slot_tx;
      ul_indication.thread_id = proc->thread_id;
Florian Kaltenberger's avatar
Florian Kaltenberger committed
340

341 342
      UE->if_inst->ul_indication(&ul_indication);
    }
343

Florian Kaltenberger's avatar
Florian Kaltenberger committed
344
    if (UE->mode != loop_through_memory) {
345
      phy_procedures_nrUE_TX(UE,proc,0);
Florian Kaltenberger's avatar
Florian Kaltenberger committed
346 347 348 349 350 351
    }
  }
}

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

352
  fapi_nr_config_request_t *cfg = &UE->nrUE_config;
353
  int rx_slot_type = nr_ue_slot_select(cfg, proc->frame_rx, proc->nr_slot_rx);
cig's avatar
cig committed
354
  uint8_t gNB_id = 0;
Florian Kaltenberger's avatar
Florian Kaltenberger committed
355

356
  if (rx_slot_type == NR_DOWNLINK_SLOT || rx_slot_type == NR_MIXED_SLOT){
Florian Kaltenberger's avatar
Florian Kaltenberger committed
357

cig's avatar
cig committed
358
    if(UE->if_inst != NULL && UE->if_inst->dl_indication != NULL) {
359
      nr_downlink_indication_t dl_indication;
cig's avatar
cig committed
360
      nr_fill_dl_indication(&dl_indication, NULL, NULL, proc, UE, gNB_id);
361 362
      UE->if_inst->dl_indication(&dl_indication, NULL);
    }
363

Florian Kaltenberger's avatar
Florian Kaltenberger committed
364
  // Process Rx data for one sub-frame
laurent's avatar
laurent committed
365
#ifdef UE_SLOT_PARALLELISATION
cig's avatar
cig committed
366
    phy_procedures_slot_parallelization_nrUE_RX( UE, proc, 0, 0, 1, no_relay, NULL );
laurent's avatar
laurent committed
367
#else
laurent's avatar
laurent committed
368
    uint64_t a=rdtsc();
369
    phy_procedures_nrUE_RX(UE, proc, gNB_id, get_nrUE_params()->nr_dlsch_parallel);
cig's avatar
cig committed
370
    LOG_D(PHY, "In %s: slot %d, time %lu\n", __FUNCTION__, proc->nr_slot_rx, (rdtsc()-a)/3500);
laurent's avatar
laurent committed
371
#endif
Raymond Knopp's avatar
Raymond Knopp committed
372

cig's avatar
cig committed
373 374
    if(IS_SOFTMODEM_NOS1){
      NR_UE_MAC_INST_t *mac = get_mac_inst(0);
Florian Kaltenberger's avatar
Florian Kaltenberger committed
375
      protocol_ctxt_t ctxt;
cig's avatar
cig committed
376
      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
377 378
      pdcp_run(&ctxt);
    }
laurent's avatar
laurent committed
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
  }

}

/*!
 * \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) {
397
  processingData_t *rxtxD = (processingData_t *) arg;
laurent's avatar
laurent committed
398 399
  UE_nr_rxtx_proc_t *proc = &rxtxD->proc;
  PHY_VARS_NR_UE    *UE   = rxtxD->UE;
400 401
  int slot_tx = proc->nr_slot_tx;
  int frame_tx = proc->frame_tx;
laurent's avatar
laurent committed
402

403 404
  processSlotRX(UE, proc);
  processSlotTX(UE, proc);
405
  ue_ta_procedures(UE, slot_tx, frame_tx);
406

laurent's avatar
laurent committed
407 408
}

409
void dummyWrite(PHY_VARS_NR_UE *UE,openair0_timestamp timestamp, int writeBlockSize) {
laurent's avatar
laurent committed
410 411 412
  void *dummy_tx[UE->frame_parms.nb_antennas_tx];

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

415 416 417 418 419 420 421
  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
422 423 424 425 426

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

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

429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
  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]);
454
    }
laurent's avatar
laurent committed
455 456 457 458 459
  }

}

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

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

Sakthivel Velumani's avatar
Sakthivel Velumani committed
463
    *timestamp += UE->frame_parms.get_samples_per_slot(1,&UE->frame_parms);
laurent's avatar
laurent committed
464 465
    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
466 467 468
      // 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
469 470 471 472 473 474
      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
475
      *timestamp += unitTransfer; // this does not affect the read but needed for RFSIM write
laurent's avatar
laurent committed
476 477 478 479 480 481 482
    }

}

int computeSamplesShift(PHY_VARS_NR_UE *UE) {

  // compute TO compensation that should be applied for this frame
483 484 485
  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
486
    return -1 ;
487
  }
laurent's avatar
laurent committed
488

489 490 491
  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
492
    return 1;
493
  }
laurent's avatar
laurent committed
494

laurent's avatar
laurent committed
495 496 497
  return 0;
}

498
static inline int get_firstSymSamp(uint16_t slot, NR_DL_FRAME_PARMS *fp) {
Sakthivel Velumani's avatar
Sakthivel Velumani committed
499 500 501 502 503 504 505
  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;
}

506
static inline int get_readBlockSize(uint16_t slot, NR_DL_FRAME_PARMS *fp) {
Sakthivel Velumani's avatar
Sakthivel Velumani committed
507 508 509 510 511 512 513
  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
514
void *UE_thread(void *arg) {
laurent's avatar
laurent committed
515
  //this thread should be over the processing thread to keep in real time
laurent's avatar
laurent committed
516 517
  PHY_VARS_NR_UE *UE = (PHY_VARS_NR_UE *) arg;
  //  int tx_enabled = 0;
518
  openair0_timestamp timestamp, writeTimestamp;
laurent's avatar
laurent committed
519 520 521 522 523 524 525 526 527
  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;
528 529
  notifiedFIFO_t freeBlocks;
  initNotifiedFIFO_nothreadSafe(&freeBlocks);
530
  NR_UE_MAC_INST_t *mac = get_mac_inst(0);
531
  int timing_advance = UE->timing_advance;
laurent's avatar
laurent committed
532

533 534 535
  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
536

laurent's avatar
fixes  
laurent committed
537
  bool syncRunning=false;
538
  const int nb_slot_frame = UE->frame_parms.slots_per_frame;
539
  int absolute_slot=0, decoded_frame_rx=INT_MAX, trashed_frames=0;
laurent's avatar
laurent committed
540 541

  while (!oai_exit) {
542
    if (syncRunning) {
543
      notifiedFIFO_elt_t *res=tryPullTpool(&nf,&(get_nrUE_params()->Tpool));
544 545 546 547

      if (res) {
        syncRunning=false;
        syncData_t *tmp=(syncData_t *)NotifiedFifoData(res);
548 549 550 551 552
        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;
        }
553
        delNotifiedFIFO_elt(res);
laurent's avatar
laurent committed
554
      } else {
555
        readFrame(UE, &timestamp, true);
556
        trashed_frames+=2;
557
        continue;
laurent's avatar
laurent committed
558
      }
559
    }
laurent's avatar
laurent committed
560

561
    AssertFatal( !syncRunning, "At this point synchronization can't be running\n");
562 563

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

595

laurent's avatar
laurent committed
596
    absolute_slot++;
597

598 599 600 601
    // 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
602
    thread_idx = absolute_slot % RX_NB_TH;
laurent's avatar
fixes  
laurent committed
603
    int slot_nr = absolute_slot % nb_slot_frame;
604 605 606 607
    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
608
    // update thread index for received subframe
609 610 611 612 613 614
    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;
615
    curMsg->proc.decoded_frame_rx=-1;
Hongzhi Wang's avatar
Hongzhi Wang committed
616 617 618
    //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
619
    /*uint32_t total_gain_dB_prev = 0;
Hongzhi Wang's avatar
Hongzhi Wang committed
620
    if (total_gain_dB_prev != UE->rx_total_gain_dB) {
Thomas Schlichter's avatar
Thomas Schlichter committed
621
        total_gain_dB_prev = UE->rx_total_gain_dB;
Hongzhi Wang's avatar
Hongzhi Wang committed
622
        openair0_cfg[0].rx_gain[0] = UE->rx_total_gain_dB;
Hongzhi Wang's avatar
Hongzhi Wang committed
623
        UE->rfdevice.trx_set_gains_func(&UE->rfdevice,&openair0_cfg[0]);
Hongzhi Wang's avatar
Hongzhi Wang committed
624
    }*/
Hongzhi Wang's avatar
Hongzhi Wang committed
625
#endif
laurent's avatar
laurent committed
626

Sakthivel Velumani's avatar
Sakthivel Velumani committed
627
    int firstSymSamp = get_firstSymSamp(slot_nr, &UE->frame_parms);
laurent's avatar
laurent committed
628
    for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++)
Sakthivel Velumani's avatar
Sakthivel Velumani committed
629
      rxp[i] = (void *)&UE->common_vars.rxdata[i][firstSymSamp+
630
               UE->frame_parms.get_samples_slot_timestamp(slot_nr,&UE->frame_parms,0)];
laurent's avatar
laurent committed
631 632

    for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
633
      txp[i] = (void *)&UE->common_vars.txdata[i][UE->frame_parms.get_samples_slot_timestamp(
634
               ((slot_nr + DURATION_RX_TO_TX - RX_NB_TH)%nb_slot_frame),&UE->frame_parms,0)];
laurent's avatar
laurent committed
635 636 637 638

    int readBlockSize, writeBlockSize;

    if (slot_nr<(nb_slot_frame - 1)) {
Sakthivel Velumani's avatar
Sakthivel Velumani committed
639
      readBlockSize=get_readBlockSize(slot_nr, &UE->frame_parms);
640
      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
641 642
    } else {
      UE->rx_offset_diff = computeSamplesShift(UE);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
643
      readBlockSize=get_readBlockSize(slot_nr, &UE->frame_parms) -
laurent's avatar
laurent committed
644
                    UE->rx_offset_diff;
645
      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
646 647 648 649 650 651 652 653 654
                     UE->rx_offset_diff;
    }

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

laurent's avatar
laurent committed
656 657
    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
658
      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
659

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

672
    curMsg->proc.timestamp_tx = timestamp+
673
                                UE->frame_parms.get_samples_slot_timestamp(slot_nr,
Sakthivel Velumani's avatar
Sakthivel Velumani committed
674 675
                                &UE->frame_parms,DURATION_RX_TO_TX) - firstSymSamp;

laurent's avatar
fixes  
laurent committed
676
    notifiedFIFO_elt_t *res;
laurent's avatar
laurent committed
677

678
    while (nbSlotProcessing >= RX_NB_TH) {
679
      res=pullTpool(&nf, &(get_nrUE_params()->Tpool));
680 681
      nbSlotProcessing--;
      processingData_t *tmp=(processingData_t *)res->msgData;
laurent's avatar
fixes  
laurent committed
682

683 684
      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);
Laurent's avatar
Laurent committed
685 686
      else 
         decoded_frame_rx=-1;
laurent's avatar
laurent committed
687

688
      pushNotifiedFIFO_nothreadSafe(&freeBlocks,res);
laurent's avatar
laurent committed
689 690
    }

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

695 696 697 698 699 700 701 702 703 704
    // 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;
    }

705 706
    AssertFatal( writeBlockSize ==
                 UE->rfdevice.trx_write_func(&UE->rfdevice,
707
                     writeTimestamp,
708 709 710 711 712
                     txp,
                     writeBlockSize,
                     UE->frame_parms.nb_antennas_tx,
                     1),"");

713 714 715
    for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
      memset(txp[i], 0, writeBlockSize);

716
    nbSlotProcessing++;
717
    msgToPush->key=slot_nr;
718
    pushTpool(&(get_nrUE_params()->Tpool), msgToPush);
laurent's avatar
laurent committed
719

720
    if ( IS_SOFTMODEM_RFSIM || IS_SOFTMODEM_NOS1) {  //getenv("RFSIMULATOR")
laurent's avatar
laurent committed
721 722 723
      // 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
724
      res=pullTpool(&nf, &(get_nrUE_params()->Tpool));
laurent's avatar
laurent committed
725
      nbSlotProcessing--;
laurent's avatar
fixes  
laurent committed
726 727 728
      processingData_t *tmp=(processingData_t *)res->msgData;

      if (tmp->proc.decoded_frame_rx != -1)
729
        decoded_frame_rx=(((mac->mib->systemFrameNumber.buf[0] >> mac->mib->systemFrameNumber.bits_unused)<<4) | tmp->proc.decoded_frame_rx);
Laurent's avatar
Laurent committed
730 731
      else 
        decoded_frame_rx=-1;
732
        //decoded_frame_rx=tmp->proc.decoded_frame_rx;
laurent's avatar
fixes  
laurent committed
733

734
      pushNotifiedFIFO_nothreadSafe(&freeBlocks,res);
laurent's avatar
laurent committed
735
    }
736

laurent's avatar
laurent committed
737 738 739 740 741
  } // while !oai_exit

  return NULL;
}

742
void init_NR_UE(int nb_inst, char* rrc_config_path) {
laurent's avatar
laurent committed
743 744
  int inst;
  NR_UE_MAC_INST_t *mac_inst;
Florian Kaltenberger's avatar
Florian Kaltenberger committed
745 746
  NR_UE_RRC_INST_t* rrc_inst;
  
laurent's avatar
laurent committed
747
  for (inst=0; inst < nb_inst; inst++) {
Florian Kaltenberger's avatar
Florian Kaltenberger committed
748 749 750
    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");
751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767

    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);
      }
    }
768 769 770 771 772 773 774 775 776 777 778
  }
}

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

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

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

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