rrc_common.c 18 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The OpenAirInterface Software Alliance licenses this file to You under
 * the OAI Public License, Version 1.0  (the "License"); you may not use this file
 * except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.openairinterface.org/?page_id=698
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *-------------------------------------------------------------------------------
 * For more information about the OpenAirInterface (OAI) Software Alliance:
 *      contact@openairinterface.org
 */

22
/*! \file rrc_common.c
23
 * \brief rrc common procedures for eNB and UE
24 25
 * \author Navid Nikaein and Raymond Knopp
 * \date 2011 - 2014
26 27
 * \version 1.0
 * \company Eurecom
28
 * \email:  navid.nikaein@eurecom.fr and raymond.knopp@eurecom.fr
29
 */
30 31 32 33 34

#include "defs.h"
#include "extern.h"
#include "LAYER2/MAC/extern.h"
#include "COMMON/openair_defs.h"
35
#include "COMMON/platform_types.h"
36 37 38 39
#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h"
#include "LAYER2/RLC/rlc.h"
#include "COMMON/mac_rrc_primitives.h"
#include "UTIL/LOG/log.h"
40
#include "asn1_msg.h"
41
#include "pdcp.h"
42
#include "UTIL/LOG/vcd_signal_dumper.h"
43
#include "rrc_eNB_UE_context.h"
44
#include "common/ran_context.h"
45

46
#ifdef LOCALIZATION
47 48 49
#include <sys/time.h>
#endif

50
#define DEBUG_RRC 1
51
extern RAN_CONTEXT_t RC;
52 53
extern UE_MAC_INST *UE_mac_inst;

54 55
extern mui_t rrc_eNB_mui;

56
//configure  BCCH & CCCH Logical Channels and associated rrc_buffers, configure associated SRBs
57 58 59 60 61 62
//-----------------------------------------------------------------------------
void
openair_rrc_on(
  const protocol_ctxt_t* const ctxt_pP
)
//-----------------------------------------------------------------------------
63
{
64
  unsigned short i;
65
  int            CC_id;
66

67 68 69
  if (ctxt_pP->enb_flag == ENB_FLAG_YES) {
    LOG_I(RRC, PROTOCOL_RRC_CTXT_FMT" OPENAIR RRC IN....\n",
          PROTOCOL_RRC_CTXT_ARGS(ctxt_pP));
70
    for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
71 72 73 74
      rrc_config_buffer (&RC.rrc[ctxt_pP->module_id]->carrier[CC_id].SI, BCCH, 1);
      RC.rrc[ctxt_pP->module_id]->carrier[CC_id].SI.Active = 1;
      rrc_config_buffer (&RC.rrc[ctxt_pP->module_id]->carrier[CC_id].Srb0, CCCH, 1);
      RC.rrc[ctxt_pP->module_id]->carrier[CC_id].Srb0.Active = 1;
75
    }
76
  } else {
77 78
    LOG_I(RRC, PROTOCOL_RRC_CTXT_FMT" OPENAIR RRC IN....\n",
          PROTOCOL_RRC_CTXT_ARGS(ctxt_pP));
79

80
    for (i = 0; i < NB_eNB_INST; i++) {
81 82 83 84 85 86 87
      LOG_D(RRC, PROTOCOL_RRC_CTXT_FMT" Activating CCCH (eNB %d)\n",
            PROTOCOL_RRC_CTXT_ARGS(ctxt_pP), i);
      UE_rrc_inst[ctxt_pP->module_id].Srb0[i].Srb_id = CCCH;
      memcpy (&UE_rrc_inst[ctxt_pP->module_id].Srb0[i].Lchan_desc[0], &CCCH_LCHAN_DESC, LCHAN_DESC_SIZE);
      memcpy (&UE_rrc_inst[ctxt_pP->module_id].Srb0[i].Lchan_desc[1], &CCCH_LCHAN_DESC, LCHAN_DESC_SIZE);
      rrc_config_buffer (&UE_rrc_inst[ctxt_pP->module_id].Srb0[i], CCCH, 1);
      UE_rrc_inst[ctxt_pP->module_id].Srb0[i].Active = 1;
88 89 90 91
    }
  }
}

