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

22
#define _GNU_SOURCE // For pthread_setname_np
Laurent THOMAS's avatar
Laurent THOMAS committed
23
#include <pthread.h>
Laurent THOMAS's avatar
Laurent THOMAS committed
24
#include <openair1/PHY/impl_defs_top.h>
cig's avatar
cig committed
25
#include "executables/nr-uesoftmodem.h"
laurent's avatar
laurent committed
26 27
#include "PHY/phy_extern_nr_ue.h"
#include "PHY/INIT/phy_init.h"
28
#include "NR_MAC_UE/mac_proto.h"
laurent's avatar
laurent committed
29
#include "RRC/NR_UE/rrc_proto.h"
cig's avatar
cig committed
30
#include "SCHED_NR_UE/phy_frame_config_nr.h"
laurent's avatar
laurent committed
31 32
#include "SCHED_NR_UE/defs.h"
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
33
#include "executables/softmodem-common.h"
34
#include "LAYER2/nr_pdcp/nr_pdcp_entity.h"
Sakthivel Velumani's avatar
Sakthivel Velumani committed
35
#include "SCHED_NR_UE/pucch_uci_ue_nr.h"
36
#include "openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h"
37
#include "PHY/NR_REFSIG/refsig_defs_ue.h"
laurent's avatar
laurent committed
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 93 94 95

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

Laurent THOMAS's avatar
Laurent THOMAS committed
96

Sakthivel Velumani's avatar
Sakthivel Velumani committed
97 98
#define RX_JOB_ID 0x1010
#define TX_JOB_ID 100
laurent's avatar
laurent committed
99

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

106 107
queue_t nr_rach_ind_queue;

108 109
static void *NRUE_phy_stub_standalone_pnf_task(void *arg);

110
static size_t dump_L1_UE_meas_stats(PHY_VARS_NR_UE *ue, char *output, size_t max_len)
111
{
112 113 114 115
  const char *begin = output;
  const char *end = output + max_len;
  output += print_meas_log(&ue->phy_proc_tx, "L1 TX processing", NULL, NULL, output, end - output);
  output += print_meas_log(&ue->ulsch_encoding_stats, "ULSCH encoding", NULL, NULL, output, end - output);
116
  output += print_meas_log(&ue->phy_proc_rx, "L1 RX processing", NULL, NULL, output, end - output);
117 118
  output += print_meas_log(&ue->ue_ul_indication_stats, "UL Indication", NULL, NULL, output, end - output);
  output += print_meas_log(&ue->rx_pdsch_stats, "PDSCH receiver", NULL, NULL, output, end - output);
119
  output += print_meas_log(&ue->dlsch_decoding_stats, "PDSCH decoding", NULL, NULL, output, end - output);
120 121 122 123 124 125
  output += print_meas_log(&ue->dlsch_deinterleaving_stats, " -> Deinterleive", NULL, NULL, output, end - output);
  output += print_meas_log(&ue->dlsch_rate_unmatching_stats, " -> Rate Unmatch", NULL, NULL, output, end - output);
  output += print_meas_log(&ue->dlsch_ldpc_decoding_stats, " ->  LDPC Decode", NULL, NULL, output, end - output);
  output += print_meas_log(&ue->dlsch_unscrambling_stats, "PDSCH unscrambling", NULL, NULL, output, end - output);
  output += print_meas_log(&ue->dlsch_rx_pdcch_stats, "PDCCH handling", NULL, NULL, output, end - output);
  return output - begin;
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
}

static void *nrL1_UE_stats_thread(void *param)
{
  PHY_VARS_NR_UE *ue = (PHY_VARS_NR_UE *) param;
  const int max_len = 16384;
  char output[max_len];
  char filename[30];
  snprintf(filename, 29, "nrL1_UE_stats-%d.log", ue->Mod_id);
  filename[29] = 0;
  FILE *fd = fopen(filename, "w");
  AssertFatal(fd != NULL, "Cannot open %s\n", filename);

  while (!oai_exit) {
    sleep(1);
    const int len = dump_L1_UE_meas_stats(ue, output, max_len);
    AssertFatal(len < max_len, "exceeded length\n");
    fwrite(output, len + 1, 1, fd); // + 1 for terminating NULL byte
    fflush(fd);
    fseek(fd, 0, SEEK_SET);
  }
  fclose(fd);

  return NULL;
}

152 153 154
void init_nr_ue_vars(PHY_VARS_NR_UE *ue,
                     uint8_t UE_id,
                     uint8_t abstraction_flag)
laurent's avatar
laurent committed
155
{
156

157 158
  int nb_connected_gNB = 1, gNB_id;

laurent's avatar
laurent committed
159
  ue->Mod_id      = UE_id;
160
  ue->mac_enabled = 1;
161
  ue->if_inst     = nr_ue_if_module_init(0);
162
  ue->dci_thres   = 0;
163

164 165 166 167 168 169
  // 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
170
  // initialize all signal buffers
171
  init_nr_ue_signal(ue, nb_connected_gNB);
172

laurent's avatar
laurent committed
173
  // intialize transport
174
  init_nr_ue_transport(ue);
175 176 177

  // init N_TA offset
  init_N_TA_offset(ue);
laurent's avatar
laurent committed
178 179
}

180 181
void init_nrUE_standalone_thread(int ue_idx)
{
182 183
  int standalone_tx_port = 3611 + ue_idx * 2;
  int standalone_rx_port = 3612 + ue_idx * 2;
184
  nrue_init_standalone_socket(standalone_tx_port, standalone_rx_port);
185

186 187 188
  NR_UE_MAC_INST_t *mac = get_mac_inst(0);
  pthread_mutex_init(&mac->mutex_dl_info, NULL);

189 190 191 192 193
  pthread_t thread;
  if (pthread_create(&thread, NULL, nrue_standalone_pnf_task, NULL) != 0) {
    LOG_E(NR_MAC, "pthread_create failed for calling nrue_standalone_pnf_task");
  }
  pthread_setname_np(thread, "oai:nrue-stand");
194 195 196 197 198
  pthread_t phy_thread;
  if (pthread_create(&phy_thread, NULL, NRUE_phy_stub_standalone_pnf_task, NULL) != 0) {
    LOG_E(NR_MAC, "pthread_create failed for calling NRUE_phy_stub_standalone_pnf_task");
  }
  pthread_setname_np(phy_thread, "oai:nrue-stand-phy");
199 200
}

