flexran_agent_ran_api.c 101 KB
Newer Older
1 2 3 4 5
/*
 * 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
6
 * the OAI Public License, Version 1.1  (the "License"); you may not use this file
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 * 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
 */ 

/*! \file flexran_agent_ran_api.c
 * \brief FlexRAN RAN API abstraction 
Robert Schmidt's avatar
Robert Schmidt committed
24
 * \author N. Nikaein, X. Foukas, S. SHARIAT BAGHERI and R. Schmidt
25 26 27 28
 * \date 2017
 * \version 0.1
 */

29
#include <dlfcn.h>
30 31
#include "flexran_agent_ran_api.h"

32 33 34 35
static inline int phy_is_present(mid_t mod_id, uint8_t cc_id)
{
  return RC.eNB && RC.eNB[mod_id] && RC.eNB[mod_id][cc_id];
}
36

37 38 39 40 41 42 43 44
static inline int mac_is_present(mid_t mod_id)
{
  return RC.mac && RC.mac[mod_id];
}

static inline int rrc_is_present(mid_t mod_id)
{
  return RC.rrc && RC.rrc[mod_id];
45
}
46

Robert Schmidt's avatar
Robert Schmidt committed
47
uint32_t flexran_get_current_time_ms(mid_t mod_id, int subframe_flag)
48
{
49
  if (!mac_is_present(mod_id)) return 0;
Robert Schmidt's avatar
Robert Schmidt committed
50
  if (subframe_flag == 1)
51
    return RC.mac[mod_id]->frame*10 + RC.mac[mod_id]->subframe;
Robert Schmidt's avatar
Robert Schmidt committed
52
  else
53
    return RC.mac[mod_id]->frame*10;
54 55
}

Robert Schmidt's avatar
Robert Schmidt committed
56 57
frame_t flexran_get_current_frame(mid_t mod_id)
{
58
  if (!mac_is_present(mod_id)) return 0;
59
  //  #warning "SFN will not be in [0-1023] when oaisim is used"
60
  return RC.mac[mod_id]->frame;
61 62
}

Robert Schmidt's avatar
Robert Schmidt committed
63 64 65
frame_t flexran_get_current_system_frame_num(mid_t mod_id)
{
  return flexran_get_current_frame(mod_id) % 1024;
66 67
}

Robert Schmidt's avatar
Robert Schmidt committed
68 69
sub_frame_t flexran_get_current_subframe(mid_t mod_id)
{
70 71
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->subframe;
72 73
}

74
uint32_t flexran_get_sfn_sf(mid_t mod_id)
Robert Schmidt's avatar
Robert Schmidt committed
75
{
76
  if (!mac_is_present(mod_id)) return 0;
77
  return flexran_get_current_frame(mod_id) * 10 + flexran_get_current_subframe(mod_id);
78 79
}

Robert Schmidt's avatar
Robert Schmidt committed
80 81
uint16_t flexran_get_future_sfn_sf(mid_t mod_id, int ahead_of_time)
{
82
  if (!mac_is_present(mod_id)) return 0;
Robert Schmidt's avatar
Robert Schmidt committed
83 84
  frame_t frame = flexran_get_current_system_frame_num(mod_id);
  sub_frame_t subframe = flexran_get_current_subframe(mod_id);
85
  uint16_t sfn_sf, frame_mask, sf_mask;
Robert Schmidt's avatar
Robert Schmidt committed
86
  int additional_frames;
87

Robert Schmidt's avatar
Robert Schmidt committed
88 89 90
  subframe = (subframe + ahead_of_time) % 10;

  if (subframe < flexran_get_current_subframe(mod_id))
91
    frame = (frame + 1) % 1024;
Robert Schmidt's avatar
Robert Schmidt committed
92 93

  additional_frames = ahead_of_time / 10;
94
  frame = (frame + additional_frames) % 1024;
Robert Schmidt's avatar
Robert Schmidt committed
95 96 97

  frame_mask = (1 << 12) - 1;
  sf_mask = (1 << 4) - 1;
98
  sfn_sf = (subframe & sf_mask) | ((frame & frame_mask) << 4);
Robert Schmidt's avatar
Robert Schmidt committed
99

100 101 102
  return sfn_sf;
}

103
int flexran_get_mac_num_ues(mid_t mod_id)
Robert Schmidt's avatar
Robert Schmidt committed
104
{
105 106
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.num_UEs;
107 108
}

109 110 111 112
int flexran_get_num_ue_lcs(mid_t mod_id, mid_t ue_id)
{
  if (!mac_is_present(mod_id)) return 0;
  // Not sure whether this is needed: if (!rrc_is_present(mod_id)) return 0;
113
  const rnti_t rnti = flexran_get_mac_ue_crnti(mod_id, ue_id);
114 115 116 117 118 119 120 121 122
  const int s = mac_eNB_get_rrc_status(mod_id, rnti);
  if (s < RRC_CONNECTED)
    return 0;
  else if (s == RRC_CONNECTED)
    return 1;
  else
    return 3;
}

123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
int flexran_get_mac_ue_id_rnti(mid_t mod_id, rnti_t rnti)
{
  int n;
  if (!mac_is_present(mod_id)) return 0;
  /* get the (active) UE with RNTI i */
  for (n = 0; n < MAX_MOBILES_PER_ENB; ++n) {
    if (RC.mac[mod_id]->UE_list.active[n] == TRUE
        && rnti == UE_RNTI(mod_id, n)) {
      return n;
    }
  }
  return 0;

}

138
int flexran_get_mac_ue_id(mid_t mod_id, int i)
139 140 141 142 143 144 145 146 147 148 149 150 151 152
{
  int n;
  if (!mac_is_present(mod_id)) return 0;
  /* get the (i+1)'th active UE */
  for (n = 0; n < MAX_MOBILES_PER_ENB; ++n) {
    if (RC.mac[mod_id]->UE_list.active[n] == TRUE) {
      if (i == 0)
        return n;
      --i;
    }
  }
  return 0;
}

153
rnti_t flexran_get_mac_ue_crnti(mid_t mod_id, mid_t ue_id)
Robert Schmidt's avatar
Robert Schmidt committed
154
{
155
  if (!mac_is_present(mod_id)) return 0;
Robert Schmidt's avatar
Robert Schmidt committed
156
  return UE_RNTI(mod_id, ue_id);
157 158
}

159
int flexran_get_ue_bsr_ul_buffer_info(mid_t mod_id, mid_t ue_id, lcid_t lcid)
Robert Schmidt's avatar
Robert Schmidt committed
160
{
161 162
  if (!mac_is_present(mod_id)) return -1;
  return RC.mac[mod_id]->UE_list.UE_template[UE_PCCID(mod_id, ue_id)][ue_id].ul_buffer_info[lcid];
163 164
}

Robert Schmidt's avatar
Robert Schmidt committed
165 166
int8_t flexran_get_ue_phr(mid_t mod_id, mid_t ue_id)
{
167 168
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.UE_template[UE_PCCID(mod_id, ue_id)][ue_id].phr_info;
169 170
}

Robert Schmidt's avatar
Robert Schmidt committed
171 172
uint8_t flexran_get_ue_wcqi(mid_t mod_id, mid_t ue_id)
{
173
  if (!mac_is_present(mod_id)) return 0;
174
  return RC.mac[mod_id]->UE_list.UE_sched_ctrl[ue_id].dl_cqi[0];
175 176
}

Robert Schmidt's avatar
Robert Schmidt committed
177 178
rlc_buffer_occupancy_t flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id)
{
179
  if (!mac_is_present(mod_id)) return 0;
180
  rnti_t rnti = flexran_get_mac_ue_crnti(mod_id, ue_id);
Robert Schmidt's avatar
Robert Schmidt committed
181 182
  frame_t frame = flexran_get_current_frame(mod_id);
  sub_frame_t subframe = flexran_get_current_subframe(mod_id);
183
  mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id,rnti, mod_id, frame, subframe, ENB_FLAG_YES,MBMS_FLAG_NO, channel_id, 0
184
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
185 186 187
                                                    ,0, 0
#endif
                                                    );
188
  return rlc_status.bytes_in_buffer;
189 190
}

Robert Schmidt's avatar
Robert Schmidt committed
191 192
rlc_buffer_occupancy_t flexran_get_num_pdus_buffer(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id)
{
193
  if (!mac_is_present(mod_id)) return 0;
194
  rnti_t rnti = flexran_get_mac_ue_crnti(mod_id,ue_id);
Robert Schmidt's avatar
Robert Schmidt committed
195 196
  frame_t frame = flexran_get_current_frame(mod_id);
  sub_frame_t subframe = flexran_get_current_subframe(mod_id);
197
  mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id,rnti, mod_id, frame, subframe, ENB_FLAG_YES,MBMS_FLAG_NO, channel_id, 0
198
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
199 200 201
                                                    ,0, 0
#endif
                                                    );
202 203 204
  return rlc_status.pdus_in_buffer;
}

Robert Schmidt's avatar
Robert Schmidt committed
205 206
frame_t flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id)
{
207
  if (!mac_is_present(mod_id)) return 0;
208
  rnti_t rnti = flexran_get_mac_ue_crnti(mod_id,ue_id);
Robert Schmidt's avatar
Robert Schmidt committed
209 210
  frame_t frame = flexran_get_current_frame(mod_id);
  sub_frame_t subframe = flexran_get_current_subframe(mod_id);
211
  mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id, rnti, mod_id, frame, subframe, ENB_FLAG_YES, MBMS_FLAG_NO, channel_id, 0
212
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
213 214 215
                                                    ,0, 0
#endif
                                                    );
216 217 218
  return rlc_status.head_sdu_creation_time;
}

Robert Schmidt's avatar
Robert Schmidt committed
219 220
int32_t flexran_get_TA(mid_t mod_id, mid_t ue_id, uint8_t cc_id)
{
221
  if (!phy_is_present(mod_id, cc_id)) return 0;
222

223
  int32_t tau = RC.eNB[mod_id][cc_id]->UE_stats[ue_id].timing_advance_update;
Robert Schmidt's avatar
Robert Schmidt committed
224
  switch (flexran_get_N_RB_DL(mod_id, cc_id)) {
225
  case 6:
Robert Schmidt's avatar
Robert Schmidt committed
226
    return tau;
227
  case 15:
Robert Schmidt's avatar
Robert Schmidt committed
228
    return tau / 2;
229
  case 25:
Robert Schmidt's avatar
Robert Schmidt committed
230
    return tau / 4;
231
  case 50:
Robert Schmidt's avatar
Robert Schmidt committed
232
    return tau / 8;
233
  case 75:
Robert Schmidt's avatar
Robert Schmidt committed
234
    return tau / 12;
235
  case 100:
Robert Schmidt's avatar
Robert Schmidt committed
236 237 238 239
    if (flexran_get_threequarter_fs(mod_id, cc_id) == 0)
      return tau / 16;
    else
      return tau / 12;
240 241 242 243 244
  default:
    return 0;
  }
}

245 246
uint32_t flexran_get_total_size_dl_mac_sdus(mid_t mod_id, mid_t ue_id, int cc_id)
{
247 248 249 250
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_sdu_bytes;
}

251 252 253
uint32_t flexran_get_total_size_ul_mac_sdus(mid_t mod_id, mid_t ue_id, int cc_id)
{
  if (!mac_is_present(mod_id)) return 0;
254 255 256 257 258
  uint64_t bytes = 0;
  for (int i = 0; i < NB_RB_MAX; ++i) {
    bytes += RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].num_bytes_rx[i];
  }
  return bytes;
259 260
}

261 262
uint32_t flexran_get_TBS_dl(mid_t mod_id, mid_t ue_id, int cc_id)
{
263 264 265 266
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].TBS;
}

267 268
uint32_t flexran_get_TBS_ul(mid_t mod_id, mid_t ue_id, int cc_id)
{
269 270 271 272
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].ulsch_TBS;
}

273 274 275 276
uint16_t flexran_get_num_prb_retx_dl_per_ue(mid_t mod_id, mid_t ue_id, int cc_id)
{
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].rbs_used_retx;
277 278
}

279 280
uint32_t flexran_get_num_prb_retx_ul_per_ue(mid_t mod_id, mid_t ue_id, int cc_id)
{
281 282 283 284
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].rbs_used_retx_rx;
}

285 286 287 288
uint16_t flexran_get_num_prb_dl_tx_per_ue(mid_t mod_id, mid_t ue_id, int cc_id)
{
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].rbs_used;
289 290
}

291 292 293 294
uint16_t flexran_get_num_prb_ul_rx_per_ue(mid_t mod_id, mid_t ue_id, int cc_id)
{
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].rbs_used_rx;
295 296
}

Robert Schmidt's avatar
Robert Schmidt committed
297 298
uint8_t flexran_get_ue_wpmi(mid_t mod_id, mid_t ue_id, uint8_t cc_id)
{
299 300
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.UE_sched_ctrl[ue_id].periodic_wideband_pmi[cc_id];
301 302
}

303 304
uint8_t flexran_get_mcs1_dl(mid_t mod_id, mid_t ue_id, int cc_id)
{
305 306 307 308
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].dlsch_mcs1;
}

309 310
uint8_t flexran_get_mcs2_dl(mid_t mod_id, mid_t ue_id, int cc_id)
{
311 312 313 314
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].dlsch_mcs2;
}

315 316
uint8_t flexran_get_mcs1_ul(mid_t mod_id, mid_t ue_id, int cc_id)
{
317 318 319 320
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].ulsch_mcs1;
}

321 322
uint8_t flexran_get_mcs2_ul(mid_t mod_id, mid_t ue_id, int cc_id)
{
323 324 325 326
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].ulsch_mcs2;
}

327 328
uint32_t flexran_get_total_prb_dl_tx_per_ue(mid_t mod_id, mid_t ue_id, int cc_id)
{
329 330 331 332
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_rbs_used;
}

333 334
uint32_t flexran_get_total_prb_ul_rx_per_ue(mid_t mod_id, mid_t ue_id, int cc_id)
{
335 336 337 338
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_rbs_used_rx;
}

339 340
uint32_t flexran_get_total_num_pdu_dl(mid_t mod_id, mid_t ue_id, int cc_id)
{
341 342 343 344
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_num_pdus;
}

345 346
uint32_t flexran_get_total_num_pdu_ul(mid_t mod_id, mid_t ue_id, int cc_id)
{
347 348 349 350
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_num_pdus_rx;
}

351 352
uint64_t flexran_get_total_TBS_dl(mid_t mod_id, mid_t ue_id, int cc_id)
{
353 354 355 356
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_pdu_bytes;
}

357 358
uint64_t flexran_get_total_TBS_ul(mid_t mod_id, mid_t ue_id, int cc_id)
{
359 360 361 362
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].total_ulsch_TBS;
}

363 364
int flexran_get_harq_round(mid_t mod_id, uint8_t cc_id, mid_t ue_id)
{
365 366 367 368
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].harq_round;
}

369 370 371 372
uint32_t flexran_get_num_mac_sdu_tx(mid_t mod_id, mid_t ue_id, int cc_id)
{
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].num_mac_sdu_tx;
373 374
}

375 376
unsigned char flexran_get_mac_sdu_lcid_index(mid_t mod_id, mid_t ue_id, int cc_id, int index)
{
377 378 379 380
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].lcid_sdu[index];
}

381 382
uint32_t flexran_get_mac_sdu_size(mid_t mod_id, mid_t ue_id, int cc_id, int lcid)
{
383 384 385 386 387
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.eNB_UE_stats[cc_id][ue_id].sdu_length_tx[lcid];
}


Robert Schmidt's avatar
Robert Schmidt committed
388 389 390 391
/* TODO needs to be revised */
void flexran_update_TA(mid_t mod_id, mid_t ue_id, uint8_t cc_id)
{
/*
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
  UE_list_t *UE_list=&eNB_mac_inst[mod_id].UE_list;
  UE_sched_ctrl *ue_sched_ctl = &UE_list->UE_sched_ctrl[ue_id];

  if (ue_sched_ctl->ta_timer == 0) {
    
    // WE SHOULD PROTECT the eNB_UE_stats with a mutex here ...                                                                         
    //    LTE_eNB_UE_stats		*eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id, CC_id, rnti);
    //ue_sched_ctl->ta_timer		      = 20;	// wait 20 subframes before taking TA measurement from PHY                                         
    ue_sched_ctl->ta_update = flexran_get_TA(mod_id, ue_id, CC_id);

    // clear the update in case PHY does not have a new measurement after timer expiry                                               
    //    eNB_UE_stats->timing_advance_update	      = 0;
  } else {
    ue_sched_ctl->ta_timer--;
    ue_sched_ctl->ta_update		      = 0;	// don't trigger a timing advance command      
  }
Robert Schmidt's avatar
Robert Schmidt committed
408
#warning "Implement flexran_update_TA() in RAN API"
409
*/
410 411
}

