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

Laurent THOMAS's avatar
Laurent THOMAS committed
22
#include <openair1/PHY/impl_defs_top.h>
cig's avatar
cig committed
23
#include "executables/nr-uesoftmodem.h"
laurent's avatar
laurent committed
24 25
#include "PHY/phy_extern_nr_ue.h"
#include "PHY/INIT/phy_init.h"
26
#include "NR_MAC_UE/mac_proto.h"
laurent's avatar
laurent committed
27
#include "RRC/NR_UE/rrc_proto.h"
cig's avatar
cig committed
28
#include "SCHED_NR_UE/phy_frame_config_nr.h"
laurent's avatar
laurent committed
29 30
#include "SCHED_NR_UE/defs.h"
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
Melissa Elkadi's avatar
Melissa Elkadi committed
31
#include "executables/softmodem-common.h"
32
#include "LAYER2/nr_pdcp/nr_pdcp_entity.h"
Sakthivel Velumani's avatar
Sakthivel Velumani committed
33
#include "SCHED_NR_UE/pucch_uci_ue_nr.h"
34
#include "openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h"
laurent's avatar
laurent committed
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92

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

Laurent THOMAS's avatar
Laurent THOMAS committed
93

Sakthivel Velumani's avatar
Sakthivel Velumani committed
94 95
#define RX_JOB_ID 0x1010
#define TX_JOB_ID 100
laurent's avatar
laurent committed
96 97

typedef enum {
98 99 100
  pss = 0,
  pbch = 1,
  si = 2
laurent's avatar
laurent committed
101 102
} sync_mode_t;

103 104
queue_t nr_rach_ind_queue;

105 106
static void *NRUE_phy_stub_standalone_pnf_task(void *arg);

107 108 109
void init_nr_ue_vars(PHY_VARS_NR_UE *ue,
                     uint8_t UE_id,
                     uint8_t abstraction_flag)
laurent's avatar
laurent committed
110
{
111

112 113
  int nb_connected_gNB = 1, gNB_id;

laurent's avatar
laurent committed
114 115
  ue->Mod_id      = UE_id;
  ue->mac_enabled = 1;
116
  ue->if_inst     = nr_ue_if_module_init(0);
117
  ue->dci_thres   = 0;
118

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

laurent's avatar
laurent committed
128
  // intialize transport
129
  init_nr_ue_transport(ue, abstraction_flag);
130 131 132

  // init N_TA offset
  init_N_TA_offset(ue);
laurent's avatar
laurent committed
133 134
}

135 136
void init_nrUE_standalone_thread(int ue_idx)
{
137 138
  int standalone_tx_port = 3611 + ue_idx * 2;
  int standalone_rx_port = 3612 + ue_idx * 2;
139
  nrue_init_standalone_socket(standalone_tx_port, standalone_rx_port);
140

141 142 143
  NR_UE_MAC_INST_t *mac = get_mac_inst(0);
  pthread_mutex_init(&mac->mutex_dl_info, NULL);

144 145 146 147 148
  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");
149 150 151 152 153
  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");
154 155
}

156
static void L1_nsa_prach_procedures(frame_t frame, int slot, fapi_nr_ul_config_prach_pdu *prach_pdu)
157
{
158
  NR_UE_MAC_INST_t *mac    = get_mac_inst(0);
159
  nfapi_nr_rach_indication_t *rach_ind = CALLOC(1, sizeof(*rach_ind));
160 161 162
  rach_ind->sfn = frame;
  rach_ind->slot = slot;
  rach_ind->header.message_id = NFAPI_NR_PHY_MSG_TYPE_RACH_INDICATION;
163 164

  uint8_t pdu_index = 0;
165 166 167 168 169
  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;
170
  rach_ind->pdu_list[pdu_index].freq_index                          = prach_pdu->num_ra;
171 172 173 174 175 176
  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));
177 178 179 180
  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;
181

182 183 184
  rach_ind->pdu_list[pdu_index].preamble_list[0].timing_advance     = 0;
  rach_ind->pdu_list[pdu_index].preamble_list[0].preamble_pwr       = 0xffffffff;

185 186
  if (!put_queue(&nr_rach_ind_queue, rach_ind))
  {
187 188 189 190
    for (int pdu_index = 0; pdu_index < rach_ind->number_of_pdus; pdu_index++)
    {
      free(rach_ind->pdu_list[pdu_index].preamble_list);
    }
191
    free(rach_ind->pdu_list);
192
    free(rach_ind);
193
  }
Melissa Elkadi's avatar
Melissa Elkadi committed
194
  LOG_D(NR_MAC, "We have successfully filled the rach_ind queue with the recently filled rach ind\n");
195 196
}