201
static void L1_nsa_prach_procedures(frame_t frame, int slot, fapi_nr_ul_config_prach_pdu *prach_pdu)
202
{
203
  NR_UE_MAC_INST_t *mac    = get_mac_inst(0);
204
  nfapi_nr_rach_indication_t *rach_ind = CALLOC(1, sizeof(*rach_ind));
205 206 207
  rach_ind->sfn = frame;
  rach_ind->slot = slot;
  rach_ind->header.message_id = NFAPI_NR_PHY_MSG_TYPE_RACH_INDICATION;
208 209

  uint8_t pdu_index = 0;
210 211 212 213 214
  rach_ind->pdu_list = CALLOC(1, sizeof(*rach_ind->pdu_list));
  rach_ind->number_of_pdus  = 1;
  rach_ind->pdu_list[pdu_index].phy_cell_id                         = prach_pdu->phys_cell_id;
  rach_ind->pdu_list[pdu_index].symbol_index                        = prach_pdu->prach_start_symbol;
  rach_ind->pdu_list[pdu_index].slot_index                          = prach_pdu->prach_slot;
215
  rach_ind->pdu_list[pdu_index].freq_index                          = prach_pdu->num_ra;
216 217 218 219 220 221
  rach_ind->pdu_list[pdu_index].avg_rssi                            = 128;
  rach_ind->pdu_list[pdu_index].avg_snr                             = 0xff; // invalid for now

  rach_ind->pdu_list[pdu_index].num_preamble                        = 1;
  const int num_p = rach_ind->pdu_list[pdu_index].num_preamble;
  rach_ind->pdu_list[pdu_index].preamble_list = calloc(num_p, sizeof(nfapi_nr_prach_indication_preamble_t));
222 223 224 225
  uint8_t preamble_index = get_softmodem_params()->nsa ?
                           mac->ra.rach_ConfigDedicated->cfra->resources.choice.ssb->ssb_ResourceList.list.array[0]->ra_PreambleIndex :
                           mac->ra.ra_PreambleIndex;
  rach_ind->pdu_list[pdu_index].preamble_list[0].preamble_index     = preamble_index;
226

227 228 229
  rach_ind->pdu_list[pdu_index].preamble_list[0].timing_advance     = 0;
  rach_ind->pdu_list[pdu_index].preamble_list[0].preamble_pwr       = 0xffffffff;

230 231
  if (!put_queue(&nr_rach_ind_queue, rach_ind))
  {
232 233 234 235
    for (int pdu_index = 0; pdu_index < rach_ind->number_of_pdus; pdu_index++)
    {
      free(rach_ind->pdu_list[pdu_index].preamble_list);
    }
236
    free(rach_ind->pdu_list);
237
    free(rach_ind);
238
  }
Melissa Elkadi's avatar
Melissa Elkadi committed
239
  LOG_D(NR_MAC, "We have successfully filled the rach_ind queue with the recently filled rach ind\n");
240 241
}

242
static void process_queued_nr_nfapi_msgs(NR_UE_MAC_INST_t *mac, int sfn_slot)
243 244
{
  nfapi_nr_rach_indication_t *rach_ind = unqueue_matching(&nr_rach_ind_queue, MAX_QUEUE_SIZE, sfn_slot_matcher, &sfn_slot);
245 246
  nfapi_nr_dl_tti_request_t *dl_tti_request = get_queue(&nr_dl_tti_req_queue);
  nfapi_nr_ul_dci_request_t *ul_dci_request = get_queue(&nr_ul_dci_req_queue);
247

Melissa Elkadi's avatar
Melissa Elkadi committed
248
  for (int i = 0; i < NR_MAX_HARQ_PROCESSES; i++) {
249
    LOG_D(NR_MAC, "Try to get a ul_tti_req by matching CRC active SFN %d/SLOT %d from queue with %lu items\n",
Melissa Elkadi's avatar
Melissa Elkadi committed
250 251 252
            NFAPI_SFNSLOT2SFN(mac->nr_ue_emul_l1.harq[i].active_ul_harq_sfn_slot),
            NFAPI_SFNSLOT2SLOT(mac->nr_ue_emul_l1.harq[i].active_ul_harq_sfn_slot), nr_ul_tti_req_queue.num_items);
    nfapi_nr_ul_tti_request_t *ul_tti_request_crc = unqueue_matching(&nr_ul_tti_req_queue, MAX_QUEUE_SIZE, sfn_slot_matcher, &mac->nr_ue_emul_l1.harq[i].active_ul_harq_sfn_slot);
253 254 255 256
    if (ul_tti_request_crc && ul_tti_request_crc->n_pdus > 0)
    {
      check_and_process_dci(NULL, NULL, NULL, ul_tti_request_crc);
    }
257
  }
258 259 260 261 262 263 264 265 266

  if (rach_ind && rach_ind->number_of_pdus > 0)
  {
      NR_UL_IND_t UL_INFO = {
        .rach_ind = *rach_ind,
      };
      send_nsa_standalone_msg(&UL_INFO, rach_ind->header.message_id);
      for (int i = 0; i < rach_ind->number_of_pdus; i++)
      {
Melissa Elkadi's avatar
Melissa Elkadi committed
267
        free_and_zero(rach_ind->pdu_list[i].preamble_list);
268
      }
Melissa Elkadi's avatar
Melissa Elkadi committed
269 270
      free_and_zero(rach_ind->pdu_list);
      free_and_zero(rach_ind);
271 272
      nr_Msg1_transmitted(0, 0, NFAPI_SFNSLOT2SFN(sfn_slot), 0);
  }
273
  if (dl_tti_request)
274
  {
275 276
    int dl_tti_sfn_slot = NFAPI_SFNSLOT2HEX(dl_tti_request->SFN, dl_tti_request->Slot);
    nfapi_nr_tx_data_request_t *tx_data_request = unqueue_matching(&nr_tx_req_queue, MAX_QUEUE_SIZE, sfn_slot_matcher, &dl_tti_sfn_slot);
277 278
    if (!tx_data_request)
    {
279 280
      LOG_E(NR_MAC, "[%d %d] No corresponding tx_data_request for given dl_tti_request sfn/slot\n",
            NFAPI_SFNSLOT2SFN(dl_tti_sfn_slot), NFAPI_SFNSLOT2SLOT(dl_tti_sfn_slot));
281 282
      if (get_softmodem_params()->nsa)
        save_nr_measurement_info(dl_tti_request);
Melissa Elkadi's avatar
Melissa Elkadi committed
283
      free_and_zero(dl_tti_request);
284 285 286
    }
    else if (dl_tti_request->dl_tti_request_body.nPDUs > 0 && tx_data_request->Number_of_PDUs > 0)
    {
287 288
      if (get_softmodem_params()->nsa)
        save_nr_measurement_info(dl_tti_request);
289 290
      check_and_process_dci(dl_tti_request, tx_data_request, NULL, NULL);
    }
291 292 293 294 295
    else
    {
      AssertFatal(false, "We dont have PDUs in either dl_tti %d or tx_req %d\n",
                  dl_tti_request->dl_tti_request_body.nPDUs, tx_data_request->Number_of_PDUs);
    }
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
  }
  if (ul_dci_request && ul_dci_request->numPdus > 0)
  {
    check_and_process_dci(NULL, NULL, ul_dci_request, NULL);
  }
}