Robert Schmidt's avatar
Robert Schmidt committed
412 413 414
/* TODO needs to be revised, looks suspicious: why do we need UE stats? */
int flexran_get_MAC_CE_bitmap_TA(mid_t mod_id, mid_t ue_id, uint8_t cc_id)
{
415
/*
Robert Schmidt's avatar
Robert Schmidt committed
416
#warning "Implement flexran_get_MAC_CE_bitmap_TA() in RAN API"
417
*/
418
  if (!phy_is_present(mod_id, cc_id)) return 0;
419

Robert Schmidt's avatar
Robert Schmidt committed
420
  /* UE_stats can not be null, they are an array in RC
421 422 423 424 425
  LTE_eNB_UE_stats *eNB_UE_stats = mac_xface->get_eNB_UE_stats(mod_id,CC_id,rnti);
  
  if (eNB_UE_stats == NULL) {
    return 0;
  }
Robert Schmidt's avatar
Robert Schmidt committed
426
  */
427

Robert Schmidt's avatar
Robert Schmidt committed
428
  if (flexran_get_TA(mod_id, ue_id, cc_id) != 0) {
429 430 431 432 433 434
    return PROTOCOL__FLEX_CE_TYPE__FLPCET_TA;
  } else {
    return 0;
  }
}

Robert Schmidt's avatar
Robert Schmidt committed
435 436
int flexran_get_active_CC(mid_t mod_id, mid_t ue_id)
{
437 438
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.numactiveCCs[ue_id];
439 440
}

Robert Schmidt's avatar
Robert Schmidt committed
441 442
uint8_t flexran_get_current_RI(mid_t mod_id, mid_t ue_id, uint8_t cc_id)
{
443 444
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->UE_stats[ue_id].rank;
445 446
}

Robert Schmidt's avatar
Robert Schmidt committed
447 448
int flexran_get_tpc(mid_t mod_id, mid_t ue_id, uint8_t cc_id)
{
449
  if (!phy_is_present(mod_id, cc_id)) return 0;
Robert Schmidt's avatar
Robert Schmidt committed
450 451 452 453

  /* before: tested that UL_rssi != NULL and set parameter ([0]), but it is a
   * static array -> target_rx_power is useless in old ifs?! */
  int pCCid = UE_PCCID(mod_id,ue_id);
454 455
  int32_t target_rx_power = RC.eNB[mod_id][pCCid]->frame_parms.ul_power_control_config_common.p0_NominalPUSCH;
  int32_t normalized_rx_power = RC.eNB[mod_id][cc_id]->UE_stats[ue_id].UL_rssi[0];
Robert Schmidt's avatar
Robert Schmidt committed
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479

  int tpc;
  if (normalized_rx_power > target_rx_power + 1)
    tpc = 0;	//-1
  else if (normalized_rx_power < target_rx_power - 1)
    tpc = 2;	//+1
  else
    tpc = 1;	//0
  return tpc;
}

int flexran_get_harq(mid_t       mod_id,
                     uint8_t     cc_id,
                     mid_t       ue_id,
                     frame_t     frame,
                     sub_frame_t subframe,
                     uint8_t    *pid,
                     uint8_t    *round,
                     uint8_t     harq_flag)
{
  /* TODO: Add int TB in function parameters to get the status of the second
   * TB. This can be done to by editing in get_ue_active_harq_pid function in
   * line 272 file: phy_procedures_lte_eNB.c to add DLSCH_ptr =
   * PHY_vars_eNB_g[Mod_id][CC_id]->dlsch_eNB[(uint32_t)UE_id][1];*/
480

Robert Schmidt's avatar
Robert Schmidt committed
481 482
  /* TODO IMPLEMENT */
  /*
483 484 485
  uint8_t harq_pid;
  uint8_t harq_round;
  
486
  if (mac_xface_not_ready()) return 0 ;
487

488
  uint16_t rnti = flexran_get_mac_ue_crnti(mod_id,ue_id);
shahab SHARIATBAGHERI's avatar
shahab SHARIATBAGHERI committed
489
  if (harq_flag == openair_harq_DL){
490

shahab SHARIATBAGHERI's avatar
shahab SHARIATBAGHERI committed
491
      mac_xface->get_ue_active_harq_pid(mod_id,CC_id,rnti,frame,subframe,&harq_pid,&harq_round,openair_harq_DL);
492

shahab SHARIATBAGHERI's avatar
shahab SHARIATBAGHERI committed
493 494
   } else if (harq_flag == openair_harq_UL){

shahab SHARIAT BAGHERI's avatar
shahab SHARIAT BAGHERI committed
495
     mac_xface->get_ue_active_harq_pid(mod_id,CC_id,rnti,frame,subframe,&harq_pid,round,openair_harq_UL);    
shahab SHARIATBAGHERI's avatar
shahab SHARIATBAGHERI committed
496 497 498 499 500 501 502 503
   }
   else {

      LOG_W(FLEXRAN_AGENT,"harq_flag is not recongnized");
   }


  *pid = harq_pid;
Robert Schmidt's avatar
Robert Schmidt committed
504
  *round = harq_round;*/
505 506 507 508 509
  /* if (round > 0) { */
  /*   *status = 1; */
  /* } else { */
  /*   *status = 0; */
  /* } */
Robert Schmidt's avatar
Robert Schmidt committed
510
  /*return *round;*/
511
/*
Robert Schmidt's avatar
Robert Schmidt committed
512
#warning "Implement flexran_get_harq() in RAN API"
513
*/
Robert Schmidt's avatar
Robert Schmidt committed
514
  return 0;
515 516
}

Robert Schmidt's avatar
Robert Schmidt committed
517 518
int32_t flexran_get_p0_pucch_dbm(mid_t mod_id, mid_t ue_id, uint8_t cc_id)
{
519 520
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->UE_stats[ue_id].Po_PUCCH_dBm;
521 522
}

Robert Schmidt's avatar
Robert Schmidt committed
523 524
int8_t flexran_get_p0_nominal_pucch(mid_t mod_id, uint8_t cc_id)
{
525 526
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->frame_parms.ul_power_control_config_common.p0_NominalPUCCH;
527 528
}

Robert Schmidt's avatar
Robert Schmidt committed
529 530
int32_t flexran_get_p0_pucch_status(mid_t mod_id, mid_t ue_id, uint8_t cc_id)
{
531 532
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->UE_stats[ue_id].Po_PUCCH_update;
533 534
}

Robert Schmidt's avatar
Robert Schmidt committed
535 536
int flexran_update_p0_pucch(mid_t mod_id, mid_t ue_id, uint8_t cc_id)
{
537 538
  if (!phy_is_present(mod_id, cc_id)) return 0;
  RC.eNB[mod_id][cc_id]->UE_stats[ue_id].Po_PUCCH_update = 0;
539 540 541 542 543 544 545 546 547
  return 0;
}


/*
 * ************************************
 * Get Messages for eNB Configuration Reply
 * ************************************
 */
Robert Schmidt's avatar
Robert Schmidt committed
548 549
uint8_t flexran_get_threequarter_fs(mid_t mod_id, uint8_t cc_id)
{
550 551
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->frame_parms.threequarter_fs;
552 553
}

554

Robert Schmidt's avatar
Robert Schmidt committed
555 556
uint8_t flexran_get_hopping_offset(mid_t mod_id, uint8_t cc_id)
{
557 558
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->frame_parms.pusch_config_common.pusch_HoppingOffset;
559 560
}

561 562 563 564 565 566 567 568 569 570
Protocol__FlexHoppingMode flexran_get_hopping_mode(mid_t mod_id, uint8_t cc_id)
{
  if (!phy_is_present(mod_id, cc_id)) return -1;
  switch (RC.eNB[mod_id][cc_id]->frame_parms.pusch_config_common.hoppingMode) {
  case interSubFrame:
    return PROTOCOL__FLEX_HOPPING_MODE__FLHM_INTER;
  case intraAndInterSubFrame:
    return PROTOCOL__FLEX_HOPPING_MODE__FLHM_INTERINTRA;
  }
  return -1;
571 572
}

Robert Schmidt's avatar
Robert Schmidt committed
573 574
uint8_t flexran_get_n_SB(mid_t mod_id, uint8_t cc_id)
{
575 576
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->frame_parms.pusch_config_common.n_SB;
577 578
}

579
Protocol__FlexQam flexran_get_enable64QAM(mid_t mod_id, uint8_t cc_id)
Robert Schmidt's avatar
Robert Schmidt committed
580
{
581
  if (!phy_is_present(mod_id, cc_id)) return 0;
582 583 584 585
  if (RC.eNB[mod_id][cc_id]->frame_parms.pusch_config_common.enable64QAM == TRUE)
    return PROTOCOL__FLEX_QAM__FLEQ_MOD_64QAM;
  else
    return PROTOCOL__FLEX_QAM__FLEQ_MOD_16QAM;
586 587
}

588
Protocol__FlexPhichDuration flexran_get_phich_duration(mid_t mod_id, uint8_t cc_id)
Robert Schmidt's avatar
Robert Schmidt committed
589
{
590 591 592 593 594 595 596 597
  if (!phy_is_present(mod_id, cc_id)) return -1;
  switch (RC.eNB[mod_id][cc_id]->frame_parms.phich_config_common.phich_duration) {
  case normal:
    return PROTOCOL__FLEX_PHICH_DURATION__FLPD_NORMAL;
  case extended:
    return PROTOCOL__FLEX_PHICH_DURATION__FLPD_EXTENDED;
  }
  return -1;
598 599
}

600
Protocol__FlexPhichResource flexran_get_phich_resource(mid_t mod_id, uint8_t cc_id)
Robert Schmidt's avatar
Robert Schmidt committed
601
{
602
  if (!phy_is_present(mod_id, cc_id)) return -1;
603
  switch (RC.eNB[mod_id][cc_id]->frame_parms.phich_config_common.phich_resource) {
Robert Schmidt's avatar
Robert Schmidt committed
604
  case oneSixth:
605
    return PROTOCOL__FLEX_PHICH_RESOURCE__FLPR_ONE_SIXTH;
Robert Schmidt's avatar
Robert Schmidt committed
606
  case half:
607
    return PROTOCOL__FLEX_PHICH_RESOURCE__FLPR_HALF;
Robert Schmidt's avatar
Robert Schmidt committed
608
  case one:
609
    return PROTOCOL__FLEX_PHICH_RESOURCE__FLPR_ONE;
Robert Schmidt's avatar
Robert Schmidt committed
610
  case two:
611
    return PROTOCOL__FLEX_PHICH_RESOURCE__FLPR_TWO;
Robert Schmidt's avatar
Robert Schmidt committed
612
  }
613
  return -1;
614 615
}

Robert Schmidt's avatar
Robert Schmidt committed
616 617
uint16_t flexran_get_n1pucch_an(mid_t mod_id, uint8_t cc_id)
{
618 619
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->frame_parms.pucch_config_common.n1PUCCH_AN;
620 621
}

Robert Schmidt's avatar
Robert Schmidt committed
622 623
uint8_t flexran_get_nRB_CQI(mid_t mod_id, uint8_t cc_id)
{
624 625
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->frame_parms.pucch_config_common.nRB_CQI;
626 627
}

Robert Schmidt's avatar
Robert Schmidt committed
628 629
uint8_t flexran_get_deltaPUCCH_Shift(mid_t mod_id, uint8_t cc_id)
{
630 631
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->frame_parms.pucch_config_common.deltaPUCCH_Shift;
632 633
}

Robert Schmidt's avatar
Robert Schmidt committed
634 635
uint8_t flexran_get_prach_ConfigIndex(mid_t mod_id, uint8_t cc_id)
{
636 637
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->frame_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex;
638 639
}

Robert Schmidt's avatar
Robert Schmidt committed
640 641
uint8_t flexran_get_prach_FreqOffset(mid_t mod_id, uint8_t cc_id)
{
642 643
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->frame_parms.prach_config_common.prach_ConfigInfo.prach_FreqOffset;
644 645
}

Robert Schmidt's avatar
Robert Schmidt committed
646 647
uint8_t flexran_get_maxHARQ_Msg3Tx(mid_t mod_id, uint8_t cc_id)
{
648 649
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->frame_parms.maxHARQ_Msg3Tx;
650 651
}

652
Protocol__FlexUlCyclicPrefixLength flexran_get_ul_cyclic_prefix_length(mid_t mod_id, uint8_t cc_id)
Robert Schmidt's avatar
Robert Schmidt committed
653
{
654 655 656 657 658 659 660 661
  if (!phy_is_present(mod_id, cc_id)) return -1;
  switch (RC.eNB[mod_id][cc_id]->frame_parms.Ncp_UL) {
  case EXTENDED:
    return PROTOCOL__FLEX_UL_CYCLIC_PREFIX_LENGTH__FLUCPL_EXTENDED;
  case NORMAL:
    return PROTOCOL__FLEX_UL_CYCLIC_PREFIX_LENGTH__FLUCPL_NORMAL;
  }
  return -1;
662 663
}

664
Protocol__FlexDlCyclicPrefixLength flexran_get_dl_cyclic_prefix_length(mid_t mod_id, uint8_t cc_id)
Robert Schmidt's avatar
Robert Schmidt committed
665
{
666 667 668 669 670 671 672 673
  if (!phy_is_present(mod_id, cc_id)) return -1;
  switch (RC.eNB[mod_id][cc_id]->frame_parms.Ncp) {
  case EXTENDED:
    return PROTOCOL__FLEX_DL_CYCLIC_PREFIX_LENGTH__FLDCPL_EXTENDED;
  case NORMAL:
    return PROTOCOL__FLEX_DL_CYCLIC_PREFIX_LENGTH__FLDCPL_NORMAL;
  }
  return -1;
674 675
}

Robert Schmidt's avatar
Robert Schmidt committed
676 677
uint16_t flexran_get_cell_id(mid_t mod_id, uint8_t cc_id)
{
678 679
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->frame_parms.Nid_cell;
680 681
}

Robert Schmidt's avatar
Robert Schmidt committed
682 683
uint8_t flexran_get_srs_BandwidthConfig(mid_t mod_id, uint8_t cc_id)
{
684 685
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->frame_parms.soundingrs_ul_config_common.srs_BandwidthConfig;
686 687
}

Robert Schmidt's avatar
Robert Schmidt committed
688 689
uint8_t flexran_get_srs_SubframeConfig(mid_t mod_id, uint8_t cc_id)
{
690 691
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->frame_parms.soundingrs_ul_config_common.srs_SubframeConfig;
692 693
}

Robert Schmidt's avatar
Robert Schmidt committed
694 695
uint8_t flexran_get_srs_MaxUpPts(mid_t mod_id, uint8_t cc_id)
{
696 697
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->frame_parms.soundingrs_ul_config_common.srs_MaxUpPts;
698 699
}

Robert Schmidt's avatar
Robert Schmidt committed
700 701
uint8_t flexran_get_N_RB_DL(mid_t mod_id, uint8_t cc_id)
{
702 703
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->frame_parms.N_RB_DL;
704 705
}

Robert Schmidt's avatar
Robert Schmidt committed
706 707
uint8_t flexran_get_N_RB_UL(mid_t mod_id, uint8_t cc_id)
{
708 709
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->frame_parms.N_RB_UL;
710 711
}

Robert Schmidt's avatar
Robert Schmidt committed
712 713
uint8_t flexran_get_N_RBG(mid_t mod_id, uint8_t cc_id)
{
714 715
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->frame_parms.N_RBG;
716 717
}

Robert Schmidt's avatar
Robert Schmidt committed
718 719
uint8_t flexran_get_subframe_assignment(mid_t mod_id, uint8_t cc_id)
{
720 721
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->frame_parms.tdd_config;
722 723
}

Robert Schmidt's avatar
Robert Schmidt committed
724 725
uint8_t flexran_get_special_subframe_assignment(mid_t mod_id, uint8_t cc_id)
{
726 727
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->frame_parms.tdd_config_S;
728 729
}

Robert Schmidt's avatar
Robert Schmidt committed
730 731
long flexran_get_ra_ResponseWindowSize(mid_t mod_id, uint8_t cc_id)
{
732
  if (!rrc_is_present(mod_id)) return 0;
733
  return RC.rrc[mod_id]->configuration.radioresourceconfig[cc_id].rach_raResponseWindowSize;
734 735
}

Robert Schmidt's avatar
Robert Schmidt committed
736 737
long flexran_get_mac_ContentionResolutionTimer(mid_t mod_id, uint8_t cc_id)
{
738
  if (!rrc_is_present(mod_id)) return 0;
739
  return RC.rrc[mod_id]->configuration.radioresourceconfig[cc_id].rach_macContentionResolutionTimer;
740 741
}