92 93 94 95 96 97
//-----------------------------------------------------------------------------
int
rrc_init_global_param(
  void
)
//-----------------------------------------------------------------------------
98
{
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122

  //#ifdef USER_MODE
  //  Rrc_xface = (RRC_XFACE*)malloc16(sizeof(RRC_XFACE));
  //#endif //USRE_MODE

  //  Rrc_xface->openair_rrc_top_init = openair_rrc_top_init;
  //  Rrc_xface->openair_rrc_eNB_init = openair_rrc_eNB_init;
  //  Rrc_xface->openair_rrc_UE_init  = openair_rrc_ue_init;
  //  Rrc_xface->mac_rrc_data_ind     = mac_rrc_data_ind;
  //Rrc_xface->mac_rrc_data_req     = mac_rrc_data_req;
  // Rrc_xface->rrc_data_indP        = (void *)rlcrrc_data_ind;
  //  Rrc_xface->rrc_rx_tx            = rrc_rx_tx;
  //  Rrc_xface->mac_rrc_meas_ind     = mac_rrc_meas_ind;
  //  Rrc_xface->get_rrc_status       = get_rrc_status;

  //Rrc_xface->rrc_get_status = ...

  //  Mac_rlc_xface->mac_out_of_sync_ind=mac_out_of_sync_ind;

#ifndef NO_RRM
  //  Rrc_xface->fn_rrc=fn_rrc;
#endif
  //  LOG_D(RRC, "[RRC]INIT_GLOBAL_PARAM: Mac_rlc_xface %p, rrc_rlc_register %p,rlcrrc_data_ind%p\n",Mac_rlc_xface,Mac_rlc_xface->rrc_rlc_register_rrc,rlcrrc_data_ind);
  /*
123 124 125 126 127 128
   if((Mac_rlc_xface==NULL) || (Mac_rlc_xface->rrc_rlc_register_rrc==NULL) ||
   (rlcrrc_data_ind==NULL)) {
   LOG_E(RRC,"Data structured is not initialized \n");
   return -1;
   }
   */
129
  rrc_rlc_register_rrc (rrc_data_ind, NULL); //register with rlc
130 131 132 133 134 135 136 137 138 139 140

  DCCH_LCHAN_DESC.transport_block_size = 4;
  DCCH_LCHAN_DESC.max_transport_blocks = 16;
  DCCH_LCHAN_DESC.Delay_class = 1;
  DTCH_DL_LCHAN_DESC.transport_block_size = 52;
  DTCH_DL_LCHAN_DESC.max_transport_blocks = 20;
  DTCH_DL_LCHAN_DESC.Delay_class = 1;
  DTCH_UL_LCHAN_DESC.transport_block_size = 52;
  DTCH_UL_LCHAN_DESC.max_transport_blocks = 20;
  DTCH_UL_LCHAN_DESC.Delay_class = 1;

Lionel Gauthier's avatar
Lionel Gauthier committed
141
  Rlc_info_um.rlc_mode = RLC_MODE_UM;
142 143 144
  Rlc_info_um.rlc.rlc_um_info.timer_reordering = 5;
  Rlc_info_um.rlc.rlc_um_info.sn_field_length = 10;
  Rlc_info_um.rlc.rlc_um_info.is_mXch = 0;
145 146
  //Rlc_info_um.rlc.rlc_um_info.sdu_discard_mode=16;

Lionel Gauthier's avatar
Lionel Gauthier committed
147
  Rlc_info_am_config.rlc_mode = RLC_MODE_AM;
148
  Rlc_info_am_config.rlc.rlc_am_info.max_retx_threshold = 50;
149 150 151 152 153
  Rlc_info_am_config.rlc.rlc_am_info.poll_pdu = 8;
  Rlc_info_am_config.rlc.rlc_am_info.poll_byte = 1000;
  Rlc_info_am_config.rlc.rlc_am_info.t_poll_retransmit = 15;
  Rlc_info_am_config.rlc.rlc_am_info.t_reordering = 50;
  Rlc_info_am_config.rlc.rlc_am_info.t_status_prohibit = 10;
154

155
  return 0;
156 157
}

158 159 160 161 162 163 164 165
//-----------------------------------------------------------------------------
void
rrc_config_buffer(
  SRB_INFO* Srb_info,
  uint8_t Lchan_type,
  uint8_t Role
)
//-----------------------------------------------------------------------------
166
{
167 168 169 170 171

  Srb_info->Rx_buffer.payload_size = 0;
  Srb_info->Tx_buffer.payload_size = 0;
}

172