Melissa Elkadi's avatar
Melissa Elkadi committed
197 198
static bool sfn_slot_matcher(void *wanted, void *candidate)
{
199
  nfapi_p7_message_header_t *msg = candidate;
Melissa Elkadi's avatar
Melissa Elkadi committed
200 201
  int sfn_sf = *(int*)wanted;

202
  switch (msg->message_id)
Melissa Elkadi's avatar
Melissa Elkadi committed
203
  {
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
    case NFAPI_NR_PHY_MSG_TYPE_RACH_INDICATION:
    {
      nfapi_nr_rach_indication_t *ind = candidate;
      return NFAPI_SFNSLOT2SFN(sfn_sf) == ind->sfn && NFAPI_SFNSLOT2SLOT(sfn_sf) == ind->slot;
    }

    case NFAPI_NR_PHY_MSG_TYPE_RX_DATA_INDICATION:
    {
      nfapi_nr_rx_data_indication_t *ind = candidate;
      return NFAPI_SFNSLOT2SFN(sfn_sf) == ind->sfn && NFAPI_SFNSLOT2SLOT(sfn_sf) == ind->slot;
    }

    case NFAPI_NR_PHY_MSG_TYPE_CRC_INDICATION:
    {
      nfapi_nr_crc_indication_t *ind = candidate;
      return NFAPI_SFNSLOT2SFN(sfn_sf) == ind->sfn && NFAPI_SFNSLOT2SLOT(sfn_sf) == ind->slot;
    }

222 223 224 225 226 227
    case NFAPI_NR_PHY_MSG_TYPE_UCI_INDICATION:
    {
      nfapi_nr_uci_indication_t *ind = candidate;
      return NFAPI_SFNSLOT2SFN(sfn_sf) == ind->sfn && NFAPI_SFNSLOT2SLOT(sfn_sf) == ind->slot;
    }

228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
    case NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST:
    {
      nfapi_nr_dl_tti_request_t *ind = candidate;
      return NFAPI_SFNSLOT2SFN(sfn_sf) == ind->SFN && NFAPI_SFNSLOT2SLOT(sfn_sf) == ind->Slot;
    }

    case NFAPI_NR_PHY_MSG_TYPE_TX_DATA_REQUEST:
    {
      nfapi_nr_tx_data_request_t *ind = candidate;
      return NFAPI_SFNSLOT2SFN(sfn_sf) == ind->SFN && NFAPI_SFNSLOT2SLOT(sfn_sf) == ind->Slot;
    }

    case NFAPI_NR_PHY_MSG_TYPE_UL_DCI_REQUEST:
    {
      nfapi_nr_ul_dci_request_t *ind = candidate;
      return NFAPI_SFNSLOT2SFN(sfn_sf) == ind->SFN && NFAPI_SFNSLOT2SLOT(sfn_sf) == ind->Slot;
    }

    case NFAPI_NR_PHY_MSG_TYPE_UL_TTI_REQUEST:
    {
      nfapi_nr_ul_tti_request_t *ind = candidate;
      return NFAPI_SFNSLOT2SFN(sfn_sf) == ind->SFN && NFAPI_SFNSLOT2SLOT(sfn_sf) == ind->Slot;
    }

252 253 254
    default:
      LOG_E(NR_MAC, "sfn_slot_match bad ID: %d\n", msg->message_id);

Melissa Elkadi's avatar
Melissa Elkadi committed
255 256 257 258 259
  }

  return false;
}

260
static void process_queued_nr_nfapi_msgs(NR_UE_MAC_INST_t *mac, int sfn_slot)
261 262 263 264
{
  nfapi_nr_rach_indication_t *rach_ind = unqueue_matching(&nr_rach_ind_queue, MAX_QUEUE_SIZE, sfn_slot_matcher, &sfn_slot);
  nfapi_nr_rx_data_indication_t *rx_ind = unqueue_matching(&nr_rx_ind_queue, MAX_QUEUE_SIZE, sfn_slot_matcher, &sfn_slot);
  nfapi_nr_crc_indication_t *crc_ind = unqueue_matching(&nr_crc_ind_queue, MAX_QUEUE_SIZE, sfn_slot_matcher, &sfn_slot);
265 266
  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);
267

268
  LOG_D(NR_MAC, "Try to get a ul_tti_req for sfn/slot %d %d from queue with %lu items\n",
269 270
        NFAPI_SFNSLOT2SFN(mac->nr_ue_emul_l1.active_harq_sfn_slot),NFAPI_SFNSLOT2SLOT(mac->nr_ue_emul_l1.active_harq_sfn_slot), nr_ul_tti_req_queue.num_items);
  nfapi_nr_ul_tti_request_t *ul_tti_request = unqueue_matching(&nr_ul_tti_req_queue, MAX_QUEUE_SIZE, sfn_slot_matcher, &mac->nr_ue_emul_l1.active_harq_sfn_slot);
271 272 273
  if (!ul_tti_request)
  {
      LOG_D(NR_MAC, "Try to get a ul_tti_req from seprate queue because dl_tti_req was late\n");
274
      ul_tti_request = unqueue_matching(&nr_wait_ul_tti_req_queue, MAX_QUEUE_SIZE, sfn_slot_matcher, &mac->nr_ue_emul_l1.active_harq_sfn_slot);
275
  }
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308

  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++)
      {
        free(rach_ind->pdu_list[i].preamble_list);
      }
      free(rach_ind->pdu_list);
      free(rach_ind);
      nr_Msg1_transmitted(0, 0, NFAPI_SFNSLOT2SFN(sfn_slot), 0);
  }
  if (crc_ind && crc_ind->number_crcs > 0)
  {
    NR_UL_IND_t UL_INFO = {
      .crc_ind = *crc_ind,
    };
    send_nsa_standalone_msg(&UL_INFO, crc_ind->header.message_id);
    free(crc_ind->crc_list);
    free(crc_ind);
  }
  if (rx_ind && rx_ind->number_of_pdus > 0)
  {
    NR_UL_IND_t UL_INFO = {
      .rx_ind = *rx_ind,
    };
    send_nsa_standalone_msg(&UL_INFO, rx_ind->header.message_id);
    free(rx_ind->pdu_list);
    free(rx_ind);
  }