static void check_nr_prach(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info, NR_PRACH_RESOURCES_t *prach_resources)
{
  fapi_nr_ul_config_request_t *ul_config = get_ul_config_request(mac, ul_info->slot_tx);
  if (!ul_config)
  {
    LOG_E(NR_MAC, "mac->ul_config is null! \n");
    return;
  }
  if (mac->ra.ra_state != RA_SUCCEEDED)
  {
    AssertFatal(ul_config->number_pdus < sizeof(ul_config->ul_config_list) / sizeof(ul_config->ul_config_list[0]),
                "Number of PDUS in ul_config = %d > ul_config_list num elements", ul_config->number_pdus);
    fapi_nr_ul_config_prach_pdu *prach_pdu = &ul_config->ul_config_list[ul_config->number_pdus].prach_config_pdu;
316 317 318 319 320 321 322
    uint8_t nr_prach = nr_ue_get_rach(prach_resources,
                                      prach_pdu,
                                      ul_info->module_id,
                                      ul_info->cc_id,
                                      ul_info->frame_tx,
                                      ul_info->gNB_index,
                                      ul_info->slot_tx);
323 324 325 326
    if (nr_prach == 1)
    {
      L1_nsa_prach_procedures(ul_info->frame_tx, ul_info->slot_tx, prach_pdu);
      ul_config->number_pdus = 0;
327
      ul_info->ue_sched_mode = SCHED_PUSCH;
328 329 330 331 332 333 334 335 336 337 338 339
    }
    else if (nr_prach == 2)
    {
      LOG_I(NR_PHY, "In %s: [UE %d] RA completed, setting UE mode to PUSCH\n", __FUNCTION__, ul_info->module_id);
    }
    else if(nr_prach == 3)
    {
      LOG_I(NR_PHY, "In %s: [UE %d] RA failed, setting UE mode to PRACH\n", __FUNCTION__, ul_info->module_id);
    }
  }
}