173 174 175 176 177 178 179
//-----------------------------------------------------------------------------
void
rrc_t310_expiration(
  const protocol_ctxt_t* const ctxt_pP,
  const uint8_t                 eNB_index
)
//-----------------------------------------------------------------------------
180
{
181

182
  if (UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].State != RRC_CONNECTED) {
183
    LOG_D(RRC, "Timer 310 expired, going to RRC_IDLE\n");
184 185 186 187 188 189 190 191 192 193 194
    UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].State = RRC_IDLE;
    UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].UE_index = 0xffff;
    UE_rrc_inst[ctxt_pP->module_id].Srb0[eNB_index].Rx_buffer.payload_size = 0;
    UE_rrc_inst[ctxt_pP->module_id].Srb0[eNB_index].Tx_buffer.payload_size = 0;
    UE_rrc_inst[ctxt_pP->module_id].Srb1[eNB_index].Srb_info.Rx_buffer.payload_size = 0;
    UE_rrc_inst[ctxt_pP->module_id].Srb1[eNB_index].Srb_info.Tx_buffer.payload_size = 0;

    if (UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Active == 1) {
      msg ("[RRC Inst %d] eNB_index %d, Remove RB %d\n ", ctxt_pP->module_id, eNB_index,
           UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Srb_info.Srb_id);
      rrc_pdcp_config_req (ctxt_pP,
195 196
                           SRB_FLAG_YES,
                           CONFIG_ACTION_REMOVE,
197
                           UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Srb_info.Srb_id,
198
                           0);
199
      rrc_rlc_config_req (ctxt_pP,
200 201 202
                          SRB_FLAG_YES,
                          MBMS_FLAG_NO,
                          CONFIG_ACTION_REMOVE,
203
                          UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Srb_info.Srb_id,
204
                          Rlc_info_um);
205 206 207
      UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Active = 0;
      UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Status = IDLE;
      UE_rrc_inst[ctxt_pP->module_id].Srb2[eNB_index].Next_check_frame = 0;
208
    }
209
  } else { // Restablishment procedure
210
    LOG_D(RRC, "Timer 310 expired, trying RRCRestablishment ...\n");
211 212
  }
}
Cedric Roux's avatar
Cedric Roux committed
213

214 215 216
//-----------------------------------------------------------------------------
RRC_status_t
rrc_rx_tx(
217
  protocol_ctxt_t* const ctxt_pP,
218 219 220 221
  const uint8_t      enb_indexP,
  const int          CC_id
)
//-----------------------------------------------------------------------------
222
{
223
  //uint8_t        UE_id;
224 225
  int32_t        current_timestamp_ms, ref_timestamp_ms;
  struct timeval ts;
226 227
  struct rrc_eNB_ue_context_s   *ue_context_p = NULL,*ue_to_be_removed = NULL;

228 229 230 231
#ifdef LOCALIZATION
  double                         estimated_distance;
  protocol_ctxt_t                ctxt;
#endif
232
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_IN);
233

234
  if(ctxt_pP->enb_flag == ENB_FLAG_NO) {
235
    // check timers
236

237 238
    if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T300_active == 1) {
      if ((UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T300_cnt % 10) == 0)
239
        LOG_D(RRC,
240
              "[UE %d][RAPROC] Frame %d T300 Count %d ms\n", ctxt_pP->module_id, ctxt_pP->frame, UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T300_cnt);
241

242 243 244
      if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T300_cnt
          == T300[UE_rrc_inst[ctxt_pP->module_id].sib2[enb_indexP]->ue_TimersAndConstants.t300]) {
        UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T300_active = 0;
245
        // ALLOW CCCH to be used
246 247
        UE_rrc_inst[ctxt_pP->module_id].Srb0[enb_indexP].Tx_buffer.payload_size = 0;
        rrc_ue_generate_RRCConnectionRequest (ctxt_pP, enb_indexP);
248
        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT);
249
        return (RRC_ConnSetup_failed);
250
      }
251

252
      UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T300_cnt++;
253
    }
254

255
    if ((UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].SIStatus&2)>0) {
256 257
      if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].N310_cnt
          == N310[UE_rrc_inst[ctxt_pP->module_id].sib2[enb_indexP]->ue_TimersAndConstants.n310]) {
258
	LOG_I(RRC,"Activating T310\n");
259
        UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_active = 1;
260
      }
261
    } else { // in case we have not received SIB2 yet
262
      /*      if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].N310_cnt == 100) {
263
        UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].N310_cnt = 0;
264 265 266 267

	}*/
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT);
      return RRC_OK;
268
    }
269

270 271 272 273 274
    if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_active == 1) {
      if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].N311_cnt
          == N311[UE_rrc_inst[ctxt_pP->module_id].sib2[enb_indexP]->ue_TimersAndConstants.n311]) {
        UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_active = 0;
        UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].N311_cnt = 0;
275
      }