309
  if (dl_tti_request)
310
  {
311 312
    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);
313 314
    if (!tx_data_request)
    {
315 316
      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));
317 318
      if (get_softmodem_params()->nsa)
        save_nr_measurement_info(dl_tti_request);
319 320
      free(dl_tti_request);
      dl_tti_request = NULL;
321 322 323
    }
    else if (dl_tti_request->dl_tti_request_body.nPDUs > 0 && tx_data_request->Number_of_PDUs > 0)
    {
324 325
      if (get_softmodem_params()->nsa)
        save_nr_measurement_info(dl_tti_request);
326 327
      check_and_process_dci(dl_tti_request, tx_data_request, NULL, NULL);
    }
328 329 330 331 332
    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);
    }
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
  }
  if (ul_dci_request && ul_dci_request->numPdus > 0)
  {
    check_and_process_dci(NULL, NULL, ul_dci_request, NULL);
  }
  if (ul_tti_request && ul_tti_request->n_pdus > 0)
  {
    check_and_process_dci(NULL, NULL, NULL, ul_tti_request);
  }
}

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;
357 358 359 360 361 362 363
    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);
364 365 366
    if (nr_prach == 1)
    {
      L1_nsa_prach_procedures(ul_info->frame_tx, ul_info->slot_tx, prach_pdu);
367
      mac->ra.generate_nr_prach = GENERATE_PREAMBLE;
368 369 370 371 372 373 374 375 376 377 378 379 380 381
      ul_config->number_pdus = 0;
      ul_info->ue_sched_mode = SCHED_ALL;
    }
    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
382 383
static void *NRUE_phy_stub_standalone_pnf_task(void *arg)
{
384 385 386 387
  LOG_I(MAC, "Clearing Queues\n");
  reset_queue(&nr_rach_ind_queue);
  reset_queue(&nr_rx_ind_queue);
  reset_queue(&nr_crc_ind_queue);
388
  reset_queue(&nr_uci_ind_queue);
389 390 391 392
  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);
393
  reset_queue(&nr_wait_ul_tti_req_queue);
394

395 396
  NR_PRACH_RESOURCES_t prach_resources;
  memset(&prach_resources, 0, sizeof(prach_resources));
397 398
  NR_UL_TIME_ALIGNMENT_t ul_time_alignment;
  memset(&ul_time_alignment, 0, sizeof(ul_time_alignment));
Melissa Elkadi's avatar
Melissa Elkadi committed
399
  int last_sfn_slot = -1;
400
  uint16_t sfn_slot = 0;
401

Melissa Elkadi's avatar
Melissa Elkadi committed
402 403 404 405 406 407 408
  while (!oai_exit)
  {
    if (sem_wait(&sfn_slot_semaphore) != 0)
    {
      LOG_E(NR_MAC, "sem_wait() error\n");
      abort();
    }
409 410 411
    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)
412
    {
413 414
      LOG_D(MAC, "get nr_sfn_slot_queue and nr_chan_param_queue == NULL!\n");
      continue;
415 416 417 418 419 420
    }
    if (slot_ind) {
      sfn_slot = *slot_ind;
    }
    else if (ch_info) {
      sfn_slot = ch_info->sfn_slot;
421
    }
422

423 424 425
    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
426
    {
427
      LOG_D(NR_MAC, "repeated sfn_sf = %d.%d\n",
428
            frame, slot);
Melissa Elkadi's avatar
Melissa Elkadi committed
429 430
      continue;
    }
431
    last_sfn_slot = sfn_slot;
432

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

436
    module_id_t mod_id = 0;
437
    NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
438
    if (get_softmodem_params()->sa && mac->mib == NULL)
439
    {
440 441 442
      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);
443
    }
444
    if (mac->scc == NULL && mac->scc_SIB == NULL)
445 446
    {
      LOG_D(MAC, "[NSA] mac->scc == NULL and [SA] mac->scc_SIB == NULL!\n");
447 448 449
      continue;
    }

450
    mac->ra.generate_nr_prach = 0;
451 452
    int CC_id = 0;
    uint8_t gNB_id = 0;
453
    nr_uplink_indication_t ul_info;
454
    int slots_per_frame = 20; //30 kHZ subcarrier spacing
Melissa Elkadi's avatar
Melissa Elkadi committed
455
    int slot_ahead = 2; // TODO: Make this dynamic
456 457 458
    ul_info.cc_id = CC_id;
    ul_info.gNB_index = gNB_id;
    ul_info.module_id = mod_id;
459 460
    ul_info.frame_rx = frame;
    ul_info.slot_rx = slot;
461 462
    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;
463
    ul_info.ue_sched_mode = SCHED_ALL;
464

465
    if (pthread_mutex_lock(&mac->mutex_dl_info)) abort();
466

467 468 469 470 471 472 473 474 475 476
    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.thread_id = 0;
    mac->dl_info.dci_ind = NULL;
    mac->dl_info.rx_ind = NULL;

477 478 479 480
    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))