Melissa Elkadi's avatar
Melissa Elkadi committed
340 341
static void *NRUE_phy_stub_standalone_pnf_task(void *arg)
{
342 343 344 345
  LOG_I(MAC, "Clearing Queues\n");
  reset_queue(&nr_rach_ind_queue);
  reset_queue(&nr_rx_ind_queue);
  reset_queue(&nr_crc_ind_queue);
346
  reset_queue(&nr_uci_ind_queue);
347 348 349 350
  reset_queue(&nr_dl_tti_req_queue);
  reset_queue(&nr_tx_req_queue);
  reset_queue(&nr_ul_dci_req_queue);
  reset_queue(&nr_ul_tti_req_queue);
351

352 353
  NR_PRACH_RESOURCES_t prach_resources;
  memset(&prach_resources, 0, sizeof(prach_resources));
354 355
  NR_UL_TIME_ALIGNMENT_t ul_time_alignment;
  memset(&ul_time_alignment, 0, sizeof(ul_time_alignment));
Melissa Elkadi's avatar
Melissa Elkadi committed
356
  int last_sfn_slot = -1;
357
  uint16_t sfn_slot = 0;
358

Melissa Elkadi's avatar
Melissa Elkadi committed
359 360 361 362 363 364 365
  module_id_t mod_id = 0;
  NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
  for (int i = 0; i < NR_MAX_HARQ_PROCESSES; i++) {
      mac->nr_ue_emul_l1.harq[i].active = false;
      mac->nr_ue_emul_l1.harq[i].active_ul_harq_sfn_slot = -1;
  }

Melissa Elkadi's avatar
Melissa Elkadi committed
366 367 368 369 370 371 372
  while (!oai_exit)
  {
    if (sem_wait(&sfn_slot_semaphore) != 0)
    {
      LOG_E(NR_MAC, "sem_wait() error\n");
      abort();
    }
373 374 375
    uint16_t *slot_ind = get_queue(&nr_sfn_slot_queue);
    nr_phy_channel_params_t *ch_info = get_queue(&nr_chan_param_queue);
    if (!slot_ind && !ch_info)
376
    {
377 378
      LOG_D(MAC, "get nr_sfn_slot_queue and nr_chan_param_queue == NULL!\n");
      continue;
379 380 381
    }
    if (slot_ind) {
      sfn_slot = *slot_ind;
382
      free_and_zero(slot_ind);
383 384 385
    }
    else if (ch_info) {
      sfn_slot = ch_info->sfn_slot;
386
      free_and_zero(ch_info);
387
    }
388

389 390 391
    frame_t frame = NFAPI_SFNSLOT2SFN(sfn_slot);
    int slot = NFAPI_SFNSLOT2SLOT(sfn_slot);
    if (sfn_slot == last_sfn_slot)
Melissa Elkadi's avatar
Melissa Elkadi committed
392
    {
393
      LOG_D(NR_MAC, "repeated sfn_sf = %d.%d\n",
394
            frame, slot);
Melissa Elkadi's avatar
Melissa Elkadi committed
395 396
      continue;
    }
397
    last_sfn_slot = sfn_slot;
398

399 400
    LOG_D(NR_MAC, "The received sfn/slot [%d %d] from proxy\n",
          frame, slot);
Melissa Elkadi's avatar
Melissa Elkadi committed
401

402
    if (get_softmodem_params()->sa && mac->mib == NULL)
403
    {
404 405 406
      LOG_D(NR_MAC, "We haven't gotten MIB. Lets see if we received it\n");
      nr_ue_dl_indication(&mac->dl_info, &ul_time_alignment);
      process_queued_nr_nfapi_msgs(mac, sfn_slot);
407
    }
408
    if (mac->scc == NULL && mac->scc_SIB == NULL)
409 410
    {
      LOG_D(MAC, "[NSA] mac->scc == NULL and [SA] mac->scc_SIB == NULL!\n");
411 412 413
      continue;
    }

414
    mac->ra.generate_nr_prach = 0;
415 416
    int CC_id = 0;
    uint8_t gNB_id = 0;
417
    nr_uplink_indication_t ul_info;
418
    int slots_per_frame = 20; //30 kHZ subcarrier spacing
Melissa Elkadi's avatar
Melissa Elkadi committed
419
    int slot_ahead = 2; // TODO: Make this dynamic
420 421 422
    ul_info.cc_id = CC_id;
    ul_info.gNB_index = gNB_id;
    ul_info.module_id = mod_id;
423 424
    ul_info.frame_rx = frame;
    ul_info.slot_rx = slot;
425 426
    ul_info.slot_tx = (slot + slot_ahead) % slots_per_frame;
    ul_info.frame_tx = (ul_info.slot_rx + slot_ahead >= slots_per_frame) ? ul_info.frame_rx + 1 : ul_info.frame_rx;
427
    ul_info.ue_sched_mode = SCHED_PUSCH;
428

429
    if (pthread_mutex_lock(&mac->mutex_dl_info)) abort();
430

431 432 433 434 435 436 437 438
    memset(&mac->dl_info, 0, sizeof(mac->dl_info));
    mac->dl_info.cc_id = CC_id;
    mac->dl_info.gNB_index = gNB_id;
    mac->dl_info.module_id = mod_id;
    mac->dl_info.frame = frame;
    mac->dl_info.slot = slot;
    mac->dl_info.dci_ind = NULL;
    mac->dl_info.rx_ind = NULL;
Melissa Elkadi's avatar
Melissa Elkadi committed
439 440 441 442 443 444
    if (ch_info) {
      mac->nr_ue_emul_l1.pmi = ch_info->csi[0].pmi;
      mac->nr_ue_emul_l1.ri = ch_info->csi[0].ri;
      mac->nr_ue_emul_l1.cqi = ch_info->csi[0].cqi;
      free_and_zero(ch_info);
    }
445

446 447 448 449
    if (is_nr_DL_slot(get_softmodem_params()->nsa ?
                      mac->scc->tdd_UL_DL_ConfigurationCommon :
                      mac->scc_SIB->tdd_UL_DL_ConfigurationCommon,
                      ul_info.slot_rx))
450 451 452
    {
      nr_ue_dl_indication(&mac->dl_info, &ul_time_alignment);
    }
453 454 455

    if (pthread_mutex_unlock(&mac->mutex_dl_info)) abort();

456 457 458 459
    if (is_nr_UL_slot(get_softmodem_params()->nsa ?
                      mac->scc->tdd_UL_DL_ConfigurationCommon :
                      mac->scc_SIB->tdd_UL_DL_ConfigurationCommon,
                      ul_info.slot_tx, mac->frame_type))
460
    {
461
      LOG_D(NR_MAC, "Slot %d. calling nr_ue_ul_ind() and nr_ue_pucch_scheduler() from %s\n", ul_info.slot_tx, __FUNCTION__);
462
      nr_ue_scheduler(NULL, &ul_info);
463 464
      nr_ue_prach_scheduler(mod_id, ul_info.frame_tx, ul_info.slot_tx);
      nr_ue_pucch_scheduler(mod_id, ul_info.frame_tx, ul_info.slot_tx, NULL);
465
      check_nr_prach(mac, &ul_info, &prach_resources);
466
    }
467
    if (!IS_SOFTMODEM_NOS1 && get_softmodem_params()->sa) {
468 469 470 471 472
      NR_UE_MAC_INST_t *mac = get_mac_inst(0);
      protocol_ctxt_t ctxt;
      PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, 0, ENB_FLAG_NO, mac->crnti, frame, slot, 0);
      pdcp_run(&ctxt);
    }
473
    process_queued_nr_nfapi_msgs(mac, sfn_slot);
Melissa Elkadi's avatar
Melissa Elkadi committed
474
  }
475
  return NULL;
Melissa Elkadi's avatar
Melissa Elkadi committed
476
}
477

478