276

277 278 279
      if ((UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_cnt % 10) == 0) {
        LOG_D(RRC, "[UE %d] Frame %d T310 Count %d ms\n", ctxt_pP->module_id, ctxt_pP->frame, UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_cnt);
      }
280

281 282 283
      if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_cnt    == T310[UE_rrc_inst[ctxt_pP->module_id].sib2[enb_indexP]->ue_TimersAndConstants.t310]) {
        UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_active = 0;
        rrc_t310_expiration (ctxt_pP, enb_indexP);
284
        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT);
285 286
	LOG_I(RRC,"Returning RRC_PHY_RESYNCH: T310 expired\n"); 
        return RRC_PHY_RESYNCH;
287
      }
288

289
      UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T310_cnt++;
290
    }
291

292 293 294 295
    if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T304_active==1) {
      if ((UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T304_cnt % 10) == 0)
        LOG_D(RRC,"[UE %d][RAPROC] Frame %d T304 Count %d ms\n",ctxt_pP->module_id,ctxt_pP->frame,
              UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T304_cnt);
296

297 298 299
      if (UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T304_cnt == 0) {
        UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T304_active = 0;
        UE_rrc_inst[ctxt_pP->module_id].HandoverInfoUe.measFlag = 1;
Cedric Roux's avatar
Cedric Roux committed
300 301
        LOG_E(RRC,"[UE %d] Handover failure..initiating connection re-establishment procedure... \n",
              ctxt_pP->module_id);
302
        //Implement 36.331, section 5.3.5.6 here
303
        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT);
304
        return(RRC_Handover_failed);
305
      }
306

307
      UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].T304_cnt--;
308
    }
309

310
    // Layer 3 filtering of RRC measurements
311 312
    if (UE_rrc_inst[ctxt_pP->module_id].QuantityConfig[0] != NULL) {
      ue_meas_filtering(ctxt_pP,enb_indexP);
313
    }
314

315
    ue_measurement_report_triggering(ctxt_pP,enb_indexP);
316

317 318 319
    if (UE_rrc_inst[ctxt_pP->module_id].Info[0].handoverTarget > 0) {
      LOG_I(RRC,"[UE %d] Frame %d : RRC handover initiated\n", ctxt_pP->module_id, ctxt_pP->frame);
    }
320

321 322 323
    if((UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].State == RRC_HO_EXECUTION)   &&
        (UE_rrc_inst[ctxt_pP->module_id].HandoverInfoUe.targetCellId != 0xFF)) {
      UE_rrc_inst[ctxt_pP->module_id].Info[enb_indexP].State= RRC_IDLE;
324
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT);
325 326
      return(RRC_HO_STARTED);
    }
327