481 482 483
    {
      nr_ue_dl_indication(&mac->dl_info, &ul_time_alignment);
    }
484 485 486

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

487 488 489 490
    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))
491 492
    {
      LOG_D(NR_MAC, "Slot %d. calling nr_ue_ul_ind() from %s\n", ul_info.slot_tx, __FUNCTION__);
493
      nr_ue_ul_indication(&ul_info);
494
      check_nr_prach(mac, &ul_info, &prach_resources);
495
    }
496 497 498 499 500
    process_queued_nr_nfapi_msgs(mac, sfn_slot);
    free(slot_ind);
    slot_ind = NULL;
    free(ch_info);
    ch_info = NULL;
Melissa Elkadi's avatar
Melissa Elkadi committed
501
  }
502
  return NULL;
Melissa Elkadi's avatar
Melissa Elkadi committed
503
}
504

505

laurent's avatar
laurent committed
506 507 508 509 510
/*!
 * 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
511
typedef nr_rxtx_thread_data_t syncData_t;
laurent's avatar
laurent committed
512 513 514 515 516 517

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;
518
  //int CC_id = UE->CC_id;
519
  static int freq_offset=0;
laurent's avatar
laurent committed
520 521 522 523 524 525
  UE->is_synchronized = 0;

  if (UE->UE_scan == 0) {

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

526
      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",
527 528 529 530 531 532 533
        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
534 535 536 537
    }

    sync_mode = pbch;
  } else {
538 539
    LOG_E(PHY,"Fixme!\n");
    /*
laurent's avatar
laurent committed
540 541 542 543 544 545 546 547 548
    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;
    }
549
    */
laurent's avatar
laurent committed
550 551 552 553 554
  }

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

  switch (sync_mode) {
555
    /*
laurent's avatar
laurent committed
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
    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;
584
    */
laurent's avatar
laurent committed
585 586 587
    case pbch:
      LOG_I(PHY, "[UE thread Synch] Running Initial Synch (mode %d)\n",UE->mode);

588
      uint64_t dl_carrier, ul_carrier;
589
      nr_get_carrier_frequencies(UE, &dl_carrier, &ul_carrier);
590

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

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

600
        LOG_I(PHY,"Got synch: hw_slot_offset %d, carrier off %d Hz, rxgain %f (DL %f Hz, UL %f Hz)\n",
601 602
              hw_slot_offset,
              freq_offset,
603
              openair0_cfg[UE->rf_map.card].rx_gain[0],
604
              openair0_cfg[UE->rf_map.card].rx_freq[0],
605
              openair0_cfg[UE->rf_map.card].tx_freq[0]);
606

laurent's avatar
laurent committed
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623
        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 {
624

625
        if (UE->UE_scan_carrier == 1) {
626

laurent's avatar
laurent committed
627 628 629 630
          if (freq_offset >= 0)
            freq_offset += 100;

          freq_offset *= -1;
631

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

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

          if (UE->mode != loop_through_memory)
            UE->rfdevice.trx_set_freq_func(&UE->rfdevice,&openair0_cfg[0],0);
638
        }
laurent's avatar
laurent committed
639 640 641 642 643 644 645 646 647 648

        break;

      case si:
      default:
        break;
      }
  }
}

Sakthivel Velumani's avatar
Sakthivel Velumani committed
649 650
void processSlotTX(void *arg) {

651
  nr_rxtx_thread_data_t *rxtxD = (nr_rxtx_thread_data_t *) arg;
Sakthivel Velumani's avatar
Sakthivel Velumani committed
652 653
  UE_nr_rxtx_proc_t *proc = &rxtxD->proc;
  PHY_VARS_NR_UE    *UE   = rxtxD->UE;
654
  fapi_nr_config_request_t *cfg = &UE->nrUE_config;
655
  int tx_slot_type = nr_ue_slot_select(cfg, proc->frame_tx, proc->nr_slot_tx);
656
  uint8_t gNB_id = 0;
657

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

661 662 663 664 665 666 667 668 669 670
    // 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;
671
      ul_indication.slot_rx   = proc->nr_slot_rx;
672
      ul_indication.frame_tx  = proc->frame_tx;
673 674
      ul_indication.slot_tx   = proc->nr_slot_tx;
      ul_indication.thread_id = proc->thread_id;
675
      ul_indication.ue_sched_mode = rxtxD->ue_sched_mode;
Florian Kaltenberger's avatar
Florian Kaltenberger committed
676

677 678
      UE->if_inst->ul_indication(&ul_indication);
    }
679

Sakthivel Velumani's avatar
Sakthivel Velumani committed
680
    if ((UE->mode != loop_through_memory) && (rxtxD->ue_sched_mode != NOT_PUSCH)) {
681
      phy_procedures_nrUE_TX(UE,proc,0);
Florian Kaltenberger's avatar
Florian Kaltenberger committed
682 683 684 685
    }
  }
}