laurent's avatar
laurent committed
479 480 481 482 483
/*!
 * 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
484
typedef nr_rxtx_thread_data_t syncData_t;
485

laurent's avatar
laurent committed
486 487 488 489 490
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;
491
  //int CC_id = UE->CC_id;
492
  static int freq_offset=0;
laurent's avatar
laurent committed
493 494 495 496 497 498
  UE->is_synchronized = 0;

  if (UE->UE_scan == 0) {

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

499
      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",
500 501 502 503 504 505 506
        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
507 508 509 510
    }

    sync_mode = pbch;
  } else {
511 512
    LOG_E(PHY,"Fixme!\n");
    /*
laurent's avatar
laurent committed
513 514 515 516 517 518 519 520 521
    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;
    }
522
    */
laurent's avatar
laurent committed
523 524 525 526 527
  }

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

  switch (sync_mode) {
528
    /*
laurent's avatar
laurent committed
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
    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;
557
    */
laurent's avatar
laurent committed
558 559 560
    case pbch:
      LOG_I(PHY, "[UE thread Synch] Running Initial Synch (mode %d)\n",UE->mode);

561
      uint64_t dl_carrier, ul_carrier;
562
      nr_get_carrier_frequencies(UE, &dl_carrier, &ul_carrier);
563

564
      if (nr_initial_sync(&syncD->proc, UE, 2, get_softmodem_params()->sa) == 0) {
laurent's avatar
laurent committed
565
        freq_offset = UE->common_vars.freq_offset; // frequency offset computed with pss in initial sync
566
        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
567
                         round((float)((UE->rx_offset<<1) % UE->frame_parms.samples_per_subframe)/UE->frame_parms.samples_per_slot0);
laurent's avatar
laurent committed
568 569

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

573
        LOG_I(PHY,"Got synch: hw_slot_offset %d, carrier off %d Hz, rxgain %f (DL %f Hz, UL %f Hz)\n",
574 575
              hw_slot_offset,
              freq_offset,
576
              openair0_cfg[UE->rf_map.card].rx_gain[0],
577
              openair0_cfg[UE->rf_map.card].rx_freq[0],
578
              openair0_cfg[UE->rf_map.card].tx_freq[0]);
579

Robert Schmidt's avatar
Robert Schmidt committed
580
        UE->rfdevice.trx_set_freq_func(&UE->rfdevice,&openair0_cfg[0]);
laurent's avatar
laurent committed
581 582 583 584 585 586
        if (UE->UE_scan_carrier == 1) {
          UE->UE_scan_carrier = 0;
        } else {
          UE->is_synchronized = 1;
        }
      } else {
587

588
        if (UE->UE_scan_carrier == 1) {
589

laurent's avatar
laurent committed
590 591 592 593
          if (freq_offset >= 0)
            freq_offset += 100;

          freq_offset *= -1;
594

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

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

Robert Schmidt's avatar
Robert Schmidt committed
599
          UE->rfdevice.trx_set_freq_func(&UE->rfdevice,&openair0_cfg[0]);
600
        }
601 602
      }
      break;
laurent's avatar
laurent committed
603

604 605 606
    case si:
    default:
      break;
laurent's avatar
laurent committed
607 608 609 610

  }
}

Sakthivel Velumani's avatar
Sakthivel Velumani committed
611 612
void processSlotTX(void *arg) {

613
  nr_rxtx_thread_data_t *rxtxD = (nr_rxtx_thread_data_t *) arg;
Sakthivel Velumani's avatar
Sakthivel Velumani committed
614 615
  UE_nr_rxtx_proc_t *proc = &rxtxD->proc;
  PHY_VARS_NR_UE    *UE   = rxtxD->UE;
616

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

620 621 622
    // 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) {
623
      start_meas(&UE->ue_ul_indication_stats);
624 625 626 627
      nr_uplink_indication_t ul_indication;
      memset((void*)&ul_indication, 0, sizeof(ul_indication));

      ul_indication.module_id = UE->Mod_id;
628
      ul_indication.gNB_index = proc->gNB_id;
629 630
      ul_indication.cc_id     = UE->CC_id;
      ul_indication.frame_rx  = proc->frame_rx;
631
      ul_indication.slot_rx   = proc->nr_slot_rx;
632
      ul_indication.frame_tx  = proc->frame_tx;
633
      ul_indication.slot_tx   = proc->nr_slot_tx;
634
      ul_indication.ue_sched_mode = rxtxD->ue_sched_mode;
Florian Kaltenberger's avatar
Florian Kaltenberger committed
635

636
      UE->if_inst->ul_indication(&ul_indication);
637
      stop_meas(&UE->ue_ul_indication_stats);
638
    }
639

640
    phy_procedures_nrUE_TX(UE,proc,proc->gNB_id);
Florian Kaltenberger's avatar
Florian Kaltenberger committed
641 642 643
  }
}