Robert Schmidt's avatar
Robert Schmidt committed
742 743
Protocol__FlexDuplexMode flexran_get_duplex_mode(mid_t mod_id, uint8_t cc_id)
{
744 745
  if (!phy_is_present(mod_id, cc_id)) return 0;
  switch (RC.eNB[mod_id][cc_id]->frame_parms.frame_type) {
Robert Schmidt's avatar
Robert Schmidt committed
746 747 748 749 750 751 752
  case TDD:
    return PROTOCOL__FLEX_DUPLEX_MODE__FLDM_TDD;
  case FDD:
    return PROTOCOL__FLEX_DUPLEX_MODE__FLDM_FDD;
  default:
    return -1;
  }
753 754
}

Robert Schmidt's avatar
Robert Schmidt committed
755 756
long flexran_get_si_window_length(mid_t mod_id, uint8_t cc_id)
{
757 758
  if (!rrc_is_present(mod_id) || !RC.rrc[mod_id]->carrier[cc_id].sib1) return 0;
  return RC.rrc[mod_id]->carrier[cc_id].sib1->si_WindowLength;
759 760
}

Robert Schmidt's avatar
Robert Schmidt committed
761 762
uint8_t flexran_get_sib1_length(mid_t mod_id, uint8_t cc_id)
{
763 764
  if (!rrc_is_present(mod_id)) return 0;
  return RC.rrc[mod_id]->carrier[cc_id].sizeof_SIB1;
765 766
}

767 768
uint8_t flexran_get_num_pdcch_symb(mid_t mod_id, uint8_t cc_id)
{
769 770
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->pdcch_vars[0].num_pdcch_symbols;
771 772 773 774 775 776 777 778 779
}



/*
 * ************************************
 * Get Messages for UE Configuration Reply
 * ************************************
 */
780 781 782 783 784
int flexran_get_rrc_num_ues(mid_t mod_id)
{
  if (!rrc_is_present(mod_id)) return 0;
  return RC.rrc[mod_id]->Nb_ue;
}
785

786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808
rnti_t flexran_get_rrc_rnti_nth_ue(mid_t mod_id, int index)
{
  if (!rrc_is_present(mod_id)) return 0;
  struct rrc_eNB_ue_context_s* ue_context_p = NULL;
  RB_FOREACH(ue_context_p, rrc_ue_tree_s, &RC.rrc[mod_id]->rrc_ue_head) {
    if (index == 0) return ue_context_p->ue_context.rnti;
    --index;
  }
  return 0;
}

int flexran_get_rrc_rnti_list(mid_t mod_id, rnti_t *list, int max_list)
{
  if (!rrc_is_present(mod_id)) return 0;
  int n = 0;
  struct rrc_eNB_ue_context_s* ue_context_p = NULL;
  RB_FOREACH(ue_context_p, rrc_ue_tree_s, &RC.rrc[mod_id]->rrc_ue_head) {
    if (n >= max_list) break;
    list[n] = ue_context_p->ue_context.rnti;
    ++n;
  }
  return n;
}
809

810
LTE_TimeAlignmentTimer_t  flexran_get_time_alignment_timer(mid_t mod_id, rnti_t rnti)
Robert Schmidt's avatar
Robert Schmidt committed
811
{
812 813
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
Robert Schmidt's avatar
Robert Schmidt committed
814 815 816
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.mac_MainConfig) return -1;
  return ue_context_p->ue_context.mac_MainConfig->timeAlignmentTimerDedicated;
817 818
}

819
Protocol__FlexMeasGapConfigPattern flexran_get_meas_gap_config(mid_t mod_id, rnti_t rnti)
Robert Schmidt's avatar
Robert Schmidt committed
820
{
821 822
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
Robert Schmidt's avatar
Robert Schmidt committed
823 824
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measGapConfig) return -1;
825
  if (ue_context_p->ue_context.measGapConfig->present != LTE_MeasGapConfig_PR_setup) return -1;
Robert Schmidt's avatar
Robert Schmidt committed
826
  switch (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present) {
827
  case LTE_MeasGapConfig__setup__gapOffset_PR_gp0:
Robert Schmidt's avatar
Robert Schmidt committed
828
    return PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_GP1;
829
  case LTE_MeasGapConfig__setup__gapOffset_PR_gp1:
Robert Schmidt's avatar
Robert Schmidt committed
830 831 832
    return PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_GP2;
  default:
    return PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_OFF;
833 834 835
  }
}

shahab SHARIATBAGHERI's avatar
shahab SHARIATBAGHERI committed
836

837
long flexran_get_meas_gap_config_offset(mid_t mod_id, rnti_t rnti)
Robert Schmidt's avatar
Robert Schmidt committed
838
{
839 840
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
Robert Schmidt's avatar
Robert Schmidt committed
841 842
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measGapConfig) return -1;
843
  if (ue_context_p->ue_context.measGapConfig->present != LTE_MeasGapConfig_PR_setup) return -1;
Robert Schmidt's avatar
Robert Schmidt committed
844
  switch (ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.present) {
845
  case LTE_MeasGapConfig__setup__gapOffset_PR_gp0:
Robert Schmidt's avatar
Robert Schmidt committed
846
    return ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.choice.gp0;
847
  case LTE_MeasGapConfig__setup__gapOffset_PR_gp1:
Robert Schmidt's avatar
Robert Schmidt committed
848 849 850 851 852
    return ue_context_p->ue_context.measGapConfig->choice.setup.gapOffset.choice.gp1;
  default:
    return -1;
  }
}
853

854
uint8_t flexran_get_rrc_status(mid_t mod_id, rnti_t rnti)
Robert Schmidt's avatar
Robert Schmidt committed
855
{
856 857
  if (!rrc_is_present(mod_id)) return 0;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
Robert Schmidt's avatar
Robert Schmidt committed
858 859
  if (!ue_context_p) return RRC_INACTIVE;
  return ue_context_p->ue_context.Status;
shahab SHARIATBAGHERI's avatar
shahab SHARIATBAGHERI committed
860 861
}

Robert Schmidt's avatar
Robert Schmidt committed
862 863
uint64_t flexran_get_ue_aggregated_max_bitrate_dl(mid_t mod_id, mid_t ue_id)
{
864 865
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateDL;
866 867
}

Robert Schmidt's avatar
Robert Schmidt committed
868 869
uint64_t flexran_get_ue_aggregated_max_bitrate_ul(mid_t mod_id, mid_t ue_id)
{
870 871
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.UE_sched_ctrl[ue_id].ue_AggregatedMaximumBitrateUL;
872 873
}

874
int flexran_get_half_duplex(mid_t mod_id, rnti_t rnti)
875 876 877 878 879
{
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.UE_Capability) return -1;
880
  LTE_SupportedBandListEUTRA_t *bands = &ue_context_p->ue_context.UE_Capability->rf_Parameters.supportedBandListEUTRA;
881 882 883
  for (int i = 0; i < bands->list.count; i++) {
    if (bands->list.array[i]->halfDuplex > 0) return 1;
  }
884 885 886
  return 0;
}

887
int flexran_get_intra_sf_hopping(mid_t mod_id, rnti_t rnti)
Robert Schmidt's avatar
Robert Schmidt committed
888
{
889 890 891 892 893 894 895 896 897 898 899
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.UE_Capability) return -1;
  if (!ue_context_p->ue_context.UE_Capability->featureGroupIndicators) return -1;
  /* According to TS 36.331 Annex B.1, Intra SF Hopping is bit 1 (leftmost bit)
   * in this bitmap, i.e. the eighth bit (from right) in the first bye (from
   * left) */
  BIT_STRING_t *fgi = ue_context_p->ue_context.UE_Capability->featureGroupIndicators;
  uint8_t buf = fgi->buf[0];
  return (buf >> 7) & 1;
900 901
}

902
int flexran_get_type2_sb_1(mid_t mod_id, rnti_t rnti)
Robert Schmidt's avatar
Robert Schmidt committed
903
{
904 905 906 907 908 909 910 911 912 913 914 915
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.UE_Capability) return -1;
  if (!ue_context_p->ue_context.UE_Capability->featureGroupIndicators) return -1;
  /* According to TS 36.331 Annex B.1, Predefined intra- and inter-sf or
   * predfined inter-sf frequency hopping for PUSCH with N_sb>1 is bit 21 (bit
   * 1 is leftmost bit) in this bitmap, i.e. the fourth bit (from right) in the
   * third byte (from left) */
  BIT_STRING_t *fgi = ue_context_p->ue_context.UE_Capability->featureGroupIndicators;
  uint8_t buf = fgi->buf[2];
  return (buf >> 3) & 1;
916 917
}

918
long flexran_get_ue_category(mid_t mod_id, rnti_t rnti)
Robert Schmidt's avatar
Robert Schmidt committed
919
{
920 921 922 923 924
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.UE_Capability) return -1;
  return ue_context_p->ue_context.UE_Capability->ue_Category;
925 926
}

927
int flexran_get_res_alloc_type1(mid_t mod_id, rnti_t rnti)
Robert Schmidt's avatar
Robert Schmidt committed
928
{
929 930 931 932 933 934 935 936 937 938 939
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.UE_Capability) return -1;
  if (!ue_context_p->ue_context.UE_Capability->featureGroupIndicators) return -1;
  /* According to TS 36.331 Annex B.1, Resource allocation type 1 for PDSCH is
   * bit 2 (bit 1 is leftmost bit) in this bitmap, i.e. the seventh bit (from
   * right) in the first byte (from left) */
  BIT_STRING_t *fgi = ue_context_p->ue_context.UE_Capability->featureGroupIndicators;
  uint8_t buf = fgi->buf[0];
  return (buf >> 6) & 1;
940 941
}

942
long flexran_get_ue_transmission_mode(mid_t mod_id, rnti_t rnti)
Robert Schmidt's avatar
Robert Schmidt committed
943
{
944 945
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
Robert Schmidt's avatar
Robert Schmidt committed
946 947 948 949
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.physicalConfigDedicated) return -1;
  if (!ue_context_p->ue_context.physicalConfigDedicated->antennaInfo) return -1;
  return ue_context_p->ue_context.physicalConfigDedicated->antennaInfo->choice.explicitValue.transmissionMode;
950 951
}

952
BOOLEAN_t flexran_get_tti_bundling(mid_t mod_id, rnti_t rnti)
Robert Schmidt's avatar
Robert Schmidt committed
953
{
954 955
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
Robert Schmidt's avatar
Robert Schmidt committed
956 957 958 959
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.mac_MainConfig) return -1;
  if (!ue_context_p->ue_context.mac_MainConfig->ul_SCH_Config) return -1;
  return ue_context_p->ue_context.mac_MainConfig->ul_SCH_Config->ttiBundling;
960 961
}

962
long flexran_get_maxHARQ_TX(mid_t mod_id, rnti_t rnti)
Robert Schmidt's avatar
Robert Schmidt committed
963
{
964 965
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
Robert Schmidt's avatar
Robert Schmidt committed
966 967 968 969
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.mac_MainConfig) return -1;
  if (!ue_context_p->ue_context.mac_MainConfig->ul_SCH_Config) return -1;
  return *(ue_context_p->ue_context.mac_MainConfig->ul_SCH_Config->maxHARQ_Tx);
970 971
}

972
long flexran_get_beta_offset_ack_index(mid_t mod_id, rnti_t rnti)
Robert Schmidt's avatar
Robert Schmidt committed
973
{
974 975
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
Robert Schmidt's avatar
Robert Schmidt committed
976 977 978 979
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.physicalConfigDedicated) return -1;
  if (!ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated) return -1;
  return ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_ACK_Index;
980 981
}

982
long flexran_get_beta_offset_ri_index(mid_t mod_id, rnti_t rnti)
Robert Schmidt's avatar
Robert Schmidt committed
983
{
984 985
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
Robert Schmidt's avatar
Robert Schmidt committed
986 987 988 989
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.physicalConfigDedicated) return -1;
  if (!ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated) return -1;
  return ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_RI_Index;
990 991
}

992
long flexran_get_beta_offset_cqi_index(mid_t mod_id, rnti_t rnti)
Robert Schmidt's avatar
Robert Schmidt committed
993
{
994 995
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
Robert Schmidt's avatar
Robert Schmidt committed
996 997 998 999
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.physicalConfigDedicated) return -1;
  if (!ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated) return -1;
  return ue_context_p->ue_context.physicalConfigDedicated->pusch_ConfigDedicated->betaOffset_CQI_Index;
1000 1001
}

1002
BOOLEAN_t flexran_get_simultaneous_ack_nack_cqi(mid_t mod_id, rnti_t rnti)
Robert Schmidt's avatar
Robert Schmidt committed
1003
{
1004 1005
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
Robert Schmidt's avatar
Robert Schmidt committed
1006 1007 1008 1009 1010
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.physicalConfigDedicated) return -1;
  if (!ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig) return -1;
  if (!ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic) return -1;
  return ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig->cqi_ReportPeriodic->choice.setup.simultaneousAckNackAndCQI;
1011 1012
}

1013
BOOLEAN_t flexran_get_ack_nack_simultaneous_trans(mid_t mod_id, uint8_t cc_id)
Robert Schmidt's avatar
Robert Schmidt committed
1014
{
1015 1016 1017
  if (!rrc_is_present(mod_id)) return -1;
  if (!RC.rrc[mod_id]->carrier[cc_id].sib2) return -1;
  return RC.rrc[mod_id]->carrier[cc_id].sib2->radioResourceConfigCommon.soundingRS_UL_ConfigCommon.choice.setup.ackNackSRS_SimultaneousTransmission;
Robert Schmidt's avatar
Robert Schmidt committed
1018
}
1019

1020
Protocol__FlexAperiodicCqiReportMode flexran_get_aperiodic_cqi_rep_mode(mid_t mod_id, rnti_t rnti)
Robert Schmidt's avatar
Robert Schmidt committed
1021
{
1022 1023
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
Robert Schmidt's avatar
Robert Schmidt committed
1024 1025 1026
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.physicalConfigDedicated) return -1;
  if (!ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig) return -1;
1027
  switch (*ue_context_p->ue_context.physicalConfigDedicated->cqi_ReportConfig->cqi_ReportModeAperiodic) {
1028
  case LTE_CQI_ReportModeAperiodic_rm12:
1029
    return PROTOCOL__FLEX_APERIODIC_CQI_REPORT_MODE__FLACRM_RM12;
1030
  case LTE_CQI_ReportModeAperiodic_rm20:
1031
    return PROTOCOL__FLEX_APERIODIC_CQI_REPORT_MODE__FLACRM_RM20;
1032
  case LTE_CQI_ReportModeAperiodic_rm22:
1033
    return PROTOCOL__FLEX_APERIODIC_CQI_REPORT_MODE__FLACRM_RM22;
1034
  case LTE_CQI_ReportModeAperiodic_rm30:
1035
    return PROTOCOL__FLEX_APERIODIC_CQI_REPORT_MODE__FLACRM_RM30;
1036
  case LTE_CQI_ReportModeAperiodic_rm31:
1037
    return PROTOCOL__FLEX_APERIODIC_CQI_REPORT_MODE__FLACRM_RM31;
1038
  case LTE_CQI_ReportModeAperiodic_rm32_v1250:
1039
    return PROTOCOL__FLEX_APERIODIC_CQI_REPORT_MODE__FLACRM_RM32_v1250;
1040
  case LTE_CQI_ReportModeAperiodic_rm10_v1310:
1041
    return PROTOCOL__FLEX_APERIODIC_CQI_REPORT_MODE__FLACRM_RM10_v1310;
1042
  case LTE_CQI_ReportModeAperiodic_rm11_v1310:
1043 1044 1045 1046
    return PROTOCOL__FLEX_APERIODIC_CQI_REPORT_MODE__FLACRM_RM11_v1310;
  default:
    return PROTOCOL__FLEX_APERIODIC_CQI_REPORT_MODE__FLACRM_NONE;
  }
1047 1048
}

1049
long flexran_get_tdd_ack_nack_feedback_mode(mid_t mod_id, rnti_t rnti)
Robert Schmidt's avatar
Robert Schmidt committed
1050
{
1051 1052
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
Robert Schmidt's avatar
Robert Schmidt committed
1053 1054 1055 1056 1057
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.physicalConfigDedicated) return -1;
  if (!ue_context_p->ue_context.physicalConfigDedicated->pucch_ConfigDedicated) return -1;
  if (!ue_context_p->ue_context.physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode) return -1;
  return *(ue_context_p->ue_context.physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode);
1058 1059
}

1060
long flexran_get_ack_nack_repetition_factor(mid_t mod_id, rnti_t rnti)
Robert Schmidt's avatar
Robert Schmidt committed
1061
{
1062 1063
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
Robert Schmidt's avatar
Robert Schmidt committed
1064 1065 1066 1067
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.physicalConfigDedicated) return -1;
  if (!ue_context_p->ue_context.physicalConfigDedicated->pucch_ConfigDedicated) return -1;
  return ue_context_p->ue_context.physicalConfigDedicated->pucch_ConfigDedicated->ackNackRepetition.choice.setup.repetitionFactor;