Sakthivel Velumani's avatar
Sakthivel Velumani committed
686
void processSlotRX(void *arg) {
Florian Kaltenberger's avatar
Florian Kaltenberger committed
687

688
  nr_rxtx_thread_data_t *rxtxD = (nr_rxtx_thread_data_t *) arg;
Sakthivel Velumani's avatar
Sakthivel Velumani committed
689 690
  UE_nr_rxtx_proc_t *proc = &rxtxD->proc;
  PHY_VARS_NR_UE    *UE   = rxtxD->UE;
691
  fapi_nr_config_request_t *cfg = &UE->nrUE_config;
692
  int rx_slot_type = nr_ue_slot_select(cfg, proc->frame_rx, proc->nr_slot_rx);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
693
  int tx_slot_type = nr_ue_slot_select(cfg, proc->frame_tx, proc->nr_slot_tx);
cig's avatar
cig committed
694
  uint8_t gNB_id = 0;
Florian Kaltenberger's avatar
Florian Kaltenberger committed
695

696
  if (rx_slot_type == NR_DOWNLINK_SLOT || rx_slot_type == NR_MIXED_SLOT){
Florian Kaltenberger's avatar
Florian Kaltenberger committed
697

cig's avatar
cig committed
698
    if(UE->if_inst != NULL && UE->if_inst->dl_indication != NULL) {
699
      nr_downlink_indication_t dl_indication;
cig's avatar
cig committed
700
      nr_fill_dl_indication(&dl_indication, NULL, NULL, proc, UE, gNB_id);
701 702
      UE->if_inst->dl_indication(&dl_indication, NULL);
    }
703

Florian Kaltenberger's avatar
Florian Kaltenberger committed
704
  // Process Rx data for one sub-frame
laurent's avatar
laurent committed
705
#ifdef UE_SLOT_PARALLELISATION
cig's avatar
cig committed
706
    phy_procedures_slot_parallelization_nrUE_RX( UE, proc, 0, 0, 1, no_relay, NULL );
laurent's avatar
laurent committed
707
#else
laurent's avatar
laurent committed
708
    uint64_t a=rdtsc();
709
    phy_procedures_nrUE_RX(UE, proc, gNB_id, get_nrUE_params()->nr_dlsch_parallel, &rxtxD->txFifo);
cig's avatar
cig committed
710
    LOG_D(PHY, "In %s: slot %d, time %lu\n", __FUNCTION__, proc->nr_slot_rx, (rdtsc()-a)/3500);
laurent's avatar
laurent committed
711
#endif
Raymond Knopp's avatar
Raymond Knopp committed
712

713
    if(IS_SOFTMODEM_NOS1 || get_softmodem_params()->sa){
cig's avatar
cig committed
714
      NR_UE_MAC_INST_t *mac = get_mac_inst(0);
Florian Kaltenberger's avatar
Florian Kaltenberger committed
715
      protocol_ctxt_t ctxt;
cig's avatar
cig committed
716
      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
717
      pdcp_run(&ctxt);
718 719 720 721 722 723 724 725

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

731
    // Wait for PUSCH processing to finish
732 733 734
    notifiedFIFO_elt_t *res;
    res = pullTpool(&rxtxD->txFifo,&(get_nrUE_params()->Tpool));
    delNotifiedFIFO_elt(res);
laurent's avatar
laurent committed
735

736
  } else {
737
    rxtxD->ue_sched_mode = SCHED_ALL;
738
    processSlotTX(rxtxD);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
739
  }
laurent's avatar
laurent committed
740

Sakthivel Velumani's avatar
Sakthivel Velumani committed
741
  if (tx_slot_type == NR_UPLINK_SLOT || tx_slot_type == NR_MIXED_SLOT){
Sakthivel Velumani's avatar
Sakthivel Velumani committed
742 743 744 745
    if (UE->UE_mode[gNB_id] <= PUSCH) {
      if (get_softmodem_params()->usim_test==0) {
        pucch_procedures_ue_nr(UE,
                               gNB_id,
746
                               proc);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
747
      }
laurent's avatar
laurent committed
748

Sakthivel Velumani's avatar
Sakthivel Velumani committed
749 750 751 752 753
      LOG_D(PHY, "Sending Uplink data \n");
      nr_ue_pusch_common_procedures(UE,
                                    proc->nr_slot_tx,
                                    &UE->frame_parms,1);
    }
laurent's avatar
laurent committed
754

Sakthivel Velumani's avatar
Sakthivel Velumani committed
755 756 757 758
    if (UE->UE_mode[gNB_id] > NOT_SYNCHED && UE->UE_mode[gNB_id] < PUSCH) {
      nr_ue_prach_procedures(UE, proc, gNB_id);
    }
    LOG_D(PHY,"****** end TX-Chain for AbsSubframe %d.%d ******\n", proc->frame_tx, proc->nr_slot_tx);
759
  }
760

Sakthivel Velumani's avatar
Sakthivel Velumani committed
761
  ue_ta_procedures(UE, proc->nr_slot_tx, proc->frame_tx);
laurent's avatar
laurent committed
762 763
}

764
void dummyWrite(PHY_VARS_NR_UE *UE,openair0_timestamp timestamp, int writeBlockSize) {
laurent's avatar
laurent committed
765 766 767
  void *dummy_tx[UE->frame_parms.nb_antennas_tx];

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

770 771 772 773 774 775 776
  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
777 778 779 780 781

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

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

784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808
  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]);
809
    }
laurent's avatar
laurent committed
810 811 812 813 814
  }

}

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

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

Sakthivel Velumani's avatar
Sakthivel Velumani committed
818
    *timestamp += UE->frame_parms.get_samples_per_slot(1,&UE->frame_parms);
laurent's avatar
laurent committed
819 820
    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
821 822 823
      // 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