644
void UE_processing(nr_rxtx_thread_data_t *rxtxD) {
Florian Kaltenberger's avatar
Florian Kaltenberger committed
645

Sakthivel Velumani's avatar
Sakthivel Velumani committed
646 647
  UE_nr_rxtx_proc_t *proc = &rxtxD->proc;
  PHY_VARS_NR_UE    *UE   = rxtxD->UE;
cig's avatar
cig committed
648
  uint8_t gNB_id = 0;
649
  NR_UE_PDCCH_CONFIG phy_pdcch_config={0};
Florian Kaltenberger's avatar
Florian Kaltenberger committed
650

651 652 653 654 655 656 657 658 659 660
  if (IS_SOFTMODEM_NOS1 || get_softmodem_params()->sa) {
    /* 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);
    }
  }

661
  if (proc->rx_slot_type == NR_DOWNLINK_SLOT || proc->rx_slot_type == NR_MIXED_SLOT){
Florian Kaltenberger's avatar
Florian Kaltenberger committed
662

663
    if(UE->if_inst != NULL && UE->if_inst->dl_indication != NULL) {
664
      nr_downlink_indication_t dl_indication;
665
      nr_fill_dl_indication(&dl_indication, NULL, NULL, proc, UE, gNB_id, &phy_pdcch_config);
666 667
      UE->if_inst->dl_indication(&dl_indication, NULL);
    }
668

Florian Kaltenberger's avatar
Florian Kaltenberger committed
669
  // Process Rx data for one sub-frame
laurent's avatar
laurent committed
670
#ifdef UE_SLOT_PARALLELISATION
cig's avatar
cig committed
671
    phy_procedures_slot_parallelization_nrUE_RX( UE, proc, 0, 0, 1, no_relay, NULL );
laurent's avatar
laurent committed
672
#else
673
    uint64_t a=rdtsc_oai();
674
    phy_procedures_nrUE_RX(UE, proc, gNB_id, &phy_pdcch_config, &rxtxD->txFifo);
675
    LOG_D(PHY, "In %s: slot %d, time %llu\n", __FUNCTION__, proc->nr_slot_rx, (rdtsc_oai()-a)/3500);
laurent's avatar
laurent committed
676
#endif
Raymond Knopp's avatar
Raymond Knopp committed
677

678
    if(IS_SOFTMODEM_NOS1 || get_softmodem_params()->sa){
cig's avatar
cig committed
679
      NR_UE_MAC_INST_t *mac = get_mac_inst(0);
Florian Kaltenberger's avatar
Florian Kaltenberger committed
680
      protocol_ctxt_t ctxt;
cig's avatar
cig committed
681
      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
682 683
      pdcp_run(&ctxt);
    }
laurent's avatar
laurent committed
684

685
    // Wait for PUSCH processing to finish
686 687
    notifiedFIFO_elt_t *res;
    res = pullTpool(&rxtxD->txFifo,&(get_nrUE_params()->Tpool));
688 689
    if (res == NULL)
      return; // Tpool has been stopped
690
    delNotifiedFIFO_elt(res);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
691
  }
laurent's avatar
laurent committed
692

693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708
  if (proc->tx_slot_type == NR_UPLINK_SLOT || proc->tx_slot_type == NR_MIXED_SLOT) {
    nr_phy_data_t phy_data = {0};
    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;
      ul_indication.slot_rx       = proc->nr_slot_rx;
      ul_indication.frame_tx      = proc->frame_tx;
      ul_indication.slot_tx       = proc->nr_slot_tx;
      ul_indication.ue_sched_mode = SCHED_PUCCH;
      ul_indication.phy_data      = &phy_data;
      UE->if_inst->ul_indication(&ul_indication);
    }
Sakthivel Velumani's avatar
Sakthivel Velumani committed
709
    if (UE->UE_mode[gNB_id] <= PUSCH) {
710 711 712 713
      pucch_procedures_ue_nr(UE,
                             gNB_id,
                             proc,
                             &phy_data);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
714
    }
laurent's avatar
laurent committed
715

716 717 718 719 720 721 722 723
    LOG_D(PHY, "Sending Uplink data \n");
    nr_ue_pusch_common_procedures(UE,
                                  proc->nr_slot_tx,
                                  &UE->frame_parms,
                                  UE->frame_parms.nb_antennas_tx);

    if (UE->UE_mode[gNB_id] > NOT_SYNCHED && UE->UE_mode[gNB_id] < PUSCH)
      nr_ue_prach_procedures(UE, proc, proc->gNB_id);
724
  }
725

Sakthivel Velumani's avatar
Sakthivel Velumani committed
726
  ue_ta_procedures(UE, proc->nr_slot_tx, proc->frame_tx);
laurent's avatar
laurent committed
727 728
}

729
void dummyWrite(PHY_VARS_NR_UE *UE,openair0_timestamp timestamp, int writeBlockSize) {
laurent's avatar
laurent committed
730
  void *dummy_tx[UE->frame_parms.nb_antennas_tx];
731
  int16_t dummy_tx_data[UE->frame_parms.nb_antennas_tx][2*writeBlockSize]; // 2 because the function we call use pairs of int16_t implicitly as complex numbers
Laurent THOMAS's avatar
Laurent THOMAS committed
732
  memset(dummy_tx_data, 0, sizeof(dummy_tx_data));
laurent's avatar
laurent committed
733
  for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
734
    dummy_tx[i]=dummy_tx_data[i];
laurent's avatar
laurent committed
735

736 737 738 739 740 741 742
  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
743 744 745

}

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

748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772
  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]);
773
    }
laurent's avatar
laurent committed
774 775 776 777 778
  }

}

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

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

Sakthivel Velumani's avatar
Sakthivel Velumani committed
782
    *timestamp += UE->frame_parms.get_samples_per_slot(1,&UE->frame_parms);
laurent's avatar
laurent committed
783 784
    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 ;
785
      // we write before read because gNB waits for UE to write and both executions halt
Sakthivel Velumani's avatar
Sakthivel Velumani committed
786 787
      // 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
788 789 790 791 792 793
      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
794
      *timestamp += unitTransfer; // this does not affect the read but needed for RFSIM write
laurent's avatar
laurent committed
795 796 797 798 799
    }

}

int computeSamplesShift(PHY_VARS_NR_UE *UE) {
800
  int samples_shift = -(UE->rx_offset>>1);
luis_pereira87's avatar
luis_pereira87 committed
801 802
  if (samples_shift != 0) {
    LOG_I(NR_PHY,"Adjusting frame in time by %i samples\n", samples_shift);
803 804
    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 += samples_shift; // reset IIR filter when sample shift is applied
805
  }
806
  return samples_shift;
laurent's avatar
laurent committed
807 808
}

809
static inline int get_firstSymSamp(uint16_t slot, NR_DL_FRAME_PARMS *fp) {
Sakthivel Velumani's avatar
Sakthivel Velumani committed
810 811 812 813 814 815 816
  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;
}

817
static inline int get_readBlockSize(uint16_t slot, NR_DL_FRAME_PARMS *fp) {
Sakthivel Velumani's avatar
Sakthivel Velumani committed
818 819 820 821 822 823 824
  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
825
void *UE_thread(void *arg) {
laurent's avatar
laurent committed
826
  //this thread should be over the processing thread to keep in real time
laurent's avatar
laurent committed
827 828
  PHY_VARS_NR_UE *UE = (PHY_VARS_NR_UE *) arg;
  //  int tx_enabled = 0;
829
  openair0_timestamp timestamp, writeTimestamp;
laurent's avatar
laurent committed
830 831
  void *rxp[NB_ANTENNAS_RX], *txp[NB_ANTENNAS_TX];
  int start_rx_stream = 0;
832
  fapi_nr_config_request_t *cfg = &UE->nrUE_config;
laurent's avatar
laurent committed
833 834
  AssertFatal(0== openair0_device_load(&(UE->rfdevice), &openair0_cfg[0]), "");
  UE->rfdevice.host_type = RAU_HOST;
835 836
  UE->lost_sync = 0;
  UE->is_synchronized = 0;
laurent's avatar
laurent committed
837
  AssertFatal(UE->rfdevice.trx_start_func(&UE->rfdevice) == 0, "Could not start the device\n");
Sakthivel Velumani's avatar
Sakthivel Velumani committed
838

laurent's avatar
laurent committed
839 840
  notifiedFIFO_t nf;
  initNotifiedFIFO(&nf);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
841

842 843
  notifiedFIFO_t freeBlocks;
  initNotifiedFIFO_nothreadSafe(&freeBlocks);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
844

845
  NR_UE_MAC_INST_t *mac = get_mac_inst(0);
846
  int timing_advance = UE->timing_advance;
laurent's avatar
laurent committed
847

laurent's avatar
fixes  
laurent committed
848
  bool syncRunning=false;
849
  const int nb_slot_frame = UE->frame_parms.slots_per_frame;
850
  int absolute_slot=0, decoded_frame_rx=INT_MAX, trashed_frames=0;
laurent's avatar
laurent committed
851 852

  while (!oai_exit) {
853 854 855 856 857
    if (UE->lost_sync) {
      UE->is_synchronized = 0;
      UE->lost_sync = 0;
    }

858
    if (syncRunning) {
859
      notifiedFIFO_elt_t *res=tryPullTpool(&nf,&(get_nrUE_params()->Tpool));
860 861 862 863

      if (res) {
        syncRunning=false;
        syncData_t *tmp=(syncData_t *)NotifiedFifoData(res);
864 865 866
        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
867
          decoded_frame_rx=(decoded_frame_rx + UE->init_sync_frame + trashed_frames) % MAX_FRAME_NUMBER;
868
        }
869
        delNotifiedFIFO_elt(res);
870
        start_rx_stream=0;
laurent's avatar
laurent committed
871
      } else {
872
        readFrame(UE, &timestamp, true);
873
        trashed_frames+=2;
874
        continue;
laurent's avatar
laurent committed
875
      }
876
    }
laurent's avatar
laurent committed
877

878
    AssertFatal( !syncRunning, "At this point synchronization can't be running\n");
879 880

    if (!UE->is_synchronized) {
881
      readFrame(UE, &timestamp, false);
882 883 884 885
      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));
886
      pushTpool(&(get_nrUE_params()->Tpool), Msg);
887 888
      trashed_frames=0;
      syncRunning=true;
laurent's avatar
laurent committed
889 890 891 892 893 894 895 896 897 898 899 900 901 902 903
      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
904 905
      // we have the decoded frame index in the return of the synch process
      // and we shifted above to the first slot of next frame
906
      decoded_frame_rx++;
907
      // we do ++ first in the regular processing, so it will be begin of frame;
908
      absolute_slot=decoded_frame_rx*nb_slot_frame -1;
laurent's avatar
laurent committed
909 910 911
      continue;
    }

912

laurent's avatar
laurent committed
913
    absolute_slot++;
914

laurent's avatar
fixes  
laurent committed
915
    int slot_nr = absolute_slot % nb_slot_frame;
916 917
    nr_rxtx_thread_data_t curMsg = {0};
    curMsg.UE=UE;
laurent's avatar
laurent committed
918
    // update thread index for received subframe
919 920 921 922 923 924 925 926 927
    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;
    curMsg.proc.rx_slot_type = nr_ue_slot_select(cfg, curMsg.proc.frame_rx, curMsg.proc.nr_slot_rx);
    curMsg.proc.tx_slot_type = nr_ue_slot_select(cfg, curMsg.proc.frame_tx, curMsg.proc.nr_slot_tx);
    curMsg.proc.decoded_frame_rx=-1;
    //LOG_I(PHY,"Process slot %d total gain %d\n", slot_nr, UE->rx_total_gain_dB);
Hongzhi Wang's avatar
Hongzhi Wang committed
928 929

#ifdef OAI_ADRV9371_ZC706
Hongzhi Wang's avatar
Hongzhi Wang committed
930
    /*uint32_t total_gain_dB_prev = 0;
Hongzhi Wang's avatar
Hongzhi Wang committed
931
    if (total_gain_dB_prev != UE->rx_total_gain_dB) {
Thomas Schlichter's avatar
Thomas Schlichter committed
932
        total_gain_dB_prev = UE->rx_total_gain_dB;
Hongzhi Wang's avatar
Hongzhi Wang committed
933
        openair0_cfg[0].rx_gain[0] = UE->rx_total_gain_dB;
Hongzhi Wang's avatar
Hongzhi Wang committed
934
        UE->rfdevice.trx_set_gains_func(&UE->rfdevice,&openair0_cfg[0]);
Hongzhi Wang's avatar
Hongzhi Wang committed
935
    }*/
Hongzhi Wang's avatar
Hongzhi Wang committed
936
#endif
laurent's avatar
laurent committed
937

Sakthivel Velumani's avatar
Sakthivel Velumani committed
938
    int firstSymSamp = get_firstSymSamp(slot_nr, &UE->frame_parms);
laurent's avatar
laurent committed
939
    for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++)
Sakthivel Velumani's avatar
Sakthivel Velumani committed
940
      rxp[i] = (void *)&UE->common_vars.rxdata[i][firstSymSamp+
941
               UE->frame_parms.get_samples_slot_timestamp(slot_nr,&UE->frame_parms,0)];
laurent's avatar
laurent committed
942 943

    for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
944
      txp[i] = (void *)&UE->common_vars.txdata[i][UE->frame_parms.get_samples_slot_timestamp(
945
               ((slot_nr + DURATION_RX_TO_TX - NR_RX_NB_TH)%nb_slot_frame),&UE->frame_parms,0)];
laurent's avatar
laurent committed
946 947 948 949

    int readBlockSize, writeBlockSize;

    if (slot_nr<(nb_slot_frame - 1)) {
Sakthivel Velumani's avatar
Sakthivel Velumani committed
950
      readBlockSize=get_readBlockSize(slot_nr, &UE->frame_parms);
951
      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
952 953
    } else {
      UE->rx_offset_diff = computeSamplesShift(UE);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
954
      readBlockSize=get_readBlockSize(slot_nr, &UE->frame_parms) -
laurent's avatar
laurent committed
955
                    UE->rx_offset_diff;
956
      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
957 958 959 960 961 962 963 964
    }

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

laurent's avatar
laurent committed
966 967
    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
968
      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
969

970 971
      if ( first_symbols > 0 ) {
        openair0_timestamp ignore_timestamp;
laurent's avatar
laurent committed
972 973
        AssertFatal(first_symbols ==
                    UE->rfdevice.trx_read_func(&UE->rfdevice,
974
                                               &ignore_timestamp,
laurent's avatar
laurent committed
975 976 977
                                               (void **)UE->common_vars.rxdata,
                                               first_symbols,
                                               UE->frame_parms.nb_antennas_rx),"");
978
      } else
laurent's avatar
laurent committed
979 980 981
        LOG_E(PHY,"can't compensate: diff =%d\n", first_symbols);
    }