328
  } else { // eNB
329
    check_handovers(ctxt_pP);
330
    // counetr, and get the value and aggregate
331 332

    // check for UL failure
333
    RB_FOREACH(ue_context_p, rrc_ue_tree_s, &(RC.rrc[ctxt_pP->module_id]->rrc_ue_head)) {
334 335 336 337 338 339 340 341 342 343 344 345 346
      if ((ctxt_pP->frame == 0) && (ctxt_pP->subframe==0)) {
	if (ue_context_p->ue_context.Initialue_identity_s_TMSI.presence == TRUE) {
	  LOG_I(RRC,"UE rnti %x:S-TMSI %x failure timer %d/20000\n",
		ue_context_p->ue_context.rnti,
		ue_context_p->ue_context.Initialue_identity_s_TMSI.m_tmsi,
		ue_context_p->ue_context.ul_failure_timer);
	}
	else {
	  LOG_I(RRC,"UE rnti %x failure timer %d/20000\n",
		ue_context_p->ue_context.rnti,
		ue_context_p->ue_context.ul_failure_timer);
	}
      }
347 348 349 350 351 352 353 354 355
      if (ue_context_p->ue_context.ul_failure_timer>0) {
	ue_context_p->ue_context.ul_failure_timer++;
	if (ue_context_p->ue_context.ul_failure_timer >= 20000) {
	  // remove UE after 20 seconds after MAC has indicated UL failure
	  LOG_I(RRC,"Removing UE %x instance\n",ue_context_p->ue_context.rnti);
	  ue_to_be_removed = ue_context_p;
	  break;
	}
      }
356 357
      if (ue_context_p->ue_context.ue_release_timer>0) {
	ue_context_p->ue_context.ue_release_timer++;
358 359
	if (ue_context_p->ue_context.ue_release_timer >= 
	    ue_context_p->ue_context.ue_release_timer_thres) {
360 361 362 363 364
	  LOG_I(RRC,"Removing UE %x instance\n",ue_context_p->ue_context.rnti);
	  ue_to_be_removed = ue_context_p;
	  break;
	}
      }
365 366 367
    }
    if (ue_to_be_removed)
      rrc_eNB_free_UE(ctxt_pP->module_id,ue_to_be_removed);
368

369
#ifdef RRC_LOCALIZATION
370

371 372 373
    /* for the localization, only primary CC_id might be relevant*/
    gettimeofday(&ts, NULL);
    current_timestamp_ms = ts.tv_sec * 1000 + ts.tv_usec / 1000;
374 375
    ref_timestamp_ms = RC.rrc[ctxt_pP->module_id]->reference_timestamp_ms;
    RB_FOREACH(ue_context_p, rrc_ue_tree_s, &(RC.rrc[ctxt_pP->module_id]->rrc_ue_head)) {
376 377 378 379 380
      ctxt = *ctxt_pP;
      ctxt.rnti = ue_context_p->ue_context.rnti;
      estimated_distance = rrc_get_estimated_ue_distance(
                             &ctxt,
                             CC_id,
381
                             RC.rrc[ctxt_pP->module_id]->loc_type);
382

383
      if ((current_timestamp_ms - ref_timestamp_ms > RC.rrc[ctxt_pP->module_id]->aggregation_period_ms) &&
384
          estimated_distance != -1) {
385
        LOG_D(LOCALIZE, " RRC [UE/id %d -> eNB/id %d] timestamp %d frame %d estimated r = %f\n",
386 387
              ctxt.rnti,
              ctxt_pP->module_id,
388
              current_timestamp_ms,
389 390 391
              ctxt_pP->frame,
              estimated_distance);
        LOG_D(LOCALIZE, " RRC status %d\n", ue_context_p->ue_context.Status);
392
        push_front(&RC.rrc[ctxt_pP->module_id]->loc_list,
393
                   estimated_distance);
394
        RC.rrc[ctxt_pP->module_id]->reference_timestamp_ms = current_timestamp_ms;
395
      }
396
    }
397

398
#endif
399 400 401
    (void)ts; /* remove gcc warning "unused variable" */
    (void)ref_timestamp_ms; /* remove gcc warning "unused variable" */
    (void)current_timestamp_ms; /* remove gcc warning "unused variable" */
402
  }
403

404
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT);
405 406
  return (RRC_OK);
}
407

408 409 410 411 412 413 414 415
//-----------------------------------------------------------------------------
long
binary_search_int(
  int elements[],
  long numElem,
  int value
)
//-----------------------------------------------------------------------------
416
{
winckel's avatar
winckel committed
417
  long first, last, middle, search = -1;
418 419 420
  first = 0;
  last = numElem-1;
  middle = (first+last)/2;
421

422
  if(value < elements[0]) {
423
    return first;
424
  }
425

426
  if(value > elements[last]) {
427
    return last;
428
  }
429

430
  while (first <= last) {
431
    if (elements[middle] < value) {
432
      first = middle+1;
433
    } else if (elements[middle] == value) {
434 435
      search = middle+1;
      break;
436
    } else {
437
      last = middle -1;
438
    }
439

440 441
    middle = (first+last)/2;
  }
442

443
  if (first > last) {
444
    LOG_E(RRC,"Error in binary search!");
445
  }
446

447 448 449 450 451 452 453
  return search;
}

/* This is a binary search routine which operates on an array of floating
   point numbers and returns the index of the range the value lies in
   Used for RSRP and RSRQ measurement mapping. Can potentially be used for other things
*/
454 455 456 457 458 459 460 461
//-----------------------------------------------------------------------------
long
binary_search_float(
  float elements[],
  long numElem,
  float value
)
//-----------------------------------------------------------------------------
462
{
winckel's avatar
winckel committed
463
  long first, last, middle;
464 465 466
  first = 0;
  last = numElem-1;
  middle = (first+last)/2;
467

468
  if(value <= elements[0]) {
469
    return first;
470
  }
471

472
  if(value >= elements[last]) {
473
    return last;
474
  }
475

476
  while (last - first > 1) {
477
    if (elements[middle] > value) {
478
      last = middle;
479
    } else {
480
      first = middle;
481
    }
482

483 484
    middle = (first+last)/2;
  }
485

486
  if (first < 0 || first >= numElem) {
487
    LOG_E(RRC,"\n Error in binary search float!");
488
  }
489

490 491 492
  return first;
}