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

/*! \file ra_procedures.c
 * \brief Routines for UE MAC-layer Random-access procedures (36.321) V8.6 2009-03
 * \author R. Knopp and Navid Nikaein
 * \date 2011
 * \version 0.1
 * \company Eurecom
 * \email: knopp@eurecom.fr navid.nikaein@eurecom.fr
 * \note
 * \warning
 */

#include "extern.h"
#include "defs.h"
#include "proto.h"
#include "UTIL/LOG/vcd_signal_dumper.h"
#include "PHY_INTERFACE/extern.h"
#include "SCHED/defs.h"
#include "COMMON/mac_rrc_primitives.h"
#include "RRC/LITE/extern.h"
#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h"
#include "UTIL/LOG/log.h"
#include "UTIL/OPT/opt.h"
#include "OCG.h"
#include "OCG_extern.h"
#ifdef PHY_EMUL
#include "SIMULATION/simulation_defs.h"
#endif

#include "SIMULATION/TOOLS/defs.h" // for taus

extern uint8_t  nfapi_mode;
extern UE_MODE_t get_ue_mode(uint8_t Mod_id,uint8_t CC_id,uint8_t eNB_index);


int8_t get_DELTA_PREAMBLE(module_id_t module_idP,int CC_id)
{

  AssertFatal(CC_id==0,
	      "Transmission on secondary CCs is not supported yet\n");
  uint8_t prachConfigIndex = UE_mac_inst[module_idP].radioResourceConfigCommon->prach_Config.prach_ConfigInfo.prach_ConfigIndex;
  uint8_t preambleformat;

  if (UE_mac_inst[module_idP].tdd_Config) { // TDD
    if (prachConfigIndex < 20) {
      preambleformat = 0;
    } else if (prachConfigIndex < 30) {
      preambleformat = 1;
    } else if (prachConfigIndex < 40) {
      preambleformat = 2;
    } else if (prachConfigIndex < 48) {
      preambleformat = 3;
    } else {
      preambleformat = 4;
    }
  } else { // FDD
    preambleformat = prachConfigIndex>>2;
  }

  switch (preambleformat) {
  case 0:
  case 1:
    return(0);

  case 2:
  case 3:
    return(-3);

  case 4:
    return(8);

  default:
    AssertFatal(1==0,"[UE %d] ue_procedures.c: FATAL, Illegal preambleformat %d, prachConfigIndex %d\n",
		module_idP,
		preambleformat,prachConfigIndex);
  }

}