1068 1069
}

1070
long flexran_get_extended_bsr_size(mid_t mod_id, rnti_t rnti)
Robert Schmidt's avatar
Robert Schmidt committed
1071
{
1072 1073
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
Robert Schmidt's avatar
Robert Schmidt committed
1074 1075 1076 1077 1078
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.mac_MainConfig) return -1;
  if (!ue_context_p->ue_context.mac_MainConfig->ext2) return -1;
  if (!ue_context_p->ue_context.mac_MainConfig->ext2->mac_MainConfig_v1020) return -1;
  return *(ue_context_p->ue_context.mac_MainConfig->ext2->mac_MainConfig_v1020->extendedBSR_Sizes_r10);
1079 1080
}

1081
int flexran_get_ue_transmission_antenna(mid_t mod_id, rnti_t rnti)
Robert Schmidt's avatar
Robert Schmidt committed
1082
{
1083 1084
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
Robert Schmidt's avatar
Robert Schmidt committed
1085 1086 1087 1088
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.physicalConfigDedicated) return -1;
  if (!ue_context_p->ue_context.physicalConfigDedicated->antennaInfo) return -1;
  switch (ue_context_p->ue_context.physicalConfigDedicated->antennaInfo->choice.explicitValue.ue_TransmitAntennaSelection.choice.setup) {
1089
  case LTE_AntennaInfoDedicated__ue_TransmitAntennaSelection__setup_closedLoop:
Robert Schmidt's avatar
Robert Schmidt committed
1090
    return 2;
1091
  case LTE_AntennaInfoDedicated__ue_TransmitAntennaSelection__setup_openLoop:
Robert Schmidt's avatar
Robert Schmidt committed
1092 1093 1094
    return 1;
  default:
    return 0;
1095 1096 1097
  }
}

1098
uint64_t flexran_get_ue_imsi(mid_t mod_id, rnti_t rnti)
1099
{
1100
  uint64_t imsi;
1101
  if (!rrc_is_present(mod_id)) return 0;
1102
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
1103
  if (!ue_context_p) return 0;
1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119
  imsi  = ue_context_p->ue_context.imsi.digit15;
  imsi += ue_context_p->ue_context.imsi.digit14 * 10;              // pow(10, 1)
  imsi += ue_context_p->ue_context.imsi.digit13 * 100;             // pow(10, 2)
  imsi += ue_context_p->ue_context.imsi.digit12 * 1000;            // pow(10, 3)
  imsi += ue_context_p->ue_context.imsi.digit11 * 10000;           // pow(10, 4)
  imsi += ue_context_p->ue_context.imsi.digit10 * 100000;          // pow(10, 5)
  imsi += ue_context_p->ue_context.imsi.digit9  * 1000000;         // pow(10, 6)
  imsi += ue_context_p->ue_context.imsi.digit8  * 10000000;        // pow(10, 7)
  imsi += ue_context_p->ue_context.imsi.digit7  * 100000000;       // pow(10, 8)
  imsi += ue_context_p->ue_context.imsi.digit6  * 1000000000;      // pow(10, 9)
  imsi += ue_context_p->ue_context.imsi.digit5  * 10000000000;     // pow(10, 10)
  imsi += ue_context_p->ue_context.imsi.digit4  * 100000000000;    // pow(10, 11)
  imsi += ue_context_p->ue_context.imsi.digit3  * 1000000000000;   // pow(10, 12)
  imsi += ue_context_p->ue_context.imsi.digit2  * 10000000000000;  // pow(10, 13)
  imsi += ue_context_p->ue_context.imsi.digit1  * 100000000000000; // pow(10, 14)
  return imsi;
1120 1121
}

1122
long flexran_get_lcg(mid_t mod_id, mid_t ue_id, mid_t lc_id)
Robert Schmidt's avatar
Robert Schmidt committed
1123
{
1124 1125
  if (!mac_is_present(mod_id)) return 0;
  return RC.mac[mod_id]->UE_list.UE_template[UE_PCCID(mod_id, ue_id)][ue_id].lcgidmap[lc_id];
1126 1127
}

Robert Schmidt's avatar
Robert Schmidt committed
1128
/* TODO Navid: needs to be revised */
Robert Schmidt's avatar
Robert Schmidt committed
1129 1130 1131 1132 1133
int flexran_get_direction(mid_t ue_id, mid_t lc_id)
{
  switch (lc_id) {
  case DCCH:
  case DCCH1:
1134
    return 2;
Robert Schmidt's avatar
Robert Schmidt committed
1135
  case DTCH:
1136
    return 1;
Robert Schmidt's avatar
Robert Schmidt committed
1137
  default:
1138 1139 1140 1141
    return -1;
  }
}

Robert Schmidt's avatar
Robert Schmidt committed
1142 1143
uint8_t flexran_get_antenna_ports(mid_t mod_id, uint8_t cc_id)
{
1144 1145
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->frame_parms.nb_antenna_ports_eNB;
1146
}
1147

Robert Schmidt's avatar
Robert Schmidt committed
1148 1149
uint32_t flexran_agent_get_operating_dl_freq(mid_t mod_id, uint8_t cc_id)
{
1150 1151
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->frame_parms.dl_CarrierFreq / 1000000;
1152 1153
}

Robert Schmidt's avatar
Robert Schmidt committed
1154 1155
uint32_t flexran_agent_get_operating_ul_freq(mid_t mod_id, uint8_t cc_id)
{
1156 1157
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->frame_parms.ul_CarrierFreq / 1000000;
1158 1159
}

Robert Schmidt's avatar
Robert Schmidt committed
1160 1161
uint8_t flexran_agent_get_operating_eutra_band(mid_t mod_id, uint8_t cc_id)
{
1162 1163
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->frame_parms.eutra_band;
1164
}
Robert Schmidt's avatar
Robert Schmidt committed
1165 1166 1167

int8_t flexran_agent_get_operating_pdsch_refpower(mid_t mod_id, uint8_t cc_id)
{
1168 1169
  if (!phy_is_present(mod_id, cc_id)) return 0;
  return RC.eNB[mod_id][cc_id]->frame_parms.pdsch_config_common.referenceSignalPower;
1170 1171
}

Robert Schmidt's avatar
Robert Schmidt committed
1172 1173
long flexran_agent_get_operating_pusch_p0(mid_t mod_id, uint8_t cc_id)
{
1174
  if (!rrc_is_present(mod_id)) return 0;
1175
  return RC.rrc[mod_id]->configuration.radioresourceconfig[cc_id].pusch_p0_Nominal;
Robert Schmidt's avatar
Robert Schmidt committed
1176
}
1177

Robert Schmidt's avatar
Robert Schmidt committed
1178 1179
void flexran_agent_set_operating_dl_freq(mid_t mod_id, uint8_t cc_id, uint32_t dl_freq_mhz)
{
1180 1181 1182 1183
  if (phy_is_present(mod_id, cc_id)) {
    RC.eNB[mod_id][cc_id]->frame_parms.dl_CarrierFreq = dl_freq_mhz * 1000000;
  } else {
    LOG_E(FLEXRAN_AGENT, "can not set dl_CarrierFreq to %d MHz in PHY: PHY is not present\n", dl_freq_mhz);
Robert Schmidt's avatar
Robert Schmidt committed
1184
  }
1185 1186 1187 1188
  if (rrc_is_present(mod_id)) {
    RC.rrc[mod_id]->configuration.downlink_frequency[cc_id] = dl_freq_mhz * 1000000;
  } else {
    LOG_E(FLEXRAN_AGENT, "can not set downlink_frequency to %d MHz in RRC: RRC is not present\n", dl_freq_mhz);
Robert Schmidt's avatar
Robert Schmidt committed
1189
  }
1190 1191
}

Robert Schmidt's avatar
Robert Schmidt committed
1192 1193
void flexran_agent_set_operating_ul_freq(mid_t mod_id, uint8_t cc_id, int32_t ul_freq_mhz_offset)
{
1194
  if (phy_is_present(mod_id, cc_id)) {
Robert Schmidt's avatar
Robert Schmidt committed
1195
    uint32_t new_ul_freq_mhz = flexran_agent_get_operating_dl_freq(mod_id, cc_id) + ul_freq_mhz_offset;
1196 1197 1198
    RC.eNB[mod_id][cc_id]->frame_parms.ul_CarrierFreq = new_ul_freq_mhz * 1000000;
  } else {
    LOG_E(FLEXRAN_AGENT, "can not set ul_CarrierFreq using offset %d MHz in PHY: PHY is not present\n", ul_freq_mhz_offset);
Robert Schmidt's avatar
Robert Schmidt committed
1199
  }
1200 1201 1202 1203
  if (rrc_is_present(mod_id)) {
    RC.rrc[mod_id]->configuration.uplink_frequency_offset[cc_id] = ul_freq_mhz_offset;
  } else {
    LOG_E(FLEXRAN_AGENT, "can not set uplink_frequency_offset to %d MHz in RRC: RRC is not present\n", ul_freq_mhz_offset);
Robert Schmidt's avatar
Robert Schmidt committed
1204
  }
1205
}
Robert Schmidt's avatar
Robert Schmidt committed
1206 1207 1208

void flexran_agent_set_operating_eutra_band(mid_t mod_id, uint8_t cc_id, uint8_t eutra_band)
{
1209 1210 1211 1212
  if (phy_is_present(mod_id, cc_id)) {
    RC.eNB[mod_id][cc_id]->frame_parms.eutra_band = eutra_band;
  } else {
    LOG_E(FLEXRAN_AGENT, "can not set eutra_band to %d in PHY: PHY is not present\n", eutra_band);
Robert Schmidt's avatar
Robert Schmidt committed
1213
  }
1214 1215 1216 1217
  if (rrc_is_present(mod_id)) {
    RC.rrc[mod_id]->configuration.eutra_band[cc_id] = eutra_band;
  } else {
    LOG_E(FLEXRAN_AGENT, "can not set eutra_band to %d in RRC: RRC is not present\n", eutra_band);
Robert Schmidt's avatar
Robert Schmidt committed
1218
  }
1219 1220
}

Robert Schmidt's avatar
Robert Schmidt committed
1221 1222 1223
/* Sets both DL/UL */
void flexran_agent_set_operating_bandwidth(mid_t mod_id, uint8_t cc_id, uint8_t N_RB)
{
1224 1225 1226 1227 1228
  if (phy_is_present(mod_id, cc_id)) {
    RC.eNB[mod_id][cc_id]->frame_parms.N_RB_DL = N_RB;
    RC.eNB[mod_id][cc_id]->frame_parms.N_RB_UL = N_RB;
  } else {
    LOG_E(FLEXRAN_AGENT, "can not set N_RB_DL and N_RB_UL to %d in PHY: PHY is not present\n", N_RB);
Robert Schmidt's avatar
Robert Schmidt committed
1229
  }
1230 1231 1232 1233
  if (rrc_is_present(mod_id)) {
    RC.rrc[mod_id]->configuration.N_RB_DL[cc_id] = N_RB;
  } else {
    LOG_E(FLEXRAN_AGENT, "can not set N_RB_DL to %d in RRC: RRC is not present\n", N_RB);
Robert Schmidt's avatar
Robert Schmidt committed
1234
  }
1235 1236
}

Robert Schmidt's avatar
Robert Schmidt committed
1237 1238
void flexran_agent_set_operating_frame_type(mid_t mod_id, uint8_t cc_id, lte_frame_type_t frame_type)
{
1239 1240 1241 1242
  if (phy_is_present(mod_id, cc_id)) {
    RC.eNB[mod_id][cc_id]->frame_parms.frame_type = frame_type;
  } else {
    LOG_E(FLEXRAN_AGENT, "can not set frame_type to %d in PHY: PHY is not present\n", frame_type);
Robert Schmidt's avatar
Robert Schmidt committed
1243
  }
1244 1245 1246 1247
  if (rrc_is_present(mod_id)) {
    RC.rrc[mod_id]->configuration.frame_type[cc_id] = frame_type;
  } else {
    LOG_E(FLEXRAN_AGENT, "can not set frame_type to %d in RRC: RRC is not present\n", frame_type);
Robert Schmidt's avatar
Robert Schmidt committed
1248
  }
1249 1250
}

1251
/*********** PDCP  *************/
1252

1253
uint16_t flexran_get_pdcp_uid_from_rnti(mid_t mod_id, rnti_t rnti)
1254 1255
{
  if (rnti == NOT_A_RNTI) return 0;
1256 1257
  if (mod_id < 0 || mod_id >= RC.nb_inst)
    return 0;
1258 1259 1260 1261 1262 1263 1264 1265

  for (uint16_t pdcp_uid = 0; pdcp_uid < MAX_MOBILES_PER_ENB; ++pdcp_uid) {
    if (pdcp_enb[mod_id].rnti[pdcp_uid] == rnti)
      return pdcp_uid;
  }
  return 0;
}

1266
/*PDCP super frame counter flexRAN*/
1267 1268
uint32_t flexran_get_pdcp_sfn(mid_t mod_id)
{
1269 1270
  if (mod_id < 0 || mod_id >= RC.nb_inst)
    return 0;
1271
  return pdcp_enb[mod_id].sfn;
1272
}
1273

1274
/*PDCP super frame counter flexRAN*/
1275
void flexran_set_pdcp_tx_stat_window(mid_t mod_id, uint16_t uid, uint16_t obs_window)
1276
{
1277 1278 1279 1280
  if (mod_id < 0 || mod_id >= RC.nb_inst || uid < 0
      || uid >= MAX_MOBILES_PER_ENB)
    return;
  Pdcp_stats_tx_window_ms[mod_id][uid] = obs_window > 0 ? obs_window : 1000;
1281 1282 1283
}

/*PDCP super frame counter flexRAN*/
1284
void flexran_set_pdcp_rx_stat_window(mid_t mod_id, uint16_t uid, uint16_t obs_window)
1285
{
1286 1287 1288 1289
  if (mod_id < 0 || mod_id >= RC.nb_inst || uid < 0
      || uid >= MAX_MOBILES_PER_ENB)
    return;
  Pdcp_stats_rx_window_ms[mod_id][uid] = obs_window > 0 ? obs_window : 1000;
1290 1291
}

1292
/*PDCP num tx pdu status flexRAN*/
1293
uint32_t flexran_get_pdcp_tx(mid_t mod_id, uint16_t uid, lcid_t lcid)
1294
{
1295 1296 1297
  if (mod_id < 0 || mod_id >= RC.nb_inst || uid < 0
      || uid >= MAX_MOBILES_PER_ENB || lcid < 0 || lcid >= NB_RB_MAX)
    return 0;
1298
  return Pdcp_stats_tx[mod_id][uid][lcid];
1299 1300 1301
}

/*PDCP num tx bytes status flexRAN*/
1302
uint32_t flexran_get_pdcp_tx_bytes(mid_t mod_id, uint16_t uid, lcid_t lcid)
1303
{
1304 1305 1306
  if (mod_id < 0 || mod_id >= RC.nb_inst || uid < 0
      || uid >= MAX_MOBILES_PER_ENB || lcid < 0 || lcid >= NB_RB_MAX)
    return 0;
1307
  return Pdcp_stats_tx_bytes[mod_id][uid][lcid];
1308 1309 1310
}

/*PDCP number of transmit packet / second status flexRAN*/
1311
uint32_t flexran_get_pdcp_tx_w(mid_t mod_id, uint16_t uid, lcid_t lcid)
1312
{
1313 1314 1315
  if (mod_id < 0 || mod_id >= RC.nb_inst || uid < 0
      || uid >= MAX_MOBILES_PER_ENB || lcid < 0 || lcid >= NB_RB_MAX)
    return 0;
1316
  return Pdcp_stats_tx_w[mod_id][uid][lcid];
1317 1318 1319
}

/*PDCP throughput (bit/s) status flexRAN*/
1320
uint32_t flexran_get_pdcp_tx_bytes_w(mid_t mod_id, uint16_t uid, lcid_t lcid)
1321
{
1322 1323 1324
  if (mod_id < 0 || mod_id >= RC.nb_inst || uid < 0
      || uid >= MAX_MOBILES_PER_ENB || lcid < 0 || lcid >= NB_RB_MAX)
    return 0;
1325
  return Pdcp_stats_tx_bytes_w[mod_id][uid][lcid];
1326 1327 1328
}

/*PDCP tx sequence number flexRAN*/
1329
uint32_t flexran_get_pdcp_tx_sn(mid_t mod_id, uint16_t uid, lcid_t lcid)
1330
{
1331 1332 1333
  if (mod_id < 0 || mod_id >= RC.nb_inst || uid < 0
      || uid >= MAX_MOBILES_PER_ENB || lcid < 0 || lcid >= NB_RB_MAX)
    return 0;
1334
  return Pdcp_stats_tx_sn[mod_id][uid][lcid];
1335 1336 1337
}