982
    curMsg.proc.timestamp_tx = timestamp+
983
      UE->frame_parms.get_samples_slot_timestamp(slot_nr,&UE->frame_parms,DURATION_RX_TO_TX) 
984
      - firstSymSamp;
Sakthivel Velumani's avatar
Sakthivel Velumani committed
985

986
    UE_processing(&curMsg);
laurent's avatar
fixes  
laurent committed
987

988 989 990 991
    if (curMsg.proc.decoded_frame_rx != -1)
      decoded_frame_rx=(((mac->mib->systemFrameNumber.buf[0] >> mac->mib->systemFrameNumber.bits_unused)<<4) | curMsg.proc.decoded_frame_rx);
    else
       decoded_frame_rx=-1;
laurent's avatar
laurent committed
992

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

997
    // use previous timing_advance value to compute writeTimestamp
998 999
    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
1000
      - NR_RX_NB_TH) - firstSymSamp - openair0_cfg[0].tx_sample_advance -
1001
      UE->N_TA_offset - timing_advance;
1002 1003 1004 1005 1006 1007 1008

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

1009
    int flags = 0;
1010

1011
    if (openair0_cfg[0].duplex_mode == duplex_mode_TDD && !get_softmodem_params()->continuous_tx) {
cig's avatar
cig committed
1012

1013 1014
      uint8_t tdd_period = mac->phy_config.config_req.tdd_table.tdd_period_in_slots;
      int nrofUplinkSlots, nrofUplinkSymbols;
francescomani's avatar
francescomani committed
1015 1016 1017 1018 1019 1020 1021 1022
      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;
      }