824 825 826 827 828 829
      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
830
      *timestamp += unitTransfer; // this does not affect the read but needed for RFSIM write
laurent's avatar
laurent committed
831 832 833 834 835 836 837
    }

}

int computeSamplesShift(PHY_VARS_NR_UE *UE) {

  // compute TO compensation that should be applied for this frame
838 839
  if ( UE->rx_offset < UE->frame_parms.samples_per_frame/2  &&
       UE->rx_offset > 0 ) {
840
    LOG_I(PHY,"!!!adjusting -1 samples!!! rx_offset == %d\n", UE->rx_offset);
841 842
    UE->rx_offset   = 0; // reset so that it is not applied falsely in case of SSB being only in every second frame
    UE->max_pos_fil = 0; // reset IIR filter when sample shift is applied
laurent's avatar
laurent committed
843
    return -1 ;
844
  }
laurent's avatar
laurent committed
845

846 847
  if ( UE->rx_offset > UE->frame_parms.samples_per_frame/2 &&
       UE->rx_offset < UE->frame_parms.samples_per_frame ) {
848 849
    int rx_offset = UE->rx_offset - UE->frame_parms.samples_per_frame;
    LOG_I(PHY,"!!!adjusting +1 samples!!! rx_offset == %d\n", rx_offset);
850 851
    UE->rx_offset   = 0; // reset so that it is not applied falsely in case of SSB being only in every second frame
    UE->max_pos_fil = 0; // reset IIR filter when sample shift is applied
laurent's avatar
laurent committed
852
    return 1;
853
  }
laurent's avatar
laurent committed
854

laurent's avatar
laurent committed
855 856 857
  return 0;
}

858
static inline int get_firstSymSamp(uint16_t slot, NR_DL_FRAME_PARMS *fp) {
Sakthivel Velumani's avatar
Sakthivel Velumani committed
859 860 861 862 863 864 865
  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;
}

866
static inline int get_readBlockSize(uint16_t slot, NR_DL_FRAME_PARMS *fp) {
Sakthivel Velumani's avatar
Sakthivel Velumani committed
867 868 869 870 871 872 873
  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
874
void *UE_thread(void *arg) {
laurent's avatar
laurent committed
875
  //this thread should be over the processing thread to keep in real time
laurent's avatar
laurent committed
876 877
  PHY_VARS_NR_UE *UE = (PHY_VARS_NR_UE *) arg;
  //  int tx_enabled = 0;
878
  openair0_timestamp timestamp, writeTimestamp;
laurent's avatar
laurent committed
879 880 881 882
  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;
883 884
  UE->lost_sync = 0;
  UE->is_synchronized = 0;
laurent's avatar
laurent committed
885
  AssertFatal(UE->rfdevice.trx_start_func(&UE->rfdevice) == 0, "Could not start the device\n");
Sakthivel Velumani's avatar
Sakthivel Velumani committed
886

laurent's avatar
laurent committed
887 888
  notifiedFIFO_t nf;
  initNotifiedFIFO(&nf);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
889

890 891
  notifiedFIFO_t freeBlocks;
  initNotifiedFIFO_nothreadSafe(&freeBlocks);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
892

893
  int nbSlotProcessing=0;
laurent's avatar
laurent committed
894
  int thread_idx=0;
895
  NR_UE_MAC_INST_t *mac = get_mac_inst(0);
896
  int timing_advance = UE->timing_advance;
laurent's avatar
laurent committed
897

laurent's avatar
fixes  
laurent committed
898
  bool syncRunning=false;
899
  const int nb_slot_frame = UE->frame_parms.slots_per_frame;
900
  int absolute_slot=0, decoded_frame_rx=INT_MAX, trashed_frames=0;
laurent's avatar
laurent committed
901

902
  for (int i=0; i<NR_RX_NB_TH+1; i++) {// NR_RX_NB_TH working + 1 we are making to be pushed
903 904 905 906
    notifiedFIFO_elt_t *newElt = newNotifiedFIFO_elt(sizeof(nr_rxtx_thread_data_t), RX_JOB_ID,&nf,processSlotRX);
    nr_rxtx_thread_data_t *curMsg=(nr_rxtx_thread_data_t *)NotifiedFifoData(newElt);
    initNotifiedFIFO(&curMsg->txFifo);
    pushNotifiedFIFO_nothreadSafe(&freeBlocks, newElt);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
907 908
  }

laurent's avatar
laurent committed
909
  while (!oai_exit) {
910
    if (UE->lost_sync) {
911 912 913
      int nb = abortTpool(&(get_nrUE_params()->Tpool),RX_JOB_ID);
      nb += abortNotifiedFIFO(&nf, RX_JOB_ID);
      LOG_I(PHY,"Number of aborted slots %d\n",nb);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
914
      for (int i=0; i<nb; i++)
915 916
        pushNotifiedFIFO_nothreadSafe(&freeBlocks, newNotifiedFIFO_elt(sizeof(nr_rxtx_thread_data_t), RX_JOB_ID,&nf,processSlotRX));
      nbSlotProcessing = 0;
917 918 919 920
      UE->is_synchronized = 0;
      UE->lost_sync = 0;
    }

921
    if (syncRunning) {
922
      notifiedFIFO_elt_t *res=tryPullTpool(&nf,&(get_nrUE_params()->Tpool));
923 924 925 926

      if (res) {
        syncRunning=false;
        syncData_t *tmp=(syncData_t *)NotifiedFifoData(res);
927 928 929
        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
930
          decoded_frame_rx=(decoded_frame_rx + UE->init_sync_frame + trashed_frames) % MAX_FRAME_NUMBER;
931
        }
932
        delNotifiedFIFO_elt(res);
933
        start_rx_stream=0;
laurent's avatar
laurent committed
934
      } else {
935
        readFrame(UE, &timestamp, true);
936
        trashed_frames+=2;
937
        continue;
laurent's avatar
laurent committed
938
      }
939
    }
laurent's avatar
laurent committed
940

941
    AssertFatal( !syncRunning, "At this point synchronization can't be running\n");
942 943

    if (!UE->is_synchronized) {
944
      readFrame(UE, &timestamp, false);
945 946 947 948
      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));
949
      pushTpool(&(get_nrUE_params()->Tpool), Msg);
950 951
      trashed_frames=0;
      syncRunning=true;
laurent's avatar
laurent committed
952 953 954 955 956 957 958 959 960 961 962 963 964 965 966
      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
967 968
      // we have the decoded frame index in the return of the synch process
      // and we shifted above to the first slot of next frame
969
      decoded_frame_rx++;
970
      // we do ++ first in the regular processing, so it will be begin of frame;
971
      absolute_slot=decoded_frame_rx*nb_slot_frame -1;
laurent's avatar
laurent committed
972 973 974
      continue;
    }