/*PDCP tx aggregated packet arrival  flexRAN*/
1338
uint32_t flexran_get_pdcp_tx_aiat(mid_t mod_id, uint16_t uid, lcid_t lcid)
1339
{
1340 1341 1342
  if (mod_id < 0 || mod_id >= RC.nb_inst || uid < 0
      || uid >= MAX_MOBILES_PER_ENB || lcid < 0 || lcid >= NB_RB_MAX)
    return 0;
1343
  return Pdcp_stats_tx_aiat[mod_id][uid][lcid];
1344 1345 1346
}

/*PDCP tx aggregated packet arrival  flexRAN*/
1347
uint32_t flexran_get_pdcp_tx_aiat_w(mid_t mod_id, uint16_t uid, lcid_t lcid)
1348
{
1349 1350 1351
  if (mod_id < 0 || mod_id >= RC.nb_inst || uid < 0
      || uid >= MAX_MOBILES_PER_ENB || lcid < 0 || lcid >= NB_RB_MAX)
    return 0;
1352
  return Pdcp_stats_tx_aiat_w[mod_id][uid][lcid];
1353 1354 1355
}

/*PDCP num rx pdu status flexRAN*/
1356
uint32_t flexran_get_pdcp_rx(mid_t mod_id, uint16_t uid, lcid_t lcid)
1357
{
1358 1359 1360
  if (mod_id < 0 || mod_id >= RC.nb_inst || uid < 0
      || uid >= MAX_MOBILES_PER_ENB || lcid < 0 || lcid >= NB_RB_MAX)
    return 0;
1361
  return Pdcp_stats_rx[mod_id][uid][lcid];
1362 1363 1364
}

/*PDCP num rx bytes status flexRAN*/
1365
uint32_t flexran_get_pdcp_rx_bytes(mid_t mod_id, uint16_t uid, lcid_t lcid)
1366
{
1367 1368 1369
  if (mod_id < 0 || mod_id >= RC.nb_inst || uid < 0
      || uid >= MAX_MOBILES_PER_ENB || lcid < 0 || lcid >= NB_RB_MAX)
    return 0;
1370
  return Pdcp_stats_rx_bytes[mod_id][uid][lcid];
1371 1372 1373
}

/*PDCP number of received packet / second  flexRAN*/
1374
uint32_t flexran_get_pdcp_rx_w(mid_t mod_id, uint16_t uid, lcid_t lcid)
1375
{
1376 1377 1378
  if (mod_id < 0 || mod_id >= RC.nb_inst || uid < 0
      || uid >= MAX_MOBILES_PER_ENB || lcid < 0 || lcid >= NB_RB_MAX)
    return 0;
1379
  return Pdcp_stats_rx_w[mod_id][uid][lcid];
1380 1381 1382
}

/*PDCP gootput (bit/s) status flexRAN*/
1383
uint32_t flexran_get_pdcp_rx_bytes_w(mid_t mod_id, uint16_t uid, lcid_t lcid)
1384
{
1385 1386 1387
  if (mod_id < 0 || mod_id >= RC.nb_inst || uid < 0
      || uid >= MAX_MOBILES_PER_ENB || lcid < 0 || lcid >= NB_RB_MAX)
    return 0;
1388
  return Pdcp_stats_rx_bytes_w[mod_id][uid][lcid];
1389 1390 1391
}

/*PDCP rx sequence number flexRAN*/
1392
uint32_t flexran_get_pdcp_rx_sn(mid_t mod_id, uint16_t uid, lcid_t lcid)
1393
{
1394 1395 1396
  if (mod_id < 0 || mod_id >= RC.nb_inst || uid < 0
      || uid >= MAX_MOBILES_PER_ENB || lcid < 0 || lcid >= NB_RB_MAX)
    return 0;
1397
  return Pdcp_stats_rx_sn[mod_id][uid][lcid];
1398 1399 1400
}

/*PDCP rx aggregated packet arrival  flexRAN*/
1401
uint32_t flexran_get_pdcp_rx_aiat(mid_t mod_id, uint16_t uid, lcid_t lcid)
1402
{
1403 1404 1405
  if (mod_id < 0 || mod_id >= RC.nb_inst || uid < 0
      || uid >= MAX_MOBILES_PER_ENB || lcid < 0 || lcid >= NB_RB_MAX)
    return 0;
1406
  return Pdcp_stats_rx_aiat[mod_id][uid][lcid];
1407 1408 1409
}

/*PDCP rx aggregated packet arrival  flexRAN*/
1410
uint32_t flexran_get_pdcp_rx_aiat_w(mid_t mod_id, uint16_t uid, lcid_t lcid)
1411
{
1412 1413 1414
  if (mod_id < 0 || mod_id >= RC.nb_inst || uid < 0
      || uid >= MAX_MOBILES_PER_ENB || lcid < 0 || lcid >= NB_RB_MAX)
    return 0;
1415
  return Pdcp_stats_rx_aiat_w[mod_id][uid][lcid];
1416 1417 1418
}

/*PDCP num of received outoforder pdu status flexRAN*/
1419
uint32_t flexran_get_pdcp_rx_oo(mid_t mod_id, uint16_t uid, lcid_t lcid)
1420
{
1421 1422 1423
  if (mod_id < 0 || mod_id >= RC.nb_inst || uid < 0
      || uid >= MAX_MOBILES_PER_ENB || lcid < 0 || lcid >= NB_RB_MAX)
    return 0;
1424
  return Pdcp_stats_rx_outoforder[mod_id][uid][lcid];
1425
}
1426

1427
/******************** RRC *****************************/
1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439
/* RRC Wrappers */
int flexran_call_rrc_reconfiguration (mid_t mod_id, rnti_t rnti) {
  if (!rrc_is_present(mod_id)) return -1;
  protocol_ctxt_t  ctxt;
  memset(&ctxt, 0, sizeof(ctxt));
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, mod_id, ENB_FLAG_YES, ue_context_p->ue_context.rnti, flexran_get_current_frame(mod_id), flexran_get_current_subframe (mod_id), mod_id);
  flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(&ctxt, ue_context_p, 0);
  return 0;
}

1440 1441 1442 1443 1444 1445 1446 1447 1448 1449
int flexran_call_rrc_trigger_handover (mid_t mod_id, rnti_t rnti, int target_cell_id) {
  if (!rrc_is_present(mod_id)) return -1;
  protocol_ctxt_t  ctxt;
  memset(&ctxt, 0, sizeof(ctxt));
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, mod_id, ENB_FLAG_YES, ue_context_p->ue_context.rnti, flexran_get_current_frame(mod_id), flexran_get_current_subframe (mod_id), mod_id);
  return flexran_rrc_eNB_trigger_handover(mod_id, &ctxt, ue_context_p, target_cell_id);
}

1450
/* RRC Getters */
1451

1452
LTE_MeasId_t  flexran_get_rrc_pcell_measid(mid_t mod_id, rnti_t rnti) {
1453 1454
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
Robert Schmidt's avatar
Robert Schmidt committed
1455 1456 1457
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measResults) return -1;
  return ue_context_p->ue_context.measResults->measId;
1458
}
1459

1460
float flexran_get_rrc_pcell_rsrp(mid_t mod_id, rnti_t rnti) {
1461 1462
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
Robert Schmidt's avatar
Robert Schmidt committed
1463 1464
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measResults) return -1;
1465 1466 1467 1468 1469
  #if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0))
    return RSRP_meas_mapping[ue_context_p->ue_context.measResults->measResultPCell.rsrpResult];
  #else
    return RSRP_meas_mapping[ue_context_p->ue_context.measResults->measResultServCell.rsrpResult];
  #endif
1470 1471
}

1472
float flexran_get_rrc_pcell_rsrq(mid_t mod_id, rnti_t rnti) {
1473 1474
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
Robert Schmidt's avatar
Robert Schmidt committed
1475 1476
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measResults) return -1;
1477 1478 1479 1480 1481
  #if (LTE_RRC_VERSION >= MAKE_VERSION(10, 0, 0))
    return RSRQ_meas_mapping[ue_context_p->ue_context.measResults->measResultPCell.rsrqResult];
  #else
    return RSRQ_meas_mapping[ue_context_p->ue_context.measResults->measResultServCell.rsrqResult];
  #endif
1482 1483
}

Robert Schmidt's avatar
Robert Schmidt committed
1484
/*Number of neighbouring cells for specific UE*/
1485
int flexran_get_rrc_num_ncell(mid_t mod_id, rnti_t rnti) {
1486 1487
  if (!rrc_is_present(mod_id)) return 0;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
Robert Schmidt's avatar
Robert Schmidt committed
1488 1489 1490
  if (!ue_context_p) return 0;
  if (!ue_context_p->ue_context.measResults) return 0;
  if (!ue_context_p->ue_context.measResults->measResultNeighCells) return 0;
1491
  //if (ue_context_p->ue_context.measResults->measResultNeighCells->present != LTE_MeasResults__measResultNeighCells_PR_measResultListEUTRA) return 0;
Robert Schmidt's avatar
Robert Schmidt committed
1492 1493
  return ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.count;
}
1494

1495
long flexran_get_rrc_neigh_phy_cell_id(mid_t mod_id, rnti_t rnti, long cell_id) {
1496 1497
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
Robert Schmidt's avatar
Robert Schmidt committed
1498 1499 1500
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measResults) return -1;
  if (!ue_context_p->ue_context.measResults->measResultNeighCells) return -1;
1501
  //if (ue_context_p->ue_context.measResults->measResultNeighCells->present != LTE_MeasResults__measResultNeighCells_PR_measResultListEUTRA) return -1;
Robert Schmidt's avatar
Robert Schmidt committed
1502 1503 1504
  if (!ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]) return -1;
  return ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->physCellId;
}
1505

1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516
int flexran_get_rrc_neigh_cgi(mid_t mod_id, rnti_t rnti, long cell_id) {
  if (!rrc_is_present(mod_id)) return 0;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return 0;
  if (!ue_context_p->ue_context.measResults) return 0;
  if (!ue_context_p->ue_context.measResults->measResultNeighCells) return 0;
  //if (ue_context_p->ue_context.measResults->measResultNeighCells->present != LTE_MeasResults__measResultNeighCells_PR_measResultListEUTRA) return 0;
  if (!ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]) return 0;
  return (!ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->cgi_Info)?0:1;
}

1517 1518
uint32_t flexran_get_rrc_neigh_cgi_cell_id(mid_t mod_id, rnti_t rnti, long cell_id) {
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
1519

1520 1521 1522 1523 1524 1525
  uint8_t *cId = ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->cgi_Info->cellGlobalId.cellIdentity.buf;
  return ((cId[0] << 20) + (cId[1] << 12) + (cId[2] << 4) + (cId[3] >> 4));
}

uint32_t flexran_get_rrc_neigh_cgi_tac(mid_t mod_id, rnti_t rnti, long cell_id) {
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
1526

1527 1528 1529 1530
  uint8_t *tac = ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->cgi_Info->trackingAreaCode.buf;
  return (tac[0] << 8) + (tac[1]);
}

1531
int flexran_get_rrc_neigh_cgi_num_mnc(mid_t mod_id, rnti_t rnti, long cell_id) {
1532
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
1533

1534 1535 1536
  return ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->cgi_Info->cellGlobalId.plmn_Identity.mnc.list.count;
}

1537
int flexran_get_rrc_neigh_cgi_num_mcc(mid_t mod_id, rnti_t rnti, long cell_id) {
1538
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
1539

1540 1541 1542 1543 1544
  return ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->cgi_Info->cellGlobalId.plmn_Identity.mcc->list.count;
}

uint32_t flexran_get_rrc_neigh_cgi_mnc(mid_t mod_id, rnti_t rnti, long cell_id, int mnc_id) {
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
1545

1546 1547 1548 1549 1550 1551 1552
  int num_mnc = ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->cgi_Info->cellGlobalId.plmn_Identity.mnc.list.count;
  return *(ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->cgi_Info->cellGlobalId.plmn_Identity.mnc.list.array[mnc_id]) *
               ((uint32_t) pow(10, num_mnc - mnc_id - 1));
}

uint32_t flexran_get_rrc_neigh_cgi_mcc(mid_t mod_id, rnti_t rnti, long cell_id, int mcc_id) {
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
1553

1554 1555 1556 1557 1558 1559
  int num_mcc = ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->cgi_Info->cellGlobalId.plmn_Identity.mcc->list.count;
  return *(ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->cgi_Info->cellGlobalId.plmn_Identity.mcc->list.array[mcc_id]) *
               ((uint32_t) pow(10, num_mcc - mcc_id - 1));
}

float flexran_get_rrc_neigh_rsrp(mid_t mod_id, rnti_t rnti, long cell_id) {
1560 1561
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
Robert Schmidt's avatar
Robert Schmidt committed
1562 1563 1564
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measResults) return -1;
  if (!ue_context_p->ue_context.measResults->measResultNeighCells) return -1;
1565
  //if (ue_context_p->ue_context.measResults->measResultNeighCells->present != LTE_MeasResults__measResultNeighCells_PR_measResultListEUTRA) return -1;
Robert Schmidt's avatar
Robert Schmidt committed
1566
  if (!ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]) return -1;
1567
  if (!ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->measResult.rsrpResult) return -1;
Robert Schmidt's avatar
Robert Schmidt committed
1568
  return RSRP_meas_mapping[*(ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->measResult.rsrpResult)];
1569 1570
}

1571
float flexran_get_rrc_neigh_rsrq(mid_t mod_id, rnti_t rnti, long cell_id) {
1572 1573
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
Robert Schmidt's avatar
Robert Schmidt committed
1574 1575 1576
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measResults) return -1;
  if (!ue_context_p->ue_context.measResults->measResultNeighCells) return -1;
1577 1578
  //if (ue_context_p->ue_context.measResults->measResultNeighCells->present != LTE_MeasResults__measResultNeighCells_PR_measResultListEUTRA) return -1;
  if (!ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->measResult.rsrqResult) return -1;
Robert Schmidt's avatar
Robert Schmidt committed
1579
  return RSRQ_meas_mapping[*(ue_context_p->ue_context.measResults->measResultNeighCells->choice.measResultListEUTRA.list.array[cell_id]->measResult.rsrqResult)];
1580
}
1581

1582 1583
/* Measurement offsets */

1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604
long flexran_get_rrc_ofp(mid_t mod_id, rnti_t rnti) {
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measurement_info) return -1;
  return ue_context_p->ue_context.measurement_info->offsetFreq;
}

long flexran_get_rrc_ofn(mid_t mod_id, rnti_t rnti) {
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measurement_info) return -1;
  return ue_context_p->ue_context.measurement_info->offsetFreq;
}

long flexran_get_rrc_ocp(mid_t mod_id, rnti_t rnti) {
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measurement_info) return -1;
1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638
  switch (ue_context_p->ue_context.measurement_info->cellIndividualOffset[0]) {
  case LTE_Q_OffsetRange_dB_24: return -24;
  case LTE_Q_OffsetRange_dB_22: return -22;
  case LTE_Q_OffsetRange_dB_20: return -20;
  case LTE_Q_OffsetRange_dB_18: return -18;
  case LTE_Q_OffsetRange_dB_16: return -16;
  case LTE_Q_OffsetRange_dB_14: return -14;
  case LTE_Q_OffsetRange_dB_12: return -12;
  case LTE_Q_OffsetRange_dB_10: return -10;
  case LTE_Q_OffsetRange_dB_8:  return -8;
  case LTE_Q_OffsetRange_dB_6:  return -6;
  case LTE_Q_OffsetRange_dB_5:  return -5;
  case LTE_Q_OffsetRange_dB_4:  return -4;
  case LTE_Q_OffsetRange_dB_3:  return -3;
  case LTE_Q_OffsetRange_dB_2:  return -2;
  case LTE_Q_OffsetRange_dB_1:  return -1;
  case LTE_Q_OffsetRange_dB0:   return  0;
  case LTE_Q_OffsetRange_dB1:   return  1;
  case LTE_Q_OffsetRange_dB2:   return  2;
  case LTE_Q_OffsetRange_dB3:   return  3;
  case LTE_Q_OffsetRange_dB4:   return  4;
  case LTE_Q_OffsetRange_dB5:   return  5;
  case LTE_Q_OffsetRange_dB6:   return  6;
  case LTE_Q_OffsetRange_dB8:   return  8;
  case LTE_Q_OffsetRange_dB10:  return 10;
  case LTE_Q_OffsetRange_dB12:  return 12;
  case LTE_Q_OffsetRange_dB14:  return 14;
  case LTE_Q_OffsetRange_dB16:  return 16;
  case LTE_Q_OffsetRange_dB18:  return 18;
  case LTE_Q_OffsetRange_dB20:  return 20;
  case LTE_Q_OffsetRange_dB22:  return 22;
  case LTE_Q_OffsetRange_dB24:  return 24;
  default:                      return -99;
  }