1023

1024 1025
      int slot_tx_usrp = slot_nr + DURATION_RX_TO_TX - NR_RX_NB_TH;
      uint8_t  num_UL_slots = nrofUplinkSlots + (nrofUplinkSymbols != 0);
cig's avatar
cig committed
1026 1027
      uint8_t first_tx_slot = tdd_period - num_UL_slots;

1028 1029 1030 1031 1032 1033 1034
      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 {
1035
      flags = 1;
1036
    }
1037 1038

    if (flags || IS_SOFTMODEM_RFSIM)
1039 1040 1041 1042 1043 1044 1045
      AssertFatal(writeBlockSize ==
                  UE->rfdevice.trx_write_func(&UE->rfdevice,
                                              writeTimestamp,
                                              txp,
                                              writeBlockSize,
                                              UE->frame_parms.nb_antennas_tx,
                                              flags),"");
1046
    
1047 1048 1049
    for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
      memset(txp[i], 0, writeBlockSize);

laurent's avatar
laurent committed
1050 1051 1052 1053 1054
  } // while !oai_exit

  return NULL;
}

1055
void init_NR_UE(int nb_inst,
1056
                char* uecap_file,
1057
                char* rrc_config_path) {
laurent's avatar
laurent committed
1058 1059
  int inst;
  NR_UE_MAC_INST_t *mac_inst;
Florian Kaltenberger's avatar
Florian Kaltenberger committed
1060 1061
  NR_UE_RRC_INST_t* rrc_inst;
  
laurent's avatar
laurent committed
1062
  for (inst=0; inst < nb_inst; inst++) {
1063
    AssertFatal((rrc_inst = nr_l3_init_ue(uecap_file,rrc_config_path)) != NULL, "can not initialize RRC module\n");
Florian Kaltenberger's avatar
Florian Kaltenberger committed
1064 1065
    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");
1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076
  }
}

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
1077
    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
1078
    threadCreate(&threads[inst], UE_thread, (void *)UE, "UEthread", -1, OAI_PRIORITY_RT_MAX);
1079 1080 1081 1082
    if (!IS_SOFTMODEM_NOSTATS_BIT) {
      pthread_t stat_pthread;
      threadCreate(&stat_pthread, nrL1_UE_stats_thread, UE, "L1_UE_stats", -1, OAI_PRIORITY_RT_LOW);
    }
laurent's avatar
laurent committed
1083 1084 1085
  }
}

1086 1087 1088
/* HACK: this function is needed to compile the UE
 * fix it somehow
 */
1089
int find_dlsch(uint16_t rnti,
1090 1091 1092 1093 1094 1095 1096
                  PHY_VARS_eNB *eNB,
                  find_type_t type)
{
  printf("you cannot read this\n");
  abort();
}

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