975

laurent's avatar
laurent committed
976
    absolute_slot++;
977

978 979
    // whatever means thread_idx
    // Fix me: will be wrong when slot 1 is slow, as slot 2 finishes
980
    // Slot 3 will overlap if NR_RX_NB_TH is 2
981
    // this is general failure in UE !!!
982
    thread_idx = absolute_slot % NR_RX_NB_TH;
laurent's avatar
fixes  
laurent committed
983
    int slot_nr = absolute_slot % nb_slot_frame;
984 985
    notifiedFIFO_elt_t *msgToPush;
    AssertFatal((msgToPush=pullNotifiedFIFO_nothreadSafe(&freeBlocks)) != NULL,"chained list failure");
986
    nr_rxtx_thread_data_t *curMsg=(nr_rxtx_thread_data_t *)NotifiedFifoData(msgToPush);
987
    curMsg->UE=UE;
laurent's avatar
laurent committed
988
    // update thread index for received subframe
989 990 991 992 993 994
    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;
995
    curMsg->proc.decoded_frame_rx=-1;
Hongzhi Wang's avatar
Hongzhi Wang committed
996 997 998
    //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
999
    /*uint32_t total_gain_dB_prev = 0;
Hongzhi Wang's avatar
Hongzhi Wang committed
1000
    if (total_gain_dB_prev != UE->rx_total_gain_dB) {
Thomas Schlichter's avatar
Thomas Schlichter committed
1001
        total_gain_dB_prev = UE->rx_total_gain_dB;
Hongzhi Wang's avatar
Hongzhi Wang committed
1002
        openair0_cfg[0].rx_gain[0] = UE->rx_total_gain_dB;
Hongzhi Wang's avatar
Hongzhi Wang committed
1003
        UE->rfdevice.trx_set_gains_func(&UE->rfdevice,&openair0_cfg[0]);
Hongzhi Wang's avatar
Hongzhi Wang committed
1004
    }*/
Hongzhi Wang's avatar
Hongzhi Wang committed
1005
#endif
laurent's avatar
laurent committed
1006

Sakthivel Velumani's avatar
Sakthivel Velumani committed
1007
    int firstSymSamp = get_firstSymSamp(slot_nr, &UE->frame_parms);
laurent's avatar
laurent committed
1008
    for (int i=0; i<UE->frame_parms.nb_antennas_rx; i++)
Sakthivel Velumani's avatar
Sakthivel Velumani committed
1009
      rxp[i] = (void *)&UE->common_vars.rxdata[i][firstSymSamp+
1010
               UE->frame_parms.get_samples_slot_timestamp(slot_nr,&UE->frame_parms,0)];
laurent's avatar
laurent committed
1011 1012

    for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
1013
      txp[i] = (void *)&UE->common_vars.txdata[i][UE->frame_parms.get_samples_slot_timestamp(
1014
               ((slot_nr + DURATION_RX_TO_TX - NR_RX_NB_TH)%nb_slot_frame),&UE->frame_parms,0)];
laurent's avatar
laurent committed
1015 1016 1017 1018

    int readBlockSize, writeBlockSize;

    if (slot_nr<(nb_slot_frame - 1)) {
Sakthivel Velumani's avatar
Sakthivel Velumani committed
1019
      readBlockSize=get_readBlockSize(slot_nr, &UE->frame_parms);
1020
      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
1021 1022
    } else {
      UE->rx_offset_diff = computeSamplesShift(UE);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
1023
      readBlockSize=get_readBlockSize(slot_nr, &UE->frame_parms) -
laurent's avatar
laurent committed
1024
                    UE->rx_offset_diff;
1025
      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
1026 1027 1028 1029 1030 1031 1032 1033
    }

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

laurent's avatar
laurent committed
1035 1036
    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
1037
      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
1038