1639 1640
}

1641
long flexran_get_rrc_ocn(mid_t mod_id, rnti_t rnti, long cell_id) {
1642 1643 1644 1645
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measurement_info) return -1;
1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679
  switch (ue_context_p->ue_context.measurement_info->cellIndividualOffset[cell_id+1]) {
  case LTE_Q_OffsetRange_dB_24: return -24;
  case LTE_Q_OffsetRange_dB_22: return -22;
  case LTE_Q_OffsetRange_dB_20: return -20;
  case LTE_Q_OffsetRange_dB_18: return -18;
  case LTE_Q_OffsetRange_dB_16: return -16;
  case LTE_Q_OffsetRange_dB_14: return -14;
  case LTE_Q_OffsetRange_dB_12: return -12;
  case LTE_Q_OffsetRange_dB_10: return -10;
  case LTE_Q_OffsetRange_dB_8:  return -8;
  case LTE_Q_OffsetRange_dB_6:  return -6;
  case LTE_Q_OffsetRange_dB_5:  return -5;
  case LTE_Q_OffsetRange_dB_4:  return -4;
  case LTE_Q_OffsetRange_dB_3:  return -3;
  case LTE_Q_OffsetRange_dB_2:  return -2;
  case LTE_Q_OffsetRange_dB_1:  return -1;
  case LTE_Q_OffsetRange_dB0:   return  0;
  case LTE_Q_OffsetRange_dB1:   return  1;
  case LTE_Q_OffsetRange_dB2:   return  2;
  case LTE_Q_OffsetRange_dB3:   return  3;
  case LTE_Q_OffsetRange_dB4:   return  4;
  case LTE_Q_OffsetRange_dB5:   return  5;
  case LTE_Q_OffsetRange_dB6:   return  6;
  case LTE_Q_OffsetRange_dB8:   return  8;
  case LTE_Q_OffsetRange_dB10:  return 10;
  case LTE_Q_OffsetRange_dB12:  return 12;
  case LTE_Q_OffsetRange_dB14:  return 14;
  case LTE_Q_OffsetRange_dB16:  return 16;
  case LTE_Q_OffsetRange_dB18:  return 18;
  case LTE_Q_OffsetRange_dB20:  return 20;
  case LTE_Q_OffsetRange_dB22:  return 22;
  case LTE_Q_OffsetRange_dB24:  return 24;
  default:                      return -99;
  }
1680 1681
}

1682 1683 1684 1685 1686
long flexran_get_filter_coeff_rsrp(mid_t mod_id, rnti_t rnti) {
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measurement_info) return -1;
1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705
  switch (ue_context_p->ue_context.measurement_info->filterCoefficientRSRP) {
  case LTE_FilterCoefficient_fc0:    return 0;
  case LTE_FilterCoefficient_fc1:    return 1;
  case LTE_FilterCoefficient_fc2:    return 2;
  case LTE_FilterCoefficient_fc3:    return 3;
  case LTE_FilterCoefficient_fc4:    return 4;
  case LTE_FilterCoefficient_fc5:    return 5;
  case LTE_FilterCoefficient_fc6:    return 6;
  case LTE_FilterCoefficient_fc7:    return 7;
  case LTE_FilterCoefficient_fc8:    return 8;
  case LTE_FilterCoefficient_fc9:    return 9;
  case LTE_FilterCoefficient_fc11:   return 11;
  case LTE_FilterCoefficient_fc13:   return 13;
  case LTE_FilterCoefficient_fc15:   return 15;
  case LTE_FilterCoefficient_fc17:   return 17;
  case LTE_FilterCoefficient_fc19:   return 19;
  case LTE_FilterCoefficient_spare1: return -1; /* spare means no coefficient */
  default:                           return -1;
  }
1706 1707 1708 1709 1710 1711 1712
}

long flexran_get_filter_coeff_rsrq(mid_t mod_id, rnti_t rnti) {
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measurement_info) return -1;
1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731
  switch (ue_context_p->ue_context.measurement_info->filterCoefficientRSRQ) {
  case LTE_FilterCoefficient_fc0:    return 0;
  case LTE_FilterCoefficient_fc1:    return 1;
  case LTE_FilterCoefficient_fc2:    return 2;
  case LTE_FilterCoefficient_fc3:    return 3;
  case LTE_FilterCoefficient_fc4:    return 4;
  case LTE_FilterCoefficient_fc5:    return 5;
  case LTE_FilterCoefficient_fc6:    return 6;
  case LTE_FilterCoefficient_fc7:    return 7;
  case LTE_FilterCoefficient_fc8:    return 8;
  case LTE_FilterCoefficient_fc9:    return 9;
  case LTE_FilterCoefficient_fc11:   return 11;
  case LTE_FilterCoefficient_fc13:   return 13;
  case LTE_FilterCoefficient_fc15:   return 15;
  case LTE_FilterCoefficient_fc17:   return 17;
  case LTE_FilterCoefficient_fc19:   return 19;
  case LTE_FilterCoefficient_spare1: return -1; /* spare means no coefficient */
  default:                           return -1;
  }
1732 1733
}

1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764
/* Periodic event */

long flexran_get_rrc_per_event_maxReportCells(mid_t mod_id, rnti_t rnti) {
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measurement_info) return -1;
  if (!ue_context_p->ue_context.measurement_info->events) return -1;
  if (!ue_context_p->ue_context.measurement_info->events->per_event) return -1;
  return ue_context_p->ue_context.measurement_info->events->per_event->maxReportCells;
}

/* A3 event */

long flexran_get_rrc_a3_event_hysteresis(mid_t mod_id, rnti_t rnti) {
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measurement_info) return -1;
  if (!ue_context_p->ue_context.measurement_info->events) return -1;
  if (!ue_context_p->ue_context.measurement_info->events->a3_event) return -1;
  return ue_context_p->ue_context.measurement_info->events->a3_event->hysteresis;
}

long flexran_get_rrc_a3_event_timeToTrigger(mid_t mod_id, rnti_t rnti) {
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measurement_info) return -1;
  if (!ue_context_p->ue_context.measurement_info->events) return -1;
  if (!ue_context_p->ue_context.measurement_info->events->a3_event) return -1;
1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783
  switch (ue_context_p->ue_context.measurement_info->events->a3_event->timeToTrigger) {
  case LTE_TimeToTrigger_ms0:    return 0;
  case LTE_TimeToTrigger_ms40:   return 40;
  case LTE_TimeToTrigger_ms64:   return 64;
  case LTE_TimeToTrigger_ms80:   return 80;
  case LTE_TimeToTrigger_ms100:  return 100;
  case LTE_TimeToTrigger_ms128:  return 128;
  case LTE_TimeToTrigger_ms160:  return 160;
  case LTE_TimeToTrigger_ms256:  return 256;
  case LTE_TimeToTrigger_ms320:  return 320;
  case LTE_TimeToTrigger_ms480:  return 480;
  case LTE_TimeToTrigger_ms512:  return 512;
  case LTE_TimeToTrigger_ms640:  return 640;
  case LTE_TimeToTrigger_ms1024: return 1024;
  case LTE_TimeToTrigger_ms1280: return 1280;
  case LTE_TimeToTrigger_ms2560: return 2560;
  case LTE_TimeToTrigger_ms5120: return 5120;
  default:                       return -1;
  }
1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815
}

long flexran_get_rrc_a3_event_maxReportCells(mid_t mod_id, rnti_t rnti) {
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measurement_info) return -1;
  if (!ue_context_p->ue_context.measurement_info->events) return -1;
  if (!ue_context_p->ue_context.measurement_info->events->a3_event) return -1;
  return ue_context_p->ue_context.measurement_info->events->a3_event->maxReportCells;
}

long flexran_get_rrc_a3_event_a3_offset(mid_t mod_id, rnti_t rnti) {
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measurement_info) return -1;
  if (!ue_context_p->ue_context.measurement_info->events) return -1;
  if (!ue_context_p->ue_context.measurement_info->events->a3_event) return -1;
  return ue_context_p->ue_context.measurement_info->events->a3_event->a3_offset;
}

int flexran_get_rrc_a3_event_reportOnLeave(mid_t mod_id, rnti_t rnti) {
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measurement_info) return -1;
  if (!ue_context_p->ue_context.measurement_info->events) return -1;
  if (!ue_context_p->ue_context.measurement_info->events->a3_event) return -1;
  return ue_context_p->ue_context.measurement_info->events->a3_event->reportOnLeave;
}

1816 1817 1818 1819 1820 1821 1822 1823 1824
/* RRC Setters */

/* Measurement offsets */

int flexran_set_rrc_ofp(mid_t mod_id, rnti_t rnti, long offsetFreq) {
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measurement_info) return -1;
1825
  if (!((offsetFreq >= -15) && (offsetFreq <= 15))) return -1;
1826 1827 1828 1829 1830 1831 1832 1833 1834
  ue_context_p->ue_context.measurement_info->offsetFreq = offsetFreq;
  return 0;
}

int flexran_set_rrc_ofn(mid_t mod_id, rnti_t rnti, long offsetFreq) {
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measurement_info) return -1;
1835
  if (!((offsetFreq >= -15) && (offsetFreq <= 15))) return -1;
1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990
  ue_context_p->ue_context.measurement_info->offsetFreq = offsetFreq;
  return 0;
}

int flexran_set_rrc_ocp(mid_t mod_id, rnti_t rnti, long cellIndividualOffset) {
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measurement_info) return -1;
  LTE_Q_OffsetRange_t *cio = &ue_context_p->ue_context.measurement_info->cellIndividualOffset[0];
  switch (cellIndividualOffset) {
  case -24: *cio = LTE_Q_OffsetRange_dB_24; break;
  case -22: *cio = LTE_Q_OffsetRange_dB_22; break;
  case -20: *cio = LTE_Q_OffsetRange_dB_20; break;
  case -18: *cio = LTE_Q_OffsetRange_dB_18; break;
  case -16: *cio = LTE_Q_OffsetRange_dB_16; break;
  case -14: *cio = LTE_Q_OffsetRange_dB_14; break;
  case -12: *cio = LTE_Q_OffsetRange_dB_12; break;
  case -10: *cio = LTE_Q_OffsetRange_dB_10; break;
  case -8:  *cio = LTE_Q_OffsetRange_dB_8;  break;
  case -6:  *cio = LTE_Q_OffsetRange_dB_6;  break;
  case -5:  *cio = LTE_Q_OffsetRange_dB_5;  break;
  case -4:  *cio = LTE_Q_OffsetRange_dB_4;  break;
  case -3:  *cio = LTE_Q_OffsetRange_dB_3;  break;
  case -2:  *cio = LTE_Q_OffsetRange_dB_2;  break;
  case -1:  *cio = LTE_Q_OffsetRange_dB_1;  break;
  case 0:   *cio = LTE_Q_OffsetRange_dB0;   break;
  case 1:   *cio = LTE_Q_OffsetRange_dB1;   break;
  case 2:   *cio = LTE_Q_OffsetRange_dB2;   break;
  case 3:   *cio = LTE_Q_OffsetRange_dB3;   break;
  case 4:   *cio = LTE_Q_OffsetRange_dB4;   break;
  case 5:   *cio = LTE_Q_OffsetRange_dB5;   break;
  case 6:   *cio = LTE_Q_OffsetRange_dB6;   break;
  case 8:   *cio = LTE_Q_OffsetRange_dB8;   break;
  case 10:  *cio = LTE_Q_OffsetRange_dB10;  break;
  case 12:  *cio = LTE_Q_OffsetRange_dB12;  break;
  case 14:  *cio = LTE_Q_OffsetRange_dB14;  break;
  case 16:  *cio = LTE_Q_OffsetRange_dB16;  break;
  case 18:  *cio = LTE_Q_OffsetRange_dB18;  break;
  case 20:  *cio = LTE_Q_OffsetRange_dB20;  break;
  case 22:  *cio = LTE_Q_OffsetRange_dB22;  break;
  case 24:  *cio = LTE_Q_OffsetRange_dB24;  break;
  default:                                  return -1;
  }
  return 0;
}

int flexran_set_rrc_ocn(mid_t mod_id, rnti_t rnti, long cell_id, long cellIndividualOffset) {
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measurement_info) return -1;
  LTE_Q_OffsetRange_t *cio = &ue_context_p->ue_context.measurement_info->cellIndividualOffset[cell_id+1];
  switch (cellIndividualOffset) {
  case -24: *cio = LTE_Q_OffsetRange_dB_24; break;
  case -22: *cio = LTE_Q_OffsetRange_dB_22; break;
  case -20: *cio = LTE_Q_OffsetRange_dB_20; break;
  case -18: *cio = LTE_Q_OffsetRange_dB_18; break;
  case -16: *cio = LTE_Q_OffsetRange_dB_16; break;
  case -14: *cio = LTE_Q_OffsetRange_dB_14; break;
  case -12: *cio = LTE_Q_OffsetRange_dB_12; break;
  case -10: *cio = LTE_Q_OffsetRange_dB_10; break;
  case -8:  *cio = LTE_Q_OffsetRange_dB_8;  break;
  case -6:  *cio = LTE_Q_OffsetRange_dB_6;  break;
  case -5:  *cio = LTE_Q_OffsetRange_dB_5;  break;
  case -4:  *cio = LTE_Q_OffsetRange_dB_4;  break;
  case -3:  *cio = LTE_Q_OffsetRange_dB_3;  break;
  case -2:  *cio = LTE_Q_OffsetRange_dB_2;  break;
  case -1:  *cio = LTE_Q_OffsetRange_dB_1;  break;
  case 0:   *cio = LTE_Q_OffsetRange_dB0;   break;
  case 1:   *cio = LTE_Q_OffsetRange_dB1;   break;
  case 2:   *cio = LTE_Q_OffsetRange_dB2;   break;
  case 3:   *cio = LTE_Q_OffsetRange_dB3;   break;
  case 4:   *cio = LTE_Q_OffsetRange_dB4;   break;
  case 5:   *cio = LTE_Q_OffsetRange_dB5;   break;
  case 6:   *cio = LTE_Q_OffsetRange_dB6;   break;
  case 8:   *cio = LTE_Q_OffsetRange_dB8;   break;
  case 10:  *cio = LTE_Q_OffsetRange_dB10;  break;
  case 12:  *cio = LTE_Q_OffsetRange_dB12;  break;
  case 14:  *cio = LTE_Q_OffsetRange_dB14;  break;
  case 16:  *cio = LTE_Q_OffsetRange_dB16;  break;
  case 18:  *cio = LTE_Q_OffsetRange_dB18;  break;
  case 20:  *cio = LTE_Q_OffsetRange_dB20;  break;
  case 22:  *cio = LTE_Q_OffsetRange_dB22;  break;
  case 24:  *cio = LTE_Q_OffsetRange_dB24;  break;
  default:                                  return -1;
  }
  return 0;
}

int flexran_set_filter_coeff_rsrp(mid_t mod_id, rnti_t rnti, long filterCoefficientRSRP) {
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measurement_info) return -1;
  LTE_FilterCoefficient_t *fc = &ue_context_p->ue_context.measurement_info->filterCoefficientRSRP;
  switch (filterCoefficientRSRP) {
  case 0:  *fc = LTE_FilterCoefficient_fc0;    break;
  case 1:  *fc = LTE_FilterCoefficient_fc1;    break;
  case 2:  *fc = LTE_FilterCoefficient_fc2;    break;
  case 3:  *fc = LTE_FilterCoefficient_fc3;    break;
  case 4:  *fc = LTE_FilterCoefficient_fc4;    break;
  case 5:  *fc = LTE_FilterCoefficient_fc5;    break;
  case 6:  *fc = LTE_FilterCoefficient_fc6;    break;
  case 7:  *fc = LTE_FilterCoefficient_fc7;    break;
  case 8:  *fc = LTE_FilterCoefficient_fc8;    break;
  case 9:  *fc = LTE_FilterCoefficient_fc9;    break;
  case 11: *fc = LTE_FilterCoefficient_fc11;   break;
  case 13: *fc = LTE_FilterCoefficient_fc13;   break;
  case 15: *fc = LTE_FilterCoefficient_fc15;   break;
  case 17: *fc = LTE_FilterCoefficient_fc17;   break;
  case 19: *fc = LTE_FilterCoefficient_fc19;   break;
  case -1: *fc = LTE_FilterCoefficient_spare1; break;
  default:                                     return -1;
  }
  return 0;
}