/// This routine implements Section 5.1.2 (UE Random Access Resource Selection) from 36.321
void get_prach_resources(module_id_t module_idP,
                         int CC_id,
                         uint8_t eNB_index,
                         uint8_t t_id,
                         uint8_t first_Msg3,
                         RACH_ConfigDedicated_t *rach_ConfigDedicated)
{
	LOG_I(MAC, "Panos-D: get_prach_resources 1");

  uint8_t Msg3_size = UE_mac_inst[module_idP].RA_Msg3_size;
  PRACH_RESOURCES_t *prach_resources = &UE_mac_inst[module_idP].RA_prach_resources;
  RACH_ConfigCommon_t *rach_ConfigCommon = NULL;
  uint8_t noGroupB = 0;
  uint8_t f_id = 0,num_prach=0;
  int numberOfRA_Preambles;
  int messageSizeGroupA;
  int sizeOfRA_PreamblesGroupA;
  int messagePowerOffsetGroupB;
  int PLThreshold;

  AssertFatal(CC_id==0,
	      "Transmission on secondary CCs is not supported yet\n");
  AssertFatal(UE_mac_inst[module_idP].radioResourceConfigCommon!=NULL,
	      "[UE %d] FATAL  radioResourceConfigCommon is NULL !!!\n",module_idP);

  rach_ConfigCommon = &UE_mac_inst[module_idP].radioResourceConfigCommon->rach_ConfigCommon;
  numberOfRA_Preambles = (1+rach_ConfigCommon->preambleInfo.numberOfRA_Preambles)<<2;  

  if (rach_ConfigDedicated) {   // This is for network controlled Mobility, later
    if (rach_ConfigDedicated->ra_PRACH_MaskIndex != 0) {
      prach_resources->ra_PreambleIndex = rach_ConfigDedicated->ra_PreambleIndex;
      prach_resources->ra_RACH_MaskIndex = rach_ConfigDedicated->ra_PRACH_MaskIndex;
      return;
    }
  }

  /* TODO: gcc warns if this variable is not always set, let's put -1 for no more warning */
  messageSizeGroupA = -1;

  if (!rach_ConfigCommon->preambleInfo.preamblesGroupAConfig) {
    noGroupB = 1;
  } else {
    sizeOfRA_PreamblesGroupA = (rach_ConfigCommon->preambleInfo.preamblesGroupAConfig->sizeOfRA_PreamblesGroupA+1)<<2;
    switch (rach_ConfigCommon->preambleInfo.preamblesGroupAConfig->messageSizeGroupA) {
    case 0:
      messageSizeGroupA = 56;
      break;
    case 1:
      messageSizeGroupA = 144;
      break;
    case 2:
      messageSizeGroupA = 208;
      break;
    case 3:
      messageSizeGroupA = 256;
      break;
    }

    /* TODO: what value to use as default? */
    messagePowerOffsetGroupB = -9999;
    switch (rach_ConfigCommon->preambleInfo.preamblesGroupAConfig->messagePowerOffsetGroupB) {
    case 0:
      messagePowerOffsetGroupB = -9999;
      break;
    case 1:
      messagePowerOffsetGroupB = 0;
      break;
    case 2:
      messagePowerOffsetGroupB = 5;
      break;
    case 3:
      messagePowerOffsetGroupB = 8;
      break;
    case 4:
      messagePowerOffsetGroupB = 10;
      break;
    case 5:
      messagePowerOffsetGroupB = 12;
      break;
    case 6:
      messagePowerOffsetGroupB = 15;
      break;
    case 7:
      messagePowerOffsetGroupB = 18;
      break;
    }

    PLThreshold = 0 - get_DELTA_PREAMBLE(module_idP,CC_id) - get_Po_NOMINAL_PUSCH(module_idP,CC_id) - messagePowerOffsetGroupB;
    // Note Pcmax is set to 0 here, we have to fix this

    if (sizeOfRA_PreamblesGroupA == numberOfRA_Preambles) {
      noGroupB = 1;
    }
  }

  if (first_Msg3 == 1) {
    if (noGroupB == 1) {
    	LOG_I(MAC, "Panos-D: get_prach_resources 2");
      // use Group A procedure
      UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex  = (taus())%numberOfRA_Preambles;
      UE_mac_inst[module_idP].RA_prach_resources.ra_RACH_MaskIndex = 0;
      UE_mac_inst[module_idP].RA_usedGroupA = 1;
    } else if ((Msg3_size <messageSizeGroupA) ||
               (get_PL(module_idP,0,eNB_index) > PLThreshold)) {
    	LOG_I(MAC, "Panos-D: get_prach_resources 3");
      // use Group A procedure
      UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex  = (taus())%sizeOfRA_PreamblesGroupA;
      UE_mac_inst[module_idP].RA_prach_resources.ra_RACH_MaskIndex = 0;
      UE_mac_inst[module_idP].RA_usedGroupA = 1;
    } else { // use Group B
    	LOG_I(MAC, "Panos-D: get_prach_resources 4");
      UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex  = sizeOfRA_PreamblesGroupA +
        (taus())%(numberOfRA_Preambles - sizeOfRA_PreamblesGroupA);
      UE_mac_inst[module_idP].RA_prach_resources.ra_RACH_MaskIndex = 0;
      UE_mac_inst[module_idP].RA_usedGroupA = 0;
    }

    UE_mac_inst[module_idP].RA_prach_resources.ra_PREAMBLE_RECEIVED_TARGET_POWER = get_Po_NOMINAL_PUSCH(module_idP,CC_id);
  } else { // Msg3 is being retransmitted
    if (UE_mac_inst[module_idP].RA_usedGroupA == 1) {
      if (rach_ConfigCommon->preambleInfo.preamblesGroupAConfig) {
        UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex  = (taus())%rach_ConfigCommon->preambleInfo.preamblesGroupAConfig->sizeOfRA_PreamblesGroupA;
      } else {
        UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex  = (taus())&0x3f;
      }

      UE_mac_inst[module_idP].RA_prach_resources.ra_RACH_MaskIndex = 0;
    } else {
      // FIXME rach_ConfigCommon->preambleInfo.preamblesGroupAConfig may be zero
      UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex  =
        rach_ConfigCommon->preambleInfo.preamblesGroupAConfig->sizeOfRA_PreamblesGroupA +
        (taus())%(rach_ConfigCommon->preambleInfo.numberOfRA_Preambles -
                  rach_ConfigCommon->preambleInfo.preamblesGroupAConfig->sizeOfRA_PreamblesGroupA);
      UE_mac_inst[module_idP].RA_prach_resources.ra_RACH_MaskIndex = 0;
    }
  }

  // choose random PRACH resource in TDD
  if (UE_mac_inst[module_idP].tdd_Config) {
    num_prach = get_num_prach_tdd(module_idP);

    if ((num_prach>0) && (num_prach<6)) {
      UE_mac_inst[module_idP].RA_prach_resources.ra_TDD_map_index = (taus()%num_prach);
    }

    f_id = get_fid_prach_tdd(module_idP,
			     UE_mac_inst[module_idP].RA_prach_resources.ra_TDD_map_index);
  }

  // choose RA-RNTI
  UE_mac_inst[module_idP].RA_prach_resources.ra_RNTI = 1 + t_id + 10*f_id;
  LOG_I(MAC, "Panos-D: get_prach_resources 4");
}