1039 1040
      if ( first_symbols > 0 ) {
        openair0_timestamp ignore_timestamp;
laurent's avatar
laurent committed
1041 1042
        AssertFatal(first_symbols ==
                    UE->rfdevice.trx_read_func(&UE->rfdevice,
1043
                                               &ignore_timestamp,
laurent's avatar
laurent committed
1044 1045 1046
                                               (void **)UE->common_vars.rxdata,
                                               first_symbols,
                                               UE->frame_parms.nb_antennas_rx),"");
1047
      } else
laurent's avatar
laurent committed
1048 1049 1050
        LOG_E(PHY,"can't compensate: diff =%d\n", first_symbols);
    }

1051
    curMsg->proc.timestamp_tx = timestamp+
1052
      UE->frame_parms.get_samples_slot_timestamp(slot_nr,&UE->frame_parms,DURATION_RX_TO_TX) 
1053
      - firstSymSamp;
Sakthivel Velumani's avatar
Sakthivel Velumani committed
1054

laurent's avatar
fixes  
laurent committed
1055
    notifiedFIFO_elt_t *res;
laurent's avatar
laurent committed
1056

1057
    while (nbSlotProcessing >= NR_RX_NB_TH) {
1058
      res=pullTpool(&nf, &(get_nrUE_params()->Tpool));
1059
      nbSlotProcessing--;
Sakthivel Velumani's avatar
Sakthivel Velumani committed
1060
      nr_rxtx_thread_data_t *tmp=(nr_rxtx_thread_data_t *)res->msgData;
laurent's avatar
fixes  
laurent committed
1061

1062 1063
      if (tmp->proc.decoded_frame_rx != -1)
        decoded_frame_rx=(((mac->mib->systemFrameNumber.buf[0] >> mac->mib->systemFrameNumber.bits_unused)<<4) | tmp->proc.decoded_frame_rx);
Sakthivel Velumani's avatar
Sakthivel Velumani committed
1064
      else
Laurent's avatar
Laurent committed
1065
         decoded_frame_rx=-1;
laurent's avatar
laurent committed
1066

1067
      pushNotifiedFIFO_nothreadSafe(&freeBlocks,res);
laurent's avatar
laurent committed
1068 1069
    }

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

1074
    // use previous timing_advance value to compute writeTimestamp
1075 1076
    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
1077
      - NR_RX_NB_TH) - firstSymSamp - openair0_cfg[0].tx_sample_advance -
1078
      UE->N_TA_offset - timing_advance;
1079 1080 1081 1082 1083 1084 1085

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

1086
    int flags = 0;
1087
    int slot_tx_usrp = slot_nr + DURATION_RX_TO_TX - NR_RX_NB_TH;
1088

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

1091 1092
      uint8_t tdd_period = mac->phy_config.config_req.tdd_table.tdd_period_in_slots;
      int nrofUplinkSlots, nrofUplinkSymbols;
francescomani's avatar
francescomani committed
1093 1094 1095 1096 1097 1098 1099 1100 1101
      if (mac->scc) {
        nrofUplinkSlots = mac->scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots;
        nrofUplinkSymbols = mac->scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols;
      }
      else {
        nrofUplinkSlots = mac->scc_SIB->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots;
        nrofUplinkSymbols = mac->scc_SIB->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols;
      }
      uint8_t  num_UL_slots = nrofUplinkSlots + (nrofUplinkSymbols != 0);
1102

cig's avatar
cig committed
1103 1104
      uint8_t first_tx_slot = tdd_period - num_UL_slots;

1105 1106 1107 1108 1109 1110 1111
      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 {
1112
      flags = 1;
1113
    }
1114 1115

    if (flags || IS_SOFTMODEM_RFSIM)
1116 1117 1118 1119 1120 1121 1122
      AssertFatal(writeBlockSize ==
                  UE->rfdevice.trx_write_func(&UE->rfdevice,
                                              writeTimestamp,
                                              txp,
                                              writeBlockSize,
                                              UE->frame_parms.nb_antennas_tx,
                                              flags),"");
1123
    
1124 1125 1126
    for (int i=0; i<UE->frame_parms.nb_antennas_tx; i++)
      memset(txp[i], 0, writeBlockSize);

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

laurent's avatar
laurent committed
1131 1132 1133 1134 1135
  } // while !oai_exit

  return NULL;
}

1136
void init_NR_UE(int nb_inst, char* rrc_config_path) {
laurent's avatar
laurent committed
1137 1138
  int inst;
  NR_UE_MAC_INST_t *mac_inst;
Florian Kaltenberger's avatar
Florian Kaltenberger committed
1139 1140
  NR_UE_RRC_INST_t* rrc_inst;
  
laurent's avatar
laurent committed
1141
  for (inst=0; inst < nb_inst; inst++) {
Florian Kaltenberger's avatar
Florian Kaltenberger committed
1142 1143 1144
    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");
1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155
  }
}

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

1159
     if(get_nrUE_params()->nr_dlsch_parallel)
1160 1161 1162 1163
     {
       pthread_t dlsch0_threads;
       threadCreate(&dlsch0_threads, dlsch_thread, (void *)UE, "DLthread", -1, OAI_PRIORITY_RT_MAX-1);
     }
laurent's avatar
laurent committed
1164 1165 1166
  }
}

1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177
/* 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();
}

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