int flexran_set_filter_coeff_rsrq(mid_t mod_id, rnti_t rnti, long filterCoefficientRSRQ) {
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measurement_info) return -1;
  LTE_FilterCoefficient_t *fc = &ue_context_p->ue_context.measurement_info->filterCoefficientRSRQ;
  switch (filterCoefficientRSRQ) {
  case 0:  *fc = LTE_FilterCoefficient_fc0;    break;
  case 1:  *fc = LTE_FilterCoefficient_fc1;    break;
  case 2:  *fc = LTE_FilterCoefficient_fc2;    break;
  case 3:  *fc = LTE_FilterCoefficient_fc3;    break;
  case 4:  *fc = LTE_FilterCoefficient_fc4;    break;
  case 5:  *fc = LTE_FilterCoefficient_fc5;    break;
  case 6:  *fc = LTE_FilterCoefficient_fc6;    break;
  case 7:  *fc = LTE_FilterCoefficient_fc7;    break;
  case 8:  *fc = LTE_FilterCoefficient_fc8;    break;
  case 9:  *fc = LTE_FilterCoefficient_fc9;    break;
  case 11: *fc = LTE_FilterCoefficient_fc11;   break;
  case 13: *fc = LTE_FilterCoefficient_fc13;   break;
  case 15: *fc = LTE_FilterCoefficient_fc15;   break;
  case 17: *fc = LTE_FilterCoefficient_fc17;   break;
  case 19: *fc = LTE_FilterCoefficient_fc19;   break;
  case -1: *fc = LTE_FilterCoefficient_spare1; break;
  default:                                     return -1;
  }
  return 0;
}

/* Periodic event */

int flexran_set_rrc_per_event_maxReportCells(mid_t mod_id, rnti_t rnti, long maxReportCells) {
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measurement_info) return -1;
  if (!ue_context_p->ue_context.measurement_info->events) return -1;
  if (!ue_context_p->ue_context.measurement_info->events->per_event) return -1;
1991
  if (!((maxReportCells >= 1) && (maxReportCells <= 8))) return -1;
1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004
  ue_context_p->ue_context.measurement_info->events->per_event->maxReportCells = maxReportCells;
  return 0;
}

/* A3 event */

int flexran_set_rrc_a3_event_hysteresis(mid_t mod_id, rnti_t rnti, long hysteresis) {
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measurement_info) return -1;
  if (!ue_context_p->ue_context.measurement_info->events) return -1;
  if (!ue_context_p->ue_context.measurement_info->events->a3_event) return -1;
2005
  if (!((hysteresis >=0) && (hysteresis <= 30))) return -1;
2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046
  ue_context_p->ue_context.measurement_info->events->a3_event->hysteresis = hysteresis;
  return 0;
}

int flexran_set_rrc_a3_event_timeToTrigger(mid_t mod_id, rnti_t rnti, long timeToTrigger) {
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measurement_info) return -1;
  if (!ue_context_p->ue_context.measurement_info->events) return -1;
  if (!ue_context_p->ue_context.measurement_info->events->a3_event) return -1;
  LTE_TimeToTrigger_t *ttt = &ue_context_p->ue_context.measurement_info->events->a3_event->timeToTrigger;
  switch (timeToTrigger) {
  case 0:    *ttt = LTE_TimeToTrigger_ms0;    break;
  case 40:   *ttt = LTE_TimeToTrigger_ms40;   break;
  case 64:   *ttt = LTE_TimeToTrigger_ms64;   break;
  case 80:   *ttt = LTE_TimeToTrigger_ms80;   break;
  case 100:  *ttt = LTE_TimeToTrigger_ms100;  break;
  case 128:  *ttt = LTE_TimeToTrigger_ms128;  break;
  case 160:  *ttt = LTE_TimeToTrigger_ms160;  break;
  case 256:  *ttt = LTE_TimeToTrigger_ms256;  break;
  case 320:  *ttt = LTE_TimeToTrigger_ms320;  break;
  case 480:  *ttt = LTE_TimeToTrigger_ms480;  break;
  case 512:  *ttt = LTE_TimeToTrigger_ms512;  break;
  case 640:  *ttt = LTE_TimeToTrigger_ms640;  break;
  case 1024: *ttt = LTE_TimeToTrigger_ms1024; break;
  case 1280: *ttt = LTE_TimeToTrigger_ms1280; break;
  case 2560: *ttt = LTE_TimeToTrigger_ms2560; break;
  case 5120: *ttt = LTE_TimeToTrigger_ms5120; break;
  default:                                    return -1;
  }
  return 0;
}

int flexran_set_rrc_a3_event_maxReportCells(mid_t mod_id, rnti_t rnti, long maxReportCells) {
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measurement_info) return -1;
  if (!ue_context_p->ue_context.measurement_info->events) return -1;
  if (!ue_context_p->ue_context.measurement_info->events->a3_event) return -1;
2047
  if (!((maxReportCells >= 1) && (maxReportCells <= 8))) return -1;
2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058
  ue_context_p->ue_context.measurement_info->events->a3_event->maxReportCells = maxReportCells;
  return 0;
}

int flexran_set_rrc_a3_event_a3_offset(mid_t mod_id, rnti_t rnti, long a3_offset) {
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measurement_info) return -1;
  if (!ue_context_p->ue_context.measurement_info->events) return -1;
  if (!ue_context_p->ue_context.measurement_info->events->a3_event) return -1;
2059
  if (!((a3_offset >= -30) && (a3_offset <= 30))) return -1;
2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070
  ue_context_p->ue_context.measurement_info->events->a3_event->a3_offset = a3_offset;
  return 0;
}

int flexran_set_rrc_a3_event_reportOnLeave(mid_t mod_id, rnti_t rnti, int reportOnLeave) {
  if (!rrc_is_present(mod_id)) return -1;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return -1;
  if (!ue_context_p->ue_context.measurement_info) return -1;
  if (!ue_context_p->ue_context.measurement_info->events) return -1;
  if (!ue_context_p->ue_context.measurement_info->events->a3_event) return -1;
2071
  if (!((reportOnLeave == 0) || (reportOnLeave == 1))) return -1;
2072 2073 2074 2075
  ue_context_p->ue_context.measurement_info->events->a3_event->reportOnLeave = reportOnLeave;
  return 0;
}

2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087
int flexran_set_x2_ho_net_control(mid_t mod_id, int x2_ho_net_control) {
  if (!rrc_is_present(mod_id)) return -1;
  if (!((x2_ho_net_control == 0) || (x2_ho_net_control == 1))) return -1;
  RC.rrc[mod_id]->x2_ho_net_control = x2_ho_net_control;
  return 0;
}

int flexran_get_x2_ho_net_control(mid_t mod_id) {
  if (!rrc_is_present(mod_id)) return -1;
  return RC.rrc[mod_id]->x2_ho_net_control;
}

2088
uint8_t flexran_get_rrc_num_plmn_ids(mid_t mod_id) {
2089 2090 2091 2092
  if (!rrc_is_present(mod_id)) return 0;
  return RC.rrc[mod_id]->configuration.num_plmn;
}

2093
uint16_t flexran_get_rrc_mcc(mid_t mod_id, uint8_t index) {
2094 2095 2096 2097
  if (!rrc_is_present(mod_id)) return 0;
  return RC.rrc[mod_id]->configuration.mcc[index];
}

2098
uint16_t flexran_get_rrc_mnc(mid_t mod_id, uint8_t index) {
2099 2100 2101 2102
  if (!rrc_is_present(mod_id)) return 0;
  return RC.rrc[mod_id]->configuration.mnc[index];
}

2103
uint8_t flexran_get_rrc_mnc_digit_length(mid_t mod_id, uint8_t index) {
2104 2105 2106 2107
  if (!rrc_is_present(mod_id)) return 0;
  return RC.rrc[mod_id]->configuration.mnc_digit_length[index];
}

2108 2109 2110 2111 2112
int flexran_get_rrc_num_adj_cells(mid_t mod_id) {
  if (!rrc_is_present(mod_id)) return 0;
  return RC.rrc[mod_id]->num_neigh_cells;
}

2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140
int flexran_agent_rrc_gtp_num_e_rab(mid_t mod_id, rnti_t rnti) {
  if (!rrc_is_present(mod_id)) return 0;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return 0;
  return ue_context_p->ue_context.setup_e_rabs;
}

int flexran_agent_rrc_gtp_get_e_rab_id(mid_t mod_id, rnti_t rnti, int index) {
  if (!rrc_is_present(mod_id)) return 0;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return 0;
  return ue_context_p->ue_context.e_rab[index].param.e_rab_id;
}

int flexran_agent_rrc_gtp_get_teid_enb(mid_t mod_id, rnti_t rnti, int index) {
  if (!rrc_is_present(mod_id)) return 0;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return 0;
  return ue_context_p->ue_context.enb_gtp_teid[index];
}

int flexran_agent_rrc_gtp_get_teid_sgw(mid_t mod_id, rnti_t rnti, int index) {
  if (!rrc_is_present(mod_id)) return 0;
  struct rrc_eNB_ue_context_s* ue_context_p = rrc_eNB_get_ue_context(RC.rrc[mod_id], rnti);
  if (!ue_context_p) return 0;
  return ue_context_p->ue_context.e_rab[index].param.gtp_teid;
}

2141
/**************************** SLICING ****************************/
2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153
int flexran_get_ue_dl_slice_id(mid_t mod_id, mid_t ue_id)
{
  if (!mac_is_present(mod_id)) return -1;
  int slice_idx = RC.mac[mod_id]->UE_list.assoc_dl_slice_idx[ue_id];
  if (slice_idx >= 0 && slice_idx < RC.mac[mod_id]->slice_info.n_dl)
    return RC.mac[mod_id]->slice_info.dl[slice_idx].id;
  return 0;
}

void flexran_set_ue_dl_slice_idx(mid_t mod_id, mid_t ue_id, int slice_idx)
{
  if (!mac_is_present(mod_id)) return;
2154
  if (flexran_get_mac_ue_crnti(mod_id, ue_id) == NOT_A_RNTI) return;
2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170
  if (!flexran_dl_slice_exists(mod_id, slice_idx)) return;
  RC.mac[mod_id]->UE_list.assoc_dl_slice_idx[ue_id] = slice_idx;
}

int flexran_get_ue_ul_slice_id(mid_t mod_id, mid_t ue_id)
{
  if (!mac_is_present(mod_id)) return -1;
  int slice_idx = RC.mac[mod_id]->UE_list.assoc_ul_slice_idx[ue_id];
  if (slice_idx >= 0 && slice_idx < RC.mac[mod_id]->slice_info.n_ul)
    return RC.mac[mod_id]->slice_info.ul[slice_idx].id;
  return 0;
}

void flexran_set_ue_ul_slice_idx(mid_t mod_id, mid_t ue_id, int slice_idx)
{
  if (!mac_is_present(mod_id)) return;
2171
  if (flexran_get_mac_ue_crnti(mod_id, ue_id) == NOT_A_RNTI) return;
2172 2173 2174 2175 2176 2177 2178 2179 2180 2181
  if (!flexran_ul_slice_exists(mod_id, slice_idx)) return;
  RC.mac[mod_id]->UE_list.assoc_ul_slice_idx[ue_id] = slice_idx;
}

int flexran_dl_slice_exists(mid_t mod_id, int slice_idx)
{
  if (!mac_is_present(mod_id)) return -1;
  return slice_idx >= 0 && slice_idx < RC.mac[mod_id]->slice_info.n_dl;
}

2182
int flexran_create_dl_slice(mid_t mod_id, slice_id_t slice_id)
2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208
{
  if (!mac_is_present(mod_id)) return -1;
  int newidx = RC.mac[mod_id]->slice_info.n_dl;
  if (newidx >= MAX_NUM_SLICES) return -1;
  ++RC.mac[mod_id]->slice_info.n_dl;
  flexran_set_dl_slice_id(mod_id, newidx, slice_id);
  return newidx;
}

int flexran_find_dl_slice(mid_t mod_id, slice_id_t slice_id)
{
  if (!mac_is_present(mod_id)) return -1;
  slice_info_t *sli = &RC.mac[mod_id]->slice_info;
  int n = sli->n_dl;
  for (int i = 0; i < n; i++) {
    if (sli->dl[i].id == slice_id) return i;
  }
  return -1;
}

int flexran_remove_dl_slice(mid_t mod_id, int slice_idx)
{
  if (!mac_is_present(mod_id)) return -1;
  slice_info_t *sli = &RC.mac[mod_id]->slice_info;
  if (sli->n_dl <= 1) return -1;

2209
  if (sli->dl[slice_idx].sched_name) free(sli->dl[slice_idx].sched_name);
2210 2211 2212 2213
  --sli->n_dl;
  /* move last element to the position of the removed one */
  if (slice_idx != sli->n_dl)
    memcpy(&sli->dl[slice_idx], &sli->dl[sli->n_dl], sizeof(sli->dl[sli->n_dl]));
2214
  memset(&sli->dl[sli->n_dl], 0, sizeof(sli->dl[sli->n_dl]));
2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427

  /* all UEs that have been in the old slice are put into slice index 0 */
  int *assoc_list = RC.mac[mod_id]->UE_list.assoc_dl_slice_idx;
  for (int i = 0; i < MAX_MOBILES_PER_ENB; ++i) {
    if (assoc_list[i] == slice_idx)
      assoc_list[i] = 0;
  }
  return sli->n_dl;
}

int flexran_get_num_dl_slices(mid_t mod_id)
{
  if (!mac_is_present(mod_id)) return -1;
  return RC.mac[mod_id]->slice_info.n_dl;
}

int flexran_get_intraslice_sharing_active(mid_t mod_id)
{
  if (!mac_is_present(mod_id)) return -1;
  return RC.mac[mod_id]->slice_info.intraslice_share_active;
}
void flexran_set_intraslice_sharing_active(mid_t mod_id, int intraslice_active)
{
  if (!mac_is_present(mod_id)) return;
  RC.mac[mod_id]->slice_info.intraslice_share_active = intraslice_active;
}

int flexran_get_interslice_sharing_active(mid_t mod_id)
{
  if (!mac_is_present(mod_id)) return -1;
  return RC.mac[mod_id]->slice_info.interslice_share_active;
}
void flexran_set_interslice_sharing_active(mid_t mod_id, int interslice_active)
{
  if (!mac_is_present(mod_id)) return;
  RC.mac[mod_id]->slice_info.interslice_share_active = interslice_active;
}

slice_id_t flexran_get_dl_slice_id(mid_t mod_id, int slice_idx)
{
  if (!mac_is_present(mod_id)) return -1;
  return RC.mac[mod_id]->slice_info.dl[slice_idx].id;
}
void flexran_set_dl_slice_id(mid_t mod_id, int slice_idx, slice_id_t slice_id)
{
  if (!mac_is_present(mod_id)) return;
  RC.mac[mod_id]->slice_info.dl[slice_idx].id = slice_id;
}

int flexran_get_dl_slice_percentage(mid_t mod_id, int slice_idx)
{
  if (!mac_is_present(mod_id)) return -1;
  return RC.mac[mod_id]->slice_info.dl[slice_idx].pct * 100.0f;
}
void flexran_set_dl_slice_percentage(mid_t mod_id, int slice_idx, int percentage)
{
  if (!mac_is_present(mod_id)) return;
  RC.mac[mod_id]->slice_info.dl[slice_idx].pct = percentage / 100.0f;
}

int flexran_get_dl_slice_isolation(mid_t mod_id, int slice_idx)
{
  if (!mac_is_present(mod_id)) return -1;
  return RC.mac[mod_id]->slice_info.dl[slice_idx].isol;
}
void flexran_set_dl_slice_isolation(mid_t mod_id, int slice_idx, int is_isolated)
{
  if (!mac_is_present(mod_id)) return;
  RC.mac[mod_id]->slice_info.dl[slice_idx].isol = is_isolated;
}

int flexran_get_dl_slice_priority(mid_t mod_id, int slice_idx)
{
  if (!mac_is_present(mod_id)) return -1;
  return RC.mac[mod_id]->slice_info.dl[slice_idx].prio;
}
void flexran_set_dl_slice_priority(mid_t mod_id, int slice_idx, int priority)
{
  if (!mac_is_present(mod_id)) return;
  RC.mac[mod_id]->slice_info.dl[slice_idx].prio = priority;
}

int flexran_get_dl_slice_position_low(mid_t mod_id, int slice_idx)
{
  if (!mac_is_present(mod_id)) return -1;
  return RC.mac[mod_id]->slice_info.dl[slice_idx].pos_low;
}
void flexran_set_dl_slice_position_low(mid_t mod_id, int slice_idx, int poslow)
{
  if (!mac_is_present(mod_id)) return;
  RC.mac[mod_id]->slice_info.dl[slice_idx].pos_low = poslow;
}

int flexran_get_dl_slice_position_high(mid_t mod_id, int slice_idx)
{
  if (!mac_is_present(mod_id)) return -1;
  return RC.mac[mod_id]->slice_info.dl[slice_idx].pos_high;
}
void flexran_set_dl_slice_position_high(mid_t mod_id, int slice_idx, int poshigh)
{
  if (!mac_is_present(mod_id)) return;
  RC.mac[mod_id]->slice_info.dl[slice_idx].pos_high = poshigh;
}