void Msg1_transmitted(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id)
{

  AssertFatal(CC_id==0,
	      "Transmission on secondary CCs is not supported yet\n");
  // start contention resolution timer
  UE_mac_inst[module_idP].RA_attempt_number++;

  if (opt_enabled) {
    trace_pdu(0, NULL, 0, module_idP, 0 , UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex,
        UE_mac_inst[module_idP].txFrame, UE_mac_inst[module_idP].txSubframe, 0, UE_mac_inst[module_idP].RA_attempt_number);
    LOG_D(OPT,"[UE %d][RAPROC] TX MSG1 Frame %d trace pdu for rnti %x  with size %d\n",
          module_idP, frameP, 1, UE_mac_inst[module_idP].RA_Msg3_size);
  }

}


void Msg3_transmitted(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id)
{

  AssertFatal(CC_id==0,
	      "Transmission on secondary CCs is not supported yet\n");

  // start contention resolution timer
  LOG_D(MAC,"[UE %d][RAPROC] Frame %d : Msg3_tx: Setting contention resolution timer\n",module_idP,frameP);
  UE_mac_inst[module_idP].RA_contention_resolution_cnt = 0;
  UE_mac_inst[module_idP].RA_contention_resolution_timer_active = 1;

  if (opt_enabled) { // msg3
    trace_pdu(0, &UE_mac_inst[module_idP].CCCH_pdu.payload[0], UE_mac_inst[module_idP].RA_Msg3_size,
              module_idP, 3, UE_mac_inst[module_idP].crnti, UE_mac_inst[module_idP].txFrame, UE_mac_inst[module_idP].txSubframe, 0, 0);
    LOG_D(OPT,"[UE %d][RAPROC] MSG3 Frame %d trace pdu Preamble %d   with size %d\n",
          module_idP, frameP, UE_mac_inst[module_idP].crnti /*UE_mac_inst[module_idP].RA_prach_resources.ra_PreambleIndex*/, UE_mac_inst[module_idP].RA_Msg3_size);
  }

}


PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP,int CC_id,frame_t frameP, uint8_t eNB_indexP,sub_frame_t subframeP)
{

  LOG_I(MAC, "Panos-D: ue_get_rach 1");
  uint8_t                  Size               = 0;
  UE_MODE_t UE_mode;
  // Panos: Modification for phy_stub_ue operation
  if(nfapi_mode == 3) { // Panos: phy_stub_ue mode
	  UE_mode = UE_mac_inst[module_idP].UE_mode[0];
	  LOG_I(MAC, "Panos-D: ue_get_rach 2, E_mode: %d", UE_mode);
  }
  else { // Full stack mode
	  UE_mode = get_ue_mode(module_idP,0,eNB_indexP);
  }


  uint8_t                  lcid               = CCCH;
  uint16_t                 Size16;
  struct RACH_ConfigCommon *rach_ConfigCommon = (struct RACH_ConfigCommon *)NULL;
  int32_t                  frame_diff         = 0;
  mac_rlc_status_resp_t    rlc_status;
  uint8_t                  dcch_header_len    = 0;
  uint16_t                 sdu_lengths[8];
  uint8_t                  ulsch_buff[MAX_ULSCH_PAYLOAD_BYTES];

  AssertFatal(CC_id==0,
	      "Transmission on secondary CCs is not supported yet\n");

  if (UE_mode == PRACH) {
	  LOG_I(MAC, "Panos-D: ue_get_rach 3, RA_active value: %d", UE_mac_inst[module_idP].RA_active);
    if (UE_mac_inst[module_idP].radioResourceConfigCommon) {
      rach_ConfigCommon = &UE_mac_inst[module_idP].radioResourceConfigCommon->rach_ConfigCommon;
    } else {
    	//AssertFatal(UE_mac_inst[module_idP].radioResourceConfigCommon!=NULL,"RadioResourceConfigCommon Null");
      return(NULL);
    }

    if (UE_mac_inst[module_idP].RA_active == 0) {
    	LOG_I(MAC, "Panos-D: ue_get_rach 4");
      LOG_I(MAC,"RA not active\n");
      // check if RRC is ready to initiate the RA procedure
      Size = mac_rrc_data_req(module_idP,
			      CC_id,
			      frameP,
			      CCCH,1,
			      &UE_mac_inst[module_idP].CCCH_pdu.payload[sizeof(SCH_SUBHEADER_SHORT)+1],0,
			      eNB_indexP,
			      0);
      Size16 = (uint16_t)Size;
      
      //  LOG_D(MAC,"[UE %d] Frame %d: Requested RRCConnectionRequest, got %d bytes\n",module_idP,frameP,Size);
      LOG_I(RRC, "[MSC_MSG][FRAME %05d][RRC_UE][MOD %02d][][--- MAC_DATA_REQ (RRCConnectionRequest eNB %d) --->][MAC_UE][MOD %02d][]\n",
	    frameP, module_idP, eNB_indexP, module_idP);
      LOG_I(MAC,"[UE %d] Frame %d: Requested RRCConnectionRequest, got %d bytes\n",module_idP,frameP,Size);
      
      if (Size>0) {
    	  LOG_I(MAC, "Panos-D: ue_get_rach 5");
	UE_mac_inst[module_idP].RA_active                        = 1;
	UE_mac_inst[module_idP].RA_PREAMBLE_TRANSMISSION_COUNTER = 1;
	UE_mac_inst[module_idP].RA_Msg3_size                     = Size+sizeof(SCH_SUBHEADER_SHORT)+sizeof(SCH_SUBHEADER_SHORT);
	UE_mac_inst[module_idP].RA_prachMaskIndex                = 0;
	UE_mac_inst[module_idP].RA_prach_resources.Msg3          = UE_mac_inst[module_idP].CCCH_pdu.payload;
	UE_mac_inst[module_idP].RA_backoff_cnt                   = 0;  // add the backoff condition here if we have it from a previous RA reponse which failed (i.e. backoff indicator)
	
	AssertFatal(rach_ConfigCommon!=NULL,
		    "[UE %d] FATAL Frame %d: rach_ConfigCommon is NULL !!!\n",module_idP,frameP);
	UE_mac_inst[module_idP].RA_window_cnt                    = 2+ rach_ConfigCommon->ra_SupervisionInfo.ra_ResponseWindowSize;
	
	if (UE_mac_inst[module_idP].RA_window_cnt == 9) {
	  UE_mac_inst[module_idP].RA_window_cnt = 10;  // Note: 9 subframe window doesn't exist, after 8 is 10!
	}
	
	UE_mac_inst[module_idP].RA_tx_frame         = frameP;
	UE_mac_inst[module_idP].RA_tx_subframe      = subframeP;
	UE_mac_inst[module_idP].RA_backoff_frame    = frameP;
	UE_mac_inst[module_idP].RA_backoff_subframe = subframeP;
	// Fill in preamble and PRACH resource
	get_prach_resources(module_idP,CC_id,eNB_indexP,subframeP,1,NULL);
	
	generate_ulsch_header((uint8_t*)&UE_mac_inst[module_idP].CCCH_pdu.payload[0],  // mac header
			      1,      // num sdus
			      0,            // short pading
			      &Size16,  // sdu length
			      &lcid,    // sdu lcid
			      NULL,  // power headroom
			      NULL,  // crnti
			      NULL,  // truncated bsr
			      NULL, // short bsr
			      NULL, // long_bsr
			      1); //post_padding
	return(&UE_mac_inst[module_idP].RA_prach_resources);
	
      } else if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] > 0) {
	// This is for triggering a transmission on DCCH using PRACH (during handover, or sending SR for example)
	dcch_header_len = 2 + 2;  /// SHORT Subheader + C-RNTI control element
	rlc_status = mac_rlc_status_ind(module_idP,UE_mac_inst[module_idP].crnti, eNB_indexP,frameP,subframeP,ENB_FLAG_NO,MBMS_FLAG_NO,
					DCCH,
					6
#ifdef Rel14
               ,0, 0
#endif
               );
	
	if (UE_mac_inst[module_idP].crnti_before_ho)
	  LOG_D(MAC,
		"[UE %d] Frame %d : UL-DCCH -> ULSCH, HO RRCConnectionReconfigurationComplete (%x, %x), RRC message has %d bytes to send throug PRACH (mac header len %d)\n",
		module_idP,frameP, UE_mac_inst[module_idP].crnti,UE_mac_inst[module_idP].crnti_before_ho, rlc_status.bytes_in_buffer,dcch_header_len);
	else
	  LOG_D(MAC,"[UE %d] Frame %d : UL-DCCH -> ULSCH, RRC message has %d bytes to send through PRACH(mac header len %d)\n",
		module_idP,frameP, rlc_status.bytes_in_buffer,dcch_header_len);
	
	sdu_lengths[0] = mac_rlc_data_req(module_idP, UE_mac_inst[module_idP].crnti,
					  eNB_indexP, frameP,ENB_FLAG_NO, MBMS_FLAG_NO,
					  DCCH,
					  6,	//not used
					  (char *)&ulsch_buff[0]
#ifdef Rel14
                 ,0,
                  0
#endif
                  );
	
	LOG_D(MAC,"[UE %d] TX Got %d bytes for DCCH\n",module_idP,sdu_lengths[0]);
	update_bsr(module_idP, frameP, subframeP,eNB_indexP);
	UE_mac_inst[module_idP].scheduling_info.BSR[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] =
	  locate_BsrIndexByBufferSize(BSR_TABLE, BSR_TABLE_SIZE, UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]]);
	
	//TO DO: fill BSR infos in UL TBS
	
	//header_len +=2;
	UE_mac_inst[module_idP].RA_active                        = 1;
	UE_mac_inst[module_idP].RA_PREAMBLE_TRANSMISSION_COUNTER = 1;
	UE_mac_inst[module_idP].RA_Msg3_size                     = Size+dcch_header_len;
	UE_mac_inst[module_idP].RA_prachMaskIndex                = 0;
	UE_mac_inst[module_idP].RA_prach_resources.Msg3          = ulsch_buff;
	UE_mac_inst[module_idP].RA_backoff_cnt                   = 0;  // add the backoff condition here if we have it from a previous RA reponse which failed (i.e. backoff indicator)
	
	AssertFatal(rach_ConfigCommon!=NULL,
		    "[UE %d] FATAL Frame %d: rach_ConfigCommon is NULL !!!\n",module_idP,frameP);
	UE_mac_inst[module_idP].RA_window_cnt                    = 2+ rach_ConfigCommon->ra_SupervisionInfo.ra_ResponseWindowSize;
	
	if (UE_mac_inst[module_idP].RA_window_cnt == 9) {
	  UE_mac_inst[module_idP].RA_window_cnt = 10;  // Note: 9 subframe window doesn't exist, after 8 is 10!
	}
	
	
	UE_mac_inst[module_idP].RA_tx_frame         = frameP;
	UE_mac_inst[module_idP].RA_tx_subframe      = subframeP;
	UE_mac_inst[module_idP].RA_backoff_frame    = frameP;
	UE_mac_inst[module_idP].RA_backoff_subframe = subframeP;
	// Fill in preamble and PRACH resource
	get_prach_resources(module_idP,CC_id,eNB_indexP,subframeP,1,NULL);
	generate_ulsch_header((uint8_t*)ulsch_buff,  // mac header
			      1,      // num sdus
			      0,            // short pading
			      &Size16,  // sdu length
			      &lcid,    // sdu lcid
			      NULL,  // power headroom
			      &UE_mac_inst[module_idP].crnti,  // crnti
			      NULL,  // truncated bsr
			      NULL, // short bsr
			      NULL, // long_bsr
			      0); //post_padding
	
	return(&UE_mac_inst[module_idP].RA_prach_resources);
      }
    } else { // RACH is active
      LOG_D(MAC,"[MAC][UE %d][RAPROC] frameP %d, subframe %d: RA Active, window cnt %d (RA_tx_frame %d, RA_tx_subframe %d)\n",module_idP,
	    frameP,subframeP,UE_mac_inst[module_idP].RA_window_cnt,
	    UE_mac_inst[module_idP].RA_tx_frame,UE_mac_inst[module_idP].RA_tx_subframe);
      
      // compute backoff parameters
      if (UE_mac_inst[module_idP].RA_backoff_cnt>0) {
	frame_diff = (sframe_t)frameP - UE_mac_inst[module_idP].RA_backoff_frame;
	
	if (frame_diff < 0) {
	  frame_diff = -frame_diff;
	}
	
	UE_mac_inst[module_idP].RA_backoff_cnt -= ((10*frame_diff) + (subframeP-UE_mac_inst[module_idP].RA_backoff_subframe));
	
	UE_mac_inst[module_idP].RA_backoff_frame    = frameP;
	UE_mac_inst[module_idP].RA_backoff_subframe = subframeP;
      }
      
      // compute RA window parameters
      if (UE_mac_inst[module_idP].RA_window_cnt>0) {
	frame_diff = (frame_t)frameP - UE_mac_inst[module_idP].RA_tx_frame;
	
	if (frame_diff < 0) {
	  frame_diff = -frame_diff;
	}
	
	UE_mac_inst[module_idP].RA_window_cnt -= ((10*frame_diff) + (subframeP-UE_mac_inst[module_idP].RA_tx_subframe));
	LOG_D(MAC,"[MAC][UE %d][RAPROC] frameP %d, subframe %d: RA Active, adjusted window cnt %d\n",module_idP,
	      frameP,subframeP,UE_mac_inst[module_idP].RA_window_cnt);
      }
      
      if ((UE_mac_inst[module_idP].RA_window_cnt<=0) &&
	  (UE_mac_inst[module_idP].RA_backoff_cnt<=0)) {
	
	UE_mac_inst[module_idP].RA_tx_frame    = frameP;
	UE_mac_inst[module_idP].RA_tx_subframe = subframeP;
	UE_mac_inst[module_idP].RA_PREAMBLE_TRANSMISSION_COUNTER++;
	UE_mac_inst[module_idP].RA_prach_resources.ra_PREAMBLE_RECEIVED_TARGET_POWER +=
	  (rach_ConfigCommon->powerRampingParameters.powerRampingStep<<1);  // 2dB increments in ASN.1 definition
	int preambleTransMax = -1;
	switch (rach_ConfigCommon->ra_SupervisionInfo.preambleTransMax) {
	case PreambleTransMax_n3:
	  preambleTransMax = 3;
	  break;
	case PreambleTransMax_n4:
	  preambleTransMax = 4;
	  break;
	case PreambleTransMax_n5:
	  preambleTransMax = 5;
	  break;
	case PreambleTransMax_n6:
	  preambleTransMax = 6;
	  break;
	case PreambleTransMax_n7:
	  preambleTransMax = 7;
	  break;
	case PreambleTransMax_n8:
	  preambleTransMax = 8;
	  break;
	case PreambleTransMax_n10:
	  preambleTransMax = 10;
	  break;
	case PreambleTransMax_n20:
	  preambleTransMax = 20;
	  break;
	case PreambleTransMax_n50:
	  preambleTransMax = 50;
	  break;
	case PreambleTransMax_n100:
	  preambleTransMax = 100;
	  break;
	case PreambleTransMax_n200:
	  preambleTransMax = 200;
	  break;
	} 
	
	if (UE_mac_inst[module_idP].RA_PREAMBLE_TRANSMISSION_COUNTER == preambleTransMax) {
	  LOG_D(MAC,"[UE %d] Frame %d: Maximum number of RACH attempts (%d)\n",module_idP,frameP,preambleTransMax);
	  // send message to RRC
	  UE_mac_inst[module_idP].RA_PREAMBLE_TRANSMISSION_COUNTER=1;
	  UE_mac_inst[module_idP].RA_prach_resources.ra_PREAMBLE_RECEIVED_TARGET_POWER = get_Po_NOMINAL_PUSCH(module_idP,CC_id);
	}
	
	UE_mac_inst[module_idP].RA_window_cnt                    = 2+ rach_ConfigCommon->ra_SupervisionInfo.ra_ResponseWindowSize;
	UE_mac_inst[module_idP].RA_backoff_cnt                   = 0;
	
	// Fill in preamble and PRACH resource
	get_prach_resources(module_idP,CC_id,eNB_indexP,subframeP,0,NULL);
	return(&UE_mac_inst[module_idP].RA_prach_resources);
      }
    }
  } else if (UE_mode == PUSCH) {
    LOG_D(MAC,"[UE %d] FATAL: Should not have checked for RACH in PUSCH yet ...",module_idP);
    AssertFatal(1==0,"");
  }
  
  return(NULL);
}