int flexran_get_dl_slice_maxmcs(mid_t mod_id, int slice_idx)
{
  if (!mac_is_present(mod_id)) return -1;
  return RC.mac[mod_id]->slice_info.dl[slice_idx].maxmcs;
}
void flexran_set_dl_slice_maxmcs(mid_t mod_id, int slice_idx, int maxmcs)
{
  if (!mac_is_present(mod_id)) return;
  RC.mac[mod_id]->slice_info.dl[slice_idx].maxmcs = maxmcs;
}

int flexran_get_dl_slice_sorting(mid_t mod_id, int slice_idx, Protocol__FlexDlSorting **sorting_list)
{
  if (!mac_is_present(mod_id)) return -1;
  if (!(*sorting_list)) {
    *sorting_list = calloc(CR_NUM, sizeof(Protocol__FlexDlSorting));
    if (!(*sorting_list)) return -1;
  }
  uint32_t policy = RC.mac[mod_id]->slice_info.dl[slice_idx].sorting;
  for (int i = 0; i < CR_NUM; i++) {
    switch (policy >> 4 * (CR_NUM - 1 - i) & 0xF) {
    case CR_ROUND:
      (*sorting_list)[i] = PROTOCOL__FLEX_DL_SORTING__CR_ROUND;
      break;
    case CR_SRB12:
      (*sorting_list)[i] = PROTOCOL__FLEX_DL_SORTING__CR_SRB12;
      break;
    case CR_HOL:
      (*sorting_list)[i] = PROTOCOL__FLEX_DL_SORTING__CR_HOL;
      break;
    case CR_LC:
      (*sorting_list)[i] = PROTOCOL__FLEX_DL_SORTING__CR_LC;
      break;
    case CR_CQI:
      (*sorting_list)[i] = PROTOCOL__FLEX_DL_SORTING__CR_CQI;
      break;
    case CR_LCP:
      (*sorting_list)[i] = PROTOCOL__FLEX_DL_SORTING__CR_LCP;
      break;
    default:
      /* this should not happen, but a "default" */
      (*sorting_list)[i] = PROTOCOL__FLEX_DL_SORTING__CR_ROUND;
      break;
    }
  }
  return CR_NUM;
}
void flexran_set_dl_slice_sorting(mid_t mod_id, int slice_idx, Protocol__FlexDlSorting *sorting_list, int n)
{
  if (!mac_is_present(mod_id)) return;
  uint32_t policy = 0;
  for (int i = 0; i < n && i < CR_NUM; i++) {
    switch (sorting_list[i]) {
    case PROTOCOL__FLEX_DL_SORTING__CR_ROUND:
      policy = policy << 4 | CR_ROUND;
      break;
    case PROTOCOL__FLEX_DL_SORTING__CR_SRB12:
      policy = policy << 4 | CR_SRB12;
      break;
    case PROTOCOL__FLEX_DL_SORTING__CR_HOL:
      policy = policy << 4 | CR_HOL;
      break;
    case PROTOCOL__FLEX_DL_SORTING__CR_LC:
      policy = policy << 4 | CR_LC;
      break;
    case PROTOCOL__FLEX_DL_SORTING__CR_CQI:
      policy = policy << 4 | CR_CQI;
      break;
    case PROTOCOL__FLEX_DL_SORTING__CR_LCP:
      policy = policy << 4 | CR_LCP;
      break;
    default: /* suppresses warnings */
      policy = policy << 4 | CR_ROUND;
      break;
    }
  }
  /* fill up with 0 == CR_ROUND */
  if (CR_NUM > n) policy = policy << 4 * (CR_NUM - n);
  RC.mac[mod_id]->slice_info.dl[slice_idx].sorting = policy;
}

Protocol__FlexDlAccountingPolicy flexran_get_dl_slice_accounting_policy(mid_t mod_id, int slice_idx)
{
  if (!mac_is_present(mod_id)) return PROTOCOL__FLEX_DL_ACCOUNTING_POLICY__POL_FAIR;
  switch (RC.mac[mod_id]->slice_info.dl[slice_idx].accounting) {
  case POL_FAIR:
    return PROTOCOL__FLEX_DL_ACCOUNTING_POLICY__POL_FAIR;
  case POL_GREEDY:
    return PROTOCOL__FLEX_DL_ACCOUNTING_POLICY__POL_GREEDY;
  default:
    return PROTOCOL__FLEX_DL_ACCOUNTING_POLICY__POL_FAIR;
  }
}
void flexran_set_dl_slice_accounting_policy(mid_t mod_id, int slice_idx, Protocol__FlexDlAccountingPolicy accounting)
{
  if (!mac_is_present(mod_id)) return;
  switch (accounting) {
  case PROTOCOL__FLEX_DL_ACCOUNTING_POLICY__POL_FAIR:
    RC.mac[mod_id]->slice_info.dl[slice_idx].accounting = POL_FAIR;
    return;
  case PROTOCOL__FLEX_DL_ACCOUNTING_POLICY__POL_GREEDY:
    RC.mac[mod_id]->slice_info.dl[slice_idx].accounting = POL_GREEDY;
    return;
  default:
    RC.mac[mod_id]->slice_info.dl[slice_idx].accounting = POL_FAIR;
    return;
  }
}

2428
char *flexran_get_dl_slice_scheduler(mid_t mod_id, int slice_idx)
2429 2430 2431 2432
{
  if (!mac_is_present(mod_id)) return NULL;
  return RC.mac[mod_id]->slice_info.dl[slice_idx].sched_name;
}
2433
int flexran_set_dl_slice_scheduler(mid_t mod_id, int slice_idx, char *name)
2434
{
2435
  if (!mac_is_present(mod_id)) return 0;
2436 2437
  if (RC.mac[mod_id]->slice_info.dl[slice_idx].sched_name)
    free(RC.mac[mod_id]->slice_info.dl[slice_idx].sched_name);
2438 2439 2440
  RC.mac[mod_id]->slice_info.dl[slice_idx].sched_name = strdup(name);
  RC.mac[mod_id]->slice_info.dl[slice_idx].sched_cb = dlsym(NULL, name);
  return RC.mac[mod_id]->slice_info.dl[slice_idx].sched_cb != NULL;
2441 2442
}

2443
int flexran_create_ul_slice(mid_t mod_id, slice_id_t slice_id)
2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469
{
  if (!mac_is_present(mod_id)) return -1;
  int newidx = RC.mac[mod_id]->slice_info.n_ul;
  if (newidx >= MAX_NUM_SLICES) return -1;
  ++RC.mac[mod_id]->slice_info.n_ul;
  flexran_set_ul_slice_id(mod_id, newidx, slice_id);
  return newidx;
}

int flexran_find_ul_slice(mid_t mod_id, slice_id_t slice_id)
{
  if (!mac_is_present(mod_id)) return -1;
  slice_info_t *sli = &RC.mac[mod_id]->slice_info;
  int n = sli->n_ul;
  for (int i = 0; i < n; i++) {
    if (sli->ul[i].id == slice_id) return i;
  }
  return -1;
}

int flexran_remove_ul_slice(mid_t mod_id, int slice_idx)
{
  if (!mac_is_present(mod_id)) return -1;
  slice_info_t *sli = &RC.mac[mod_id]->slice_info;
  if (sli->n_ul <= 1) return -1;

2470
  if (sli->ul[slice_idx].sched_name) free(sli->ul[slice_idx].sched_name);
2471 2472 2473 2474
  --sli->n_ul;
  /* move last element to the position of the removed one */
  if (slice_idx != sli->n_ul)
    memcpy(&sli->ul[slice_idx], &sli->ul[sli->n_ul], sizeof(sli->ul[sli->n_ul]));
2475
  memset(&sli->ul[sli->n_ul], 0, sizeof(sli->ul[sli->n_ul]));
2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542

  /* all UEs that have been in the old slice are put into slice index 0 */
  int *assoc_list = RC.mac[mod_id]->UE_list.assoc_ul_slice_idx;
  for (int i = 0; i < MAX_MOBILES_PER_ENB; ++i) {
    if (assoc_list[i] == slice_idx)
      assoc_list[i] = 0;
  }
  return sli->n_ul;
}

int flexran_get_num_ul_slices(mid_t mod_id)
{
  if (!mac_is_present(mod_id)) return -1;
  return RC.mac[mod_id]->slice_info.n_ul;
}

int flexran_ul_slice_exists(mid_t mod_id, int slice_idx)
{
  if (!mac_is_present(mod_id)) return -1;
  return slice_idx >= 0 && slice_idx < RC.mac[mod_id]->slice_info.n_ul;
}

slice_id_t flexran_get_ul_slice_id(mid_t mod_id, int slice_idx)
{
  if (!mac_is_present(mod_id)) return -1;
  return RC.mac[mod_id]->slice_info.ul[slice_idx].id;
}
void flexran_set_ul_slice_id(mid_t mod_id, int slice_idx, slice_id_t slice_id)
{
  if (!mac_is_present(mod_id)) return;
  RC.mac[mod_id]->slice_info.ul[slice_idx].id = slice_id;
}

int flexran_get_ul_slice_percentage(mid_t mod_id, int slice_idx)
{
  if (!mac_is_present(mod_id)) return -1;
  return RC.mac[mod_id]->slice_info.ul[slice_idx].pct * 100.0f;
}
void flexran_set_ul_slice_percentage(mid_t mod_id, int slice_idx, int percentage)
{
  if (!mac_is_present(mod_id)) return;
  RC.mac[mod_id]->slice_info.ul[slice_idx].pct = percentage / 100.0f;
}

int flexran_get_ul_slice_first_rb(mid_t mod_id, int slice_idx)
{
  if (!mac_is_present(mod_id)) return -1;
  return RC.mac[mod_id]->slice_info.ul[slice_idx].first_rb;
}

void flexran_set_ul_slice_first_rb(mid_t mod_id, int slice_idx, int first_rb)
{
  if (!mac_is_present(mod_id)) return;
  RC.mac[mod_id]->slice_info.ul[slice_idx].first_rb = first_rb;
}

int flexran_get_ul_slice_maxmcs(mid_t mod_id, int slice_idx)
{
  if (!mac_is_present(mod_id)) return -1;
  return RC.mac[mod_id]->slice_info.ul[slice_idx].maxmcs;
}
void flexran_set_ul_slice_maxmcs(mid_t mod_id, int slice_idx, int maxmcs)
{
  if (!mac_is_present(mod_id)) return;
  RC.mac[mod_id]->slice_info.ul[slice_idx].maxmcs = maxmcs;
}

2543
char *flexran_get_ul_slice_scheduler(mid_t mod_id, int slice_idx)
2544 2545 2546 2547
{
  if (!mac_is_present(mod_id)) return NULL;
  return RC.mac[mod_id]->slice_info.ul[slice_idx].sched_name;
}
2548
int flexran_set_ul_slice_scheduler(mid_t mod_id, int slice_idx, char *name)
2549
{
2550
  if (!mac_is_present(mod_id)) return 0;
2551 2552
  if (RC.mac[mod_id]->slice_info.ul[slice_idx].sched_name)
    free(RC.mac[mod_id]->slice_info.ul[slice_idx].sched_name);
2553 2554 2555
  RC.mac[mod_id]->slice_info.ul[slice_idx].sched_name = strdup(name);
  RC.mac[mod_id]->slice_info.ul[slice_idx].sched_cb = dlsym(NULL, name);
  return RC.mac[mod_id]->slice_info.ul[slice_idx].sched_cb != NULL;
2556
}
2557 2558

/**************************** General BS info  ****************************/
2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609
uint64_t flexran_get_bs_id(mid_t mod_id)
{
  if (!rrc_is_present(mod_id)) return 0;
  return RC.rrc[mod_id]->nr_cellid;
}

size_t flexran_get_capabilities(mid_t mod_id, Protocol__FlexBsCapability **caps)
{
  if (!caps) return 0;
  if (!rrc_is_present(mod_id)) return 0;
  size_t n_caps = 0;
  switch (RC.rrc[mod_id]->node_type) {
  case ngran_eNB_CU:
  case ngran_ng_eNB_CU:
  case ngran_gNB_CU:
    n_caps = 3;
    *caps = calloc(n_caps, sizeof(Protocol__FlexBsCapability));
    AssertFatal(*caps, "could not allocate %zu bytes for Protocol__FlexBsCapability array\n",
                n_caps * sizeof(Protocol__FlexBsCapability));
    (*caps)[0] = PROTOCOL__FLEX_BS_CAPABILITY__PDCP;
    (*caps)[1] = PROTOCOL__FLEX_BS_CAPABILITY__SDAP;
    (*caps)[2] = PROTOCOL__FLEX_BS_CAPABILITY__RRC;
    break;
  case ngran_eNB_DU:
  case ngran_gNB_DU:
    n_caps = 5;
    *caps = calloc(n_caps, sizeof(Protocol__FlexBsCapability));
    AssertFatal(*caps, "could not allocate %zu bytes for Protocol__FlexBsCapability array\n",
                n_caps * sizeof(Protocol__FlexBsCapability));
    (*caps)[0] = PROTOCOL__FLEX_BS_CAPABILITY__LOPHY;
    (*caps)[1] = PROTOCOL__FLEX_BS_CAPABILITY__HIPHY;
    (*caps)[2] = PROTOCOL__FLEX_BS_CAPABILITY__LOMAC;
    (*caps)[3] = PROTOCOL__FLEX_BS_CAPABILITY__HIMAC;
    (*caps)[4] = PROTOCOL__FLEX_BS_CAPABILITY__RLC;
    break;
  case ngran_eNB:
  case ngran_ng_eNB:
  case ngran_gNB:
    n_caps = 8;
    *caps = calloc(n_caps, sizeof(Protocol__FlexBsCapability));
    AssertFatal(*caps, "could not allocate %zu bytes for Protocol__FlexBsCapability array\n",
                n_caps * sizeof(Protocol__FlexBsCapability));
    (*caps)[0] = PROTOCOL__FLEX_BS_CAPABILITY__LOPHY;
    (*caps)[1] = PROTOCOL__FLEX_BS_CAPABILITY__HIPHY;
    (*caps)[2] = PROTOCOL__FLEX_BS_CAPABILITY__LOMAC;
    (*caps)[3] = PROTOCOL__FLEX_BS_CAPABILITY__HIMAC;
    (*caps)[4] = PROTOCOL__FLEX_BS_CAPABILITY__RLC;
    (*caps)[5] = PROTOCOL__FLEX_BS_CAPABILITY__PDCP;
    (*caps)[6] = PROTOCOL__FLEX_BS_CAPABILITY__SDAP;
    (*caps)[7] = PROTOCOL__FLEX_BS_CAPABILITY__RRC;
    break;
2610 2611
  case ngran_eNB_MBMS_STA:
   break;
2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647
  }
  return n_caps;
}

uint16_t flexran_get_capabilities_mask(mid_t mod_id)
{
  if (!rrc_is_present(mod_id)) return 0;
  uint16_t mask = 0;
  switch (RC.rrc[mod_id]->node_type) {
  case ngran_eNB_CU:
  case ngran_ng_eNB_CU:
  case ngran_gNB_CU:
    mask = (1 << PROTOCOL__FLEX_BS_CAPABILITY__PDCP)
         | (1 << PROTOCOL__FLEX_BS_CAPABILITY__SDAP)
         | (1 << PROTOCOL__FLEX_BS_CAPABILITY__RRC);
    break;
  case ngran_eNB_DU:
  case ngran_gNB_DU:
    mask = (1 << PROTOCOL__FLEX_BS_CAPABILITY__LOPHY)
         | (1 << PROTOCOL__FLEX_BS_CAPABILITY__HIPHY)
         | (1 << PROTOCOL__FLEX_BS_CAPABILITY__LOMAC)
         | (1 << PROTOCOL__FLEX_BS_CAPABILITY__HIMAC)
         | (1 << PROTOCOL__FLEX_BS_CAPABILITY__RLC);
    break;
  case ngran_eNB:
  case ngran_ng_eNB:
  case ngran_gNB:
    mask = (1 << PROTOCOL__FLEX_BS_CAPABILITY__LOPHY)
         | (1 << PROTOCOL__FLEX_BS_CAPABILITY__HIPHY)
         | (1 << PROTOCOL__FLEX_BS_CAPABILITY__LOMAC)
         | (1 << PROTOCOL__FLEX_BS_CAPABILITY__HIMAC)
         | (1 << PROTOCOL__FLEX_BS_CAPABILITY__RLC)
         | (1 << PROTOCOL__FLEX_BS_CAPABILITY__PDCP)
         | (1 << PROTOCOL__FLEX_BS_CAPABILITY__SDAP)
         | (1 << PROTOCOL__FLEX_BS_CAPABILITY__RRC);
    break;
2648 2649
  case ngran_eNB_MBMS_STA:
   break;
2650 2651 2652
  }
  return mask;
}