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

/*! \file eNB_scheduler_RA_NB_IoT.c
 * \brief functions used in Random access scheduling 
 * \author  NTUST BMW Lab./
 * \date 2017
 * \email: 
 * \version 1.0
 *
 */


#include "assertions.h"
#include "platform_types.h"
#include "PHY/defs.h"
#include "PHY/extern.h"
#include "msc.h"

#include "SCHED/defs.h"
#include "SCHED/extern.h"

#include "LAYER2/MAC/defs.h"
#include "LAYER2/MAC/extern.h"

#include "LAYER2/MAC/proto.h"
#include "UTIL/LOG/log.h"
#include "UTIL/LOG/vcd_signal_dumper.h"
#include "UTIL/OPT/opt.h"
#include "OCG.h"
#include "OCG_extern.h"

#include "RRC/LITE/extern.h"
#include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h"

//#include "LAYER2/MAC/pre_processor.c"
#include "pdcp.h"

#if defined(ENABLE_ITTI)
# include "intertask_interface.h"
#endif

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

#include "T.h"
///////////////////////////////////////////////////////////////////////////////////////////////////////

#include "defs_NB_IoT.h"
#include "proto_NB_IoT.h"
#include "extern_NB_IoT.h"

unsigned char str1[] = "rar_dci";
unsigned char str2[] = "rar";
unsigned char str3[] = "msg4_dci";
unsigned char str4[] = "msg4";
unsigned char str5[] = "ack_msg4";
unsigned char str6[] = "msg3_dci(retransmit)";
unsigned char str7[] = "msg3(retransmit)";
unsigned char str8[] = "msg4_dci(retransmit)";
unsigned char str9[] = "msg4(retransmit)";
unsigned char str10[] = "ack_msg4(retransmit)";
unsigned char str11[] = "msg3";
unsigned char str12[] = "msg3(retransmit)";

void init_RA_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, uint8_t preamble_index, ce_level_t ce_level, uint32_t sfn_id, uint16_t ta){

	int i;
	//RA_TEMPLATE_NB_IoT *msg2_list_tail = mac_inst->RA_msg2_list.tail;
	RA_TEMPLATE_NB_IoT *migrate_node;

	static int static_count=0;
	LOG_D(MAC,"[%04d][RA scheduler][MSG1] RX %d\n", mac_inst->current_subframe, static_count++);

	
	for(i=0; i<MAX_NUMBER_OF_UE_MAX_NB_IoT; ++i){
		if(0 == mac_inst->RA_template[i].active){
			migrate_node = &mac_inst->RA_template[i];
			break;
		}
	}

	if(i==MAX_NUMBER_OF_UE_MAX_NB_IoT){
		LOG_D(MAC,"[%04d][RA scheduler][MSG1] number of RA procedures is up to maximum..\n", mac_inst->current_subframe);
		return ;
	}

	migrate_node->active = 1;
	migrate_node->preamble_index = preamble_index;
	migrate_node->ce_level = ce_level;
	migrate_node->ra_rnti = (sfn_id>>2) + 1;
	migrate_node->ta = ta;
	migrate_node->next = (RA_TEMPLATE_NB_IoT *)0;
	migrate_node->prev = (RA_TEMPLATE_NB_IoT *)0;
	LOG_D(MAC,"[%04d][RA scheduler][MSG1][CE%d] Receive MSG1 RNTI %d preamble index %d\n", mac_inst->current_subframe, migrate_node->ce_level, migrate_node->ra_rnti, migrate_node->preamble_index);

	//	insert to end of list
	if((RA_TEMPLATE_NB_IoT *)0 == mac_inst->RA_msg2_list.head){
		mac_inst->RA_msg2_list.head = migrate_node;
	}else{
		//	not empty
		mac_inst->RA_msg2_list.tail->next = migrate_node;
		migrate_node->prev = mac_inst->RA_msg2_list.tail;
	}
	mac_inst->RA_msg2_list.tail = migrate_node;

}

//	triggered time :
//	1) after tx rar, wait msg3 timeout
//	2) number of retransmit msg3 meet maximum or absent of ack/nack
//	3) number of retransmit msg4 meet maximum or absent of ack/nack
void cancel_ra(uint16_t rnti){
	//uint32_t i;
}

uint16_t find_suit_i_delay(uint32_t rmax, uint32_t r, uint32_t dci_candidate){
    uint32_t i;
	uint32_t num_candidates = rmax / r;
	uint32_t left_candidates = num_candidates - dci_candidate - 1;	// 0-7
	uint32_t resource_gap = left_candidates * r;
	resource_gap = ((resource_gap * 10)>>3);	//	x1.125
	for(i=0;i<8;++i){
		if(resource_gap <= get_scheduling_delay(i, rmax)){
			return i;
		}
	}
	return 0;
}


void schedule_rar_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, int abs_subframe){
//    printf_FUNCTION_IN("schedule rar");
	RA_TEMPLATE_NB_IoT *msg2_nodes = mac_inst->RA_msg2_list.head;
	//RA_TEMPLATE_NB_IoT *msg3_list_tail = mac_inst->RA_msg3_list.tail;
	RA_TEMPLATE_NB_IoT *migrate_node;
	schedule_result_t *dci_result, *msg2_result;
    DCIFormatN0_t *dci_n0;
    DCIFormatN1_t *dci_n1_rar;
	available_resource_DL_t *dci_node, *msg2_node;//, *msg3_node;
	int rmax, fail, r, res;
	int dci_subframe, dci_end_subframe, dci_first_subframe, num_dci_subframe;
	int msg2_subframe, msg2_end_subframe, msg2_first_subframe, num_msg2_subframe;
	int msg3_subframe;//, msg3_end_subframe;

	int dci_candidate, i, num_candidate;
	int msg2_i_delay;
	int msg3_scheduling_delay;
	static uint16_t tc_rnti = 0x0101;
	int rep=1;
	sched_temp_UL_NB_IoT_t npusch_info;
    int fail_num = 0;
    int flag=0;
	while((RA_TEMPLATE_NB_IoT *)0 != msg2_nodes){
		if(flag==0)
			flag=1;
		fail=0;
		rmax = mac_inst->rrc_config.mac_NPRACH_ConfigSIB[msg2_nodes->ce_level].mac_npdcch_NumRepetitions_RA_NB_IoT;//32;
		num_candidate = 8;//rmax / r;
		r = rmax/num_candidate;
		num_dci_subframe = r;
		dci_subframe = abs_subframe;//mac_inst->current_subframe;
		for(dci_candidate=0; dci_candidate<num_candidate; ++dci_candidate){
            while(!is_dlsf(mac_inst, dci_subframe)){
                ++dci_subframe;
            }
			dci_node = (available_resource_DL_t *)check_resource_DL(mac_inst, dci_subframe, num_dci_subframe, &dci_end_subframe, &dci_first_subframe);
			if((available_resource_DL_t *)0 != dci_node){
				//dci_subframe += dci_candidate*num_dci_subframe;
				break;
			}
			res = num_dci_subframe;
			while(res != 0){ //  maybe would cost lots of time to search
                if(is_dlsf(mac_inst, dci_subframe)){
                    res--;
                }
                dci_subframe++;
            }
		}
		if(num_candidate==dci_candidate){
			fail|=0x1;
		}
		//	check msg2 resource
		uint32_t TBS, I_tbs, I_mcs, I_sf, Nrep;
		
		I_mcs = get_I_mcs(msg2_nodes->ce_level);
	    I_tbs = I_mcs;
		TBS = get_tbs(7, I_tbs, &I_sf);   //  rar 7 bytes
		Nrep = dl_rep[msg2_nodes->ce_level];
		num_msg2_subframe = get_num_sf(I_sf) * Nrep;
		
		//num_msg2_subframe = 8;
		msg2_i_delay = find_suit_i_delay(rmax, r, dci_candidate);
		for(i=0; i<8; ++i, ++msg2_i_delay){
		    msg2_i_delay = (msg2_i_delay==8)?0:msg2_i_delay;
		    msg2_subframe = dci_end_subframe+4+get_scheduling_delay(msg2_i_delay, rmax);
			msg2_node = (available_resource_DL_t *)check_resource_DL(mac_inst, msg2_subframe, num_msg2_subframe, &msg2_end_subframe, &msg2_first_subframe);
			if((available_resource_DL_t *)0 != msg2_node){
				break;
			}
		}
		if(-1==msg2_i_delay){
			fail|=0x2;
		}
		//	check msg3 resource
		rep = mac_inst->rrc_config.mac_NPRACH_ConfigSIB[msg2_nodes->ce_level].mac_numRepetitionsPerPreambleAttempt_NB_IoT;
		
		
		uint32_t Iru = 0, mcs, Nru;
		uint32_t mappedMcsIndex = 4;  //  assume all ue supported multi-tone
		mcs = mapped_mcs[msg2_nodes->ce_level][mappedMcsIndex]; //  assume all ue supported multi-tone
		
        TBS = get_TBS_UL_NB_IoT(mcs,1,Iru);
		while((TBS<11)&&(Iru<=7)){    //  88 bits
            Iru++;
            TBS=get_TBS_UL_NB_IoT(mcs,1,Iru);
        }
		Nru = RU_table[Iru];
		
        for(msg3_scheduling_delay=0; msg3_scheduling_delay<4; ++msg3_scheduling_delay){
		    //    36.213 Table 16.3.3-1 Imcs=3'b000 Nru=4
			msg3_subframe = msg2_end_subframe+msg3_scheduling_delay_table[msg3_scheduling_delay]+1;
			if(0==Check_UL_resource(msg3_subframe, Nru*rep, &npusch_info, 1, 0)){	//1: multi-tones 0: single-tone. 1: format 2(ack/nack) 0: format 1
				break;
			}
		}
		if(4==msg3_scheduling_delay){
			fail|=0x4;
		}
		if(0 < fail){
		    fail_num++;
		    LOG_D(MAC,"[%04d][RA scheduler][MSG2] fail vector %d\n", abs_subframe, fail);
		    LOG_D(MAC,"[%04d][RA scheduler][MSG2][CE%d] rnti: %d preamble: %d fail vector %d\n", abs_subframe-1, msg2_nodes->ce_level, msg2_nodes->ra_rnti, msg2_nodes->preamble_index, fail);
		    msg2_nodes = msg2_nodes->next;
		}else{
		    LOG_D(MAC,"[%04d][RA scheduler][MSG2][CE%d] rnti: %d preamble: %d scheduling success\n", abs_subframe-1, msg2_nodes->ce_level, msg2_nodes->ra_rnti, msg2_nodes->preamble_index);
		    dci_result = (schedule_result_t *)calloc(1, sizeof(schedule_result_t));
		    msg2_result = (schedule_result_t *)calloc(1, sizeof(schedule_result_t));
		    dci_n0 = (DCIFormatN0_t *)malloc(sizeof(DCIFormatN0_t));
			dci_n1_rar = (DCIFormatN1_t *)malloc(sizeof(DCIFormatN1_t));
			
		    fill_rar_NB_IoT(mac_inst, msg2_nodes, msg3_scheduling_delay, rep, &npusch_info);
		    
            msg2_nodes->wait_msg3_ack = 1;
			//	dci entity
			dci_n1_rar->type = 1;
			dci_n1_rar->orderIndicator = 0;
			dci_n1_rar->Scheddly = msg2_i_delay;
			dci_n1_rar->ResAssign = 0;
			dci_n1_rar->mcs = 0;	
			dci_n1_rar->RepNum = 0;	//	36.213 table 16.4.1.3-2, 8 candidates
			dci_n1_rar->ndi = 0;	//	ndi is useless in RAR	36.212 says the feild is reserved
			dci_n1_rar->HARQackRes = 0;	//	no HARQ procedure in RAR	36.212 says the feild is reserved
			dci_n1_rar->DCIRep = 0;	//	36.213 table 16.6-1 R=Rmax/8

			//	for dci
		    dci_result->output_subframe = dci_first_subframe;//dci_subframe;
			dci_result->end_subframe = dci_end_subframe;
		    dci_result->sdu_length = 0;
		    dci_result->direction = DL;
		    dci_result->DCI_release = 0;
		    dci_result->channel = NPDCCH;
		    dci_result->rnti = msg2_nodes->ra_rnti;//ra_rnti;
		    dci_result->rnti_type = 1;
		    dci_result->npusch_format = 0; //useless
		    dci_result->R_harq = 0;
		    dci_result->next = (schedule_result_t *)0;
		    dci_result->DCI_pdu = (void *)dci_n1_rar;
		    //dci_result->printf_str = &str1[0];
		    //dci_result->dl_sdly = msg2_subframe - dci_end_subframe;
			//dci_result->ul_sdly = msg3_subframe - msg2_end_subframe;
			//dci_result->num_sf = msg2_end_subframe - msg2_subframe+1;
			
			//	for msg2
		    msg2_result->output_subframe = msg2_first_subframe;//msg2_subframe;
		    msg2_result->end_subframe = msg2_end_subframe;
		    msg2_result->sdu_length = 56;   //  rar size
		    msg2_result->DLSCH_pdu = msg2_nodes->rar_buffer;
		    msg2_result->direction = DL;
		    msg2_result->DCI_release = 1;
		    msg2_result->channel = NPDSCH;
		    msg2_result->rnti = msg2_nodes->ra_rnti;//ra_rnti;
		    msg2_result->rnti_type = 1;
		    msg2_result->npusch_format = 0;	//useless
		    msg2_result->R_harq = 0;
		    msg2_result->next = (schedule_result_t *)0;
		    msg2_result->DCI_pdu = (void *)dci_n1_rar;
			//msg2_result->printf_str = str2;
			msg2_result->rar_buffer = msg2_nodes->rar_buffer;
			//msg2_result->dl_sdly = -1;
			//msg2_result->ul_sdly = -1;

			//	for msg3(fake DCI N0)
			dci_n0->type = 0;
			dci_n0->scind = npusch_info.subcarrier_indication;
			dci_n0->ResAssign = 0;
			dci_n0->mcs = 0;
			dci_n0->ndi = 1;
			dci_n0->Scheddly = msg3_scheduling_delay;
			dci_n0->RepNum = rep;
			dci_n0->rv = 0;
			dci_n0->DCIRep = 1;//get_DCI_REP()
			
			msg2_nodes->ue_rnti = tc_rnti;
			
			LOG_D(MAC,"[%04d][RA scheduler][MSG2] RARDCI %d-%d RAR %d-%d MSG3 %d-%d\n", abs_subframe-1, dci_first_subframe, dci_end_subframe, msg2_first_subframe, msg2_end_subframe, npusch_info.sf_start, npusch_info.sf_end);
			LOG_D(MAC,"[%04d][RA scheduler][MSG2][CE%d] Change RA-RNTI %d->T-CRNTI %d\n", abs_subframe-1, msg2_nodes->ce_level, msg2_nodes->ra_rnti, msg2_nodes->ue_rnti);
			LOG_D(MAC,"[%04d][RA scheduler][MSG2][CE%d] RAR DCI %d-%d RAR %d-%d MSG3 %d-%d\n", abs_subframe-1, msg2_nodes->ce_level, dci_first_subframe, dci_end_subframe, msg2_first_subframe, msg2_end_subframe, npusch_info.sf_start, npusch_info.sf_end);
            
            //	fill dci resource
			fill_resource_DL(mac_inst, dci_node, dci_first_subframe, dci_end_subframe, dci_result);
			//	fill msg2 resource
			fill_resource_DL(mac_inst, msg2_node, msg2_first_subframe, msg2_end_subframe, msg2_result);

			//	fill msg3 resource
			generate_scheduling_result_UL(-1, -1, npusch_info.sf_start, npusch_info.sf_end, dci_n0, tc_rnti, str11, (void *)0);
			adjust_UL_resource_list(&npusch_info);

			//simulate_rx(&simulate_rx_msg3_list, tc_rnti, npusch_info.sf_start);

			migrate_node = msg2_nodes;
			//migrate_node->ue_rnti = tc_rnti;
			tc_rnti++;
	        msg2_nodes = msg2_nodes->next;

			//	maintain list
			if((RA_TEMPLATE_NB_IoT *)0 == migrate_node->prev){
				//	first node
				mac_inst->RA_msg2_list.head = migrate_node->next;	//	including null
			}else{
				//	not first node
				migrate_node->prev->next = migrate_node->next;		//	including null
			}
			if((RA_TEMPLATE_NB_IoT *)0 == migrate_node->next){
				//	last node
				mac_inst->RA_msg2_list.tail = migrate_node->prev;	//	including null
			}else{
				//	not last node
				migrate_node->next->prev = migrate_node->prev;		//	including null
			}

			//	migrate to next list
			//	insert to end of list
			migrate_node->next = (RA_TEMPLATE_NB_IoT *)0;
			migrate_node->prev = (RA_TEMPLATE_NB_IoT *)0;
			if((RA_TEMPLATE_NB_IoT *)0 == mac_inst->RA_msg3_list.head){
				mac_inst->RA_msg3_list.head = migrate_node;
			}else{
				//	not empty
				mac_inst->RA_msg3_list.tail->next = migrate_node;
				migrate_node->prev = mac_inst->RA_msg3_list.tail;
			}
			mac_inst->RA_msg3_list.tail = migrate_node;

		}
		
	}
	if(flag==1)
		LOG_D(MAC,"[%04d][RA scheduler][MSG2] failed number: %d\n", abs_subframe-1, fail_num);
	
	
	//printf_FUNCTION_OUT("schedule rar");
	return ;
}

void msg3_do_retransmit_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, rnti_t c_rnti){
    RA_TEMPLATE_NB_IoT *msg3_nodes = mac_inst->RA_msg3_list.head;
	//RA_TEMPLATE_NB_IoT *migrate_node;

	if((RA_TEMPLATE_NB_IoT *)0 != msg3_nodes)
	while((RA_TEMPLATE_NB_IoT *)0 != msg3_nodes){
		if(msg3_nodes->ue_rnti == c_rnti){
		    msg3_nodes->wait_msg3_ack = 0;
		    msg3_nodes->msg3_retransmit_count++;
		    return ;
		}
		msg3_nodes = msg3_nodes->next;
	}
	
	return ;
}

void msg4_do_retransmit_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, rnti_t c_rnti){
    RA_TEMPLATE_NB_IoT *msg4_nodes = mac_inst->RA_msg4_list.head;
	//RA_TEMPLATE_NB_IoT *migrate_node;

	if((RA_TEMPLATE_NB_IoT *)0 != msg4_nodes)
	while((RA_TEMPLATE_NB_IoT *)0 != msg4_nodes){
		if(msg4_nodes->ue_rnti == c_rnti){
		    msg4_nodes->wait_msg4_ack = 0;
		    msg4_nodes->msg4_retransmit_count++;
		    return ;
		}
		msg4_nodes = msg4_nodes->next;
	}
	
	return ;
}

void receive_msg3_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, rnti_t c_rnti, uint32_t phr, uint32_t ul_total_buffer){
	//	since successful receive msg3, tc-rnti become c-rnti.

	RA_TEMPLATE_NB_IoT *msg3_nodes = mac_inst->RA_msg3_list.head;
	RA_TEMPLATE_NB_IoT *migrate_node;

	if((RA_TEMPLATE_NB_IoT *)0 != msg3_nodes)
	while((RA_TEMPLATE_NB_IoT *)0 != msg3_nodes){
		if(msg3_nodes->ue_rnti == c_rnti){
			add_ue_NB_IoT(mac_inst, c_rnti, msg3_nodes->ce_level, phr, ul_total_buffer);//	rnti, ce level
			LOG_D(MAC,"[%04d][RA scheduler][MSG3][CE%d] Receive MSG3 T-CRNTI %d Preamble Index %d \n", mac_inst->current_subframe, msg3_nodes->ce_level, msg3_nodes->ue_rnti, msg3_nodes->preamble_index);
			migrate_node = msg3_nodes;

			//	maintain list
			if((RA_TEMPLATE_NB_IoT *)0 == migrate_node->prev){
				//	first node
				mac_inst->RA_msg3_list.head = migrate_node->next;	//	including null
			}else{
				//	not first node
				migrate_node->prev->next = migrate_node->next;		//	including null
			}
			if((RA_TEMPLATE_NB_IoT *)0 == migrate_node->next){
				//	last node
				mac_inst->RA_msg3_list.tail = migrate_node->prev;	//	including null
			}else{
				//	not last node
				migrate_node->next->prev = migrate_node->prev;		//	including null
			}

			//	migrate to next list
			//	insert to end of list
			migrate_node->next = (RA_TEMPLATE_NB_IoT *)0;
			migrate_node->prev = (RA_TEMPLATE_NB_IoT *)0;
			if((RA_TEMPLATE_NB_IoT *)0 == mac_inst->RA_msg4_list.head){
				mac_inst->RA_msg4_list.head = migrate_node;
			}else{
				//	not empty
				mac_inst->RA_msg4_list.tail->next = migrate_node;
				migrate_node->prev = mac_inst->RA_msg4_list.tail;
			}
			mac_inst->RA_msg4_list.tail = migrate_node;

			return ;
		}
		msg3_nodes = msg3_nodes->next;
	}

	if((RA_TEMPLATE_NB_IoT *)0 == msg3_nodes){
		LOG_D(MAC,"[%04d][RA scheduler][MSG3] receive msg3.. can't found the ue from crnti %x\n", mac_inst->current_subframe, c_rnti);
		return;
	}
}

void schedule_msg3_retransimission_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, int abs_subframe){

	RA_TEMPLATE_NB_IoT *msg3_nodes = mac_inst->RA_msg3_list.head;

	available_resource_DL_t *dci_node;//, *msg3_node;
	int rmax, fail, res, r;
	int dci_subframe, dci_end_subframe, dci_first_subframe, num_dci_subframe;
	int msg3_subframe;//, msg3_end_subframe;

	int dci_candidate, num_candidate;
	int msg3_scheduling_delay;
	schedule_result_t *dci_result;//, *msg3_result;

	int rep=1;
	//sched_temp_UL_NB_IoT_t npusch_info;

#if 0
	//	msg3 retransmission pre-processor
	RA_TEMPLATE_NB_IoT *iterator, *iterator1;
	while((RA_TEMPLATE_NB_IoT *)0 != msg3_nodes){
		if(msg3_nodes->wait_msg3_ack == 0){
			iterator = msg3_nodes;
			
			while(iterator->prev != (RA_TEMPLATE_NB_IoT *)0 && iterator != mac_inst->RA_msg3_list.head){
				if(iterator->prev->msg3_retransmit_count < iterator->msg3_retransmit_count){
					//swap
					iterator1 = iterator->prev;
					
					if(iterator->prev == mac_inst->RA_msg3_list.head || iterator1->prev == (RA_TEMPLATE_NB_IoT *)0){	
						mac_inst->RA_msg3_list.head = iterator;
						iterator1->prev = (RA_TEMPLATE_NB_IoT *)0;	//	b->prev
					}else{	
						iterator->prev->prev->next = iterator;	//	a*->next
						iterator->prev = iterator1->prev;	//	b->prev
					}
					if(iterator == mac_inst->RA_msg3_list.tail || iterator->next == (RA_TEMPLATE_NB_IoT *)0){	
						mac_inst->RA_msg3_list.tail = iterator1;
						iterator1->next = (RA_TEMPLATE_NB_IoT *)0;		//	a->next
					}else{	
						iterator->next->prev = iterator->prev;	//b*->prev
						iterator1->next = iterator->next;	//	a->next
					}
					
					iterator1->prev = iterator;	//	a->prev
				
					iterator->next = iterator1;	//	b->next
				
				}else{
					break;
				}
			}
		}
		msg3_nodes = msg3_nodes->next;
	}
#endif 

	msg3_nodes = mac_inst->RA_msg3_list.head;
	while((RA_TEMPLATE_NB_IoT *)0 != msg3_nodes){
		if(msg3_nodes->wait_msg3_ack == 0){
		    
			fail=0;
			//	check dci resource
			rmax = mac_inst->rrc_config.mac_NPRACH_ConfigSIB[msg3_nodes->ce_level].mac_npdcch_NumRepetitions_RA_NB_IoT;//32;
			num_candidate = 8;//rmax / r;
			r = rmax/num_candidate;
			num_dci_subframe = r;
			dci_subframe = abs_subframe;//mac_inst->current_subframe;
			for(dci_candidate=0; dci_candidate<8; ++dci_candidate){
                while(!is_dlsf(mac_inst, dci_subframe)){
                    ++dci_subframe;
                }
				dci_node = (available_resource_DL_t *)check_resource_DL(mac_inst, dci_subframe, num_dci_subframe, &dci_end_subframe, &dci_first_subframe);
				if((available_resource_DL_t *)0 != dci_node){
					break;
				}
				res = num_dci_subframe;
    			while(res != 0){ //  cost lot of time to search
                    if(is_dlsf(mac_inst, dci_subframe)){
                        res--;
                    }
                    dci_subframe++;
                }
			}
			if(8==dci_candidate){
				//failed
				fail|=0x1;
			}
			//	check msg3 resource
			
			rep = mac_inst->rrc_config.mac_NPRACH_ConfigSIB[msg3_nodes->ce_level].mac_numRepetitionsPerPreambleAttempt_NB_IoT;
			sched_temp_UL_NB_IoT_t npusch_info;
		
        	uint32_t Iru = 0, mcs, Nru;
			uint32_t mappedMcsIndex = 4;  //  assume all ue supported multi-tone
			mcs = mapped_mcs[msg3_nodes->ce_level][mappedMcsIndex]; //  assume all ue supported multi-tone
			int TBS = get_TBS_UL_NB_IoT(mcs,1,Iru);
			while((TBS<11)&&(Iru<=7)){
				Iru++;
				TBS=get_TBS_UL_NB_IoT(mcs,1,Iru);
			}
			Nru = RU_table[Iru];
			
			for(msg3_scheduling_delay=0; msg3_scheduling_delay<4; ++msg3_scheduling_delay){
				msg3_subframe = 8+dci_end_subframe+msg3_scheduling_delay_table[msg3_scheduling_delay];
				if(0==Check_UL_resource(msg3_subframe+1, Nru*rep, &npusch_info, 1, 0)){	//1: multi-tones 0: single-tone. 1: format 2(ack/nack) 0: format 1
					break;
				}
			}
			if(4==msg3_scheduling_delay){
				//failed
				fail|=0x2;
			}
	        
			if(0 == fail){
				
				msg3_nodes->wait_msg3_ack = 1;
				DCIFormatN0_t *dci_n0_msg3 = (DCIFormatN0_t *)malloc(sizeof(DCIFormatN0_t));
				//	dci entity
				dci_n0_msg3->type = 0;
				dci_n0_msg3->scind = npusch_info.subcarrier_indication;
				dci_n0_msg3->ResAssign = 0;
				dci_n0_msg3->mcs = 0;
				dci_n0_msg3->ndi = 0;	//	retrnasmit
				dci_n0_msg3->Scheddly = msg3_scheduling_delay;
				dci_n0_msg3->RepNum = rep;
				dci_n0_msg3->rv = 0;
				dci_n0_msg3->DCIRep = 1;//get_DCI_REP()
				//	for dci
				dci_result = (schedule_result_t *)malloc(sizeof(schedule_result_t));
			    dci_result->output_subframe = dci_first_subframe;//dci_subframe;
			    dci_result->end_subframe = dci_end_subframe;
			    dci_result->sdu_length = 0;
			    dci_result->direction = UL;
			    dci_result->DCI_release = 0;
			    dci_result->channel = NPDCCH;
			    dci_result->rnti = msg3_nodes->ue_rnti;
			    dci_result->rnti_type = 1;
			    dci_result->npusch_format = 0; //useless
			    dci_result->R_harq = 0;
			    dci_result->next = (schedule_result_t *)0;
			    dci_result->DCI_pdu = (void *)dci_n0_msg3;
//		        dci_result->printf_str = str6;
	           // dci_result->dl_sdly = msg3_subframe - dci_end_subframe + 1;
			//	dci_result->ul_sdly = -1;
				//dci_result->num_sf = -1;
				//dci_result->harq_round = msg3_nodes->msg3_retransmit_count;
				
       		    //simulate_rx(&simulate_rx_msg3_list, msg3_nodes->ue_rnti, npusch_info.sf_start);

			    //	fill dci resource
			    fill_resource_DL(mac_inst, dci_node, dci_first_subframe, dci_end_subframe, dci_result);
			    //	fill msg3 resource
			    generate_scheduling_result_UL(-1, -1, npusch_info.sf_start, npusch_info.sf_end, dci_n0_msg3, msg3_nodes->ue_rnti, str12, (void *)0);	//	rnti
				adjust_UL_resource_list(&npusch_info);
	            LOG_D(MAC,"[%04d][RA scheduler][MSG3 re] MSG3DCI %d-%d MSG3 %d-%d\n", abs_subframe, dci_first_subframe, dci_end_subframe, npusch_info.sf_start, npusch_info.sf_end );
			}else{
				LOG_D(MAC,"[%04d][RA scheduler][MSG3 re] fail vector %d\n", abs_subframe, fail );
			}

			//++msg3_nodes->msg3_retransmit_count;
		}
		msg3_nodes = msg3_nodes->next;
	}
	return ;
}


void receive_msg4_ack_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, rnti_t rnti){
	int i;
	RA_TEMPLATE_NB_IoT *migrate_node = mac_inst->RA_msg4_list.head;

	UE_TEMPLATE_NB_IoT *ue_info = (UE_TEMPLATE_NB_IoT *)0;
	if((RA_TEMPLATE_NB_IoT *)0 != migrate_node)
	while((RA_TEMPLATE_NB_IoT *)0 != migrate_node){
		if(migrate_node->ue_rnti == rnti){
            
			ue_info = mac_inst->UE_list_spec[(uint32_t)migrate_node->ce_level].UE_template_NB_IoT;
			//	maintain list
			if((RA_TEMPLATE_NB_IoT *)0 == migrate_node->prev){
				//	first node
				mac_inst->RA_msg4_list.head = migrate_node->next;	//	including null
			}else{
				//	not first node
				migrate_node->prev->next = migrate_node->next;		//	including null
			}
			if((RA_TEMPLATE_NB_IoT *)0 == migrate_node->next){
				//	last node
				mac_inst->RA_msg4_list.tail = migrate_node->prev;	//	including null
			}else{
				//	not last node
				migrate_node->next->prev = migrate_node->prev;		//	including null
			}

			//	release ra template
            migrate_node->active = 0;
			migrate_node->ce_level = 0;
			migrate_node->msg3_retransmit_count = 0;
			migrate_node->msg4_retransmit_count = 0;
			migrate_node->next = (RA_TEMPLATE_NB_IoT *)0;
			migrate_node->prev = (RA_TEMPLATE_NB_IoT *)0;
			migrate_node->ta = 0;
			migrate_node->preamble_index = 0;
			migrate_node->ue_rnti = 0x0;
			migrate_node->ra_rnti = 0x0;
			migrate_node->wait_msg4_ack = 0;
			migrate_node->wait_msg3_ack = 0;
			break ;
		}
		migrate_node = migrate_node->next;
	}
	
	for(i=0; i<MAX_NUMBER_OF_UE_MAX_NB_IoT; ++i){
		if(ue_info[i].rnti == rnti){
		    
			if(ue_info[i].ul_total_buffer>0)
			{
				ue_info[i].direction = 0;
			}
			else
			{
				ue_info[i].direction = 1;
			}
			ue_info[i].RRC_connected = 1;
			LOG_D(MAC,"[%04d][RA scheduler][MSG4] received UE:%d direction: %d \n", mac_inst->current_subframe, rnti, ue_info[i].direction );
			break;
		}
	}
	
	return ;
}

//	msg4 scheduling: both first time or retransmit would be scheduled in this function(msg4_list).
void schedule_msg4_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst, int abs_subframe){
    //printf_FUNCTION_IN("[SCHEDULER RA MSG4]");
	RA_TEMPLATE_NB_IoT *msg4_nodes = mac_inst->RA_msg4_list.head;//, *migrate_node;

	available_resource_DL_t *dci_node, *msg4_node;
	int rmax, fail, r;
	int dci_subframe, dci_end_subframe, dci_first_subframe, num_dci_subframe;
	int msg4_subframe, msg4_end_subframe, msg4_first_subframe, num_msg4_subframe;
	int harq_subframe, harq_end_subframe;

	int dci_candidate, num_candidate;
	int msg4_i_delay, i, res, rep;
	int end_flagHARQ, HARQ_delay;
	sched_temp_UL_NB_IoT_t HARQ_info;
	schedule_result_t *dci_result;
	schedule_result_t *msg4_result;
	schedule_result_t *harq_result;

#if 0
	//	msg4 pre-processor
	RA_TEMPLATE_NB_IoT *iterator, *iterator1;
	while((RA_TEMPLATE_NB_IoT *)0 != msg4_nodes){
		if(msg4_nodes->wait_msg4_ack == 0){
			iterator = msg4_nodes;
			
			while(iterator->prev != (RA_TEMPLATE_NB_IoT *)0 && iterator != mac_inst->RA_msg4_list.head){
				if(iterator->prev->msg4_retransmit_count < iterator->msg4_retransmit_count){
					//swap
					iterator1 = iterator->prev;
					
					if(iterator->prev == mac_inst->RA_msg4_list.head || iterator1->prev == (RA_TEMPLATE_NB_IoT *)0){	
						mac_inst->RA_msg4_list.head = iterator;
						iterator1->prev = (RA_TEMPLATE_NB_IoT *)0;	//	b->prev
					}else{	
						iterator->prev->prev->next = iterator;	//	a*->next
						iterator->prev = iterator1->prev;	//	b->prev
					}
					if(iterator == mac_inst->RA_msg4_list.tail || iterator->next == (RA_TEMPLATE_NB_IoT *)0){	
						mac_inst->RA_msg4_list.tail = iterator1;
						iterator1->next = (RA_TEMPLATE_NB_IoT *)0;		//	a->next
					}else{	
						iterator->next->prev = iterator->prev;	//b*->prev
						iterator1->next = iterator->next;	//	a->next
					}
					
					iterator1->prev = iterator;	//	a->prev
				
					iterator->next = iterator1;	//	b->next
				
				}else{
					break;
				}
			}
		}
		msg4_nodes = msg4_nodes->next;
	}
#endif
	msg4_node = (available_resource_DL_t *)0;
	msg4_nodes = mac_inst->RA_msg4_list.head;
	while((RA_TEMPLATE_NB_IoT *)0 != msg4_nodes){

		if(msg4_nodes->wait_msg4_ack == 0){
			fail=0;
			
			//printf_FUNCTION_IN("[SCHEDULER RA MSG4 DCI]");
			//	check dci resource
			rmax = mac_inst->rrc_config.mac_NPRACH_ConfigSIB[msg4_nodes->ce_level].mac_npdcch_NumRepetitions_RA_NB_IoT;//32;
    	    num_candidate = 8;//rmax / r;
    		r = rmax/num_candidate;
    		num_dci_subframe = r;
    		dci_subframe = abs_subframe;//mac_inst->current_subframe;
			for(dci_candidate=0; dci_candidate<num_candidate; ++dci_candidate){
	            while(!is_dlsf(mac_inst, dci_subframe)){
                    ++dci_subframe;
                }
				dci_node = (available_resource_DL_t *)check_resource_DL(mac_inst, dci_subframe, num_dci_subframe, &dci_end_subframe, &dci_first_subframe);
				if((available_resource_DL_t *)0 != dci_node){
					LOG_D(MAC,"%d msg4 dci %d - %d\n", abs_subframe, dci_first_subframe, dci_end_subframe);
					break;
				}
				res = num_dci_subframe;
    			while(res != 0){ //  cost lot of time to search
                    if(is_dlsf(mac_inst, dci_subframe)){
                        res--;
                    }
                    dci_subframe++;
                }
			}
			if(num_candidate==dci_candidate){
				//failed
				fail|=1;
			}
			//printf_FUNCTION_OUT("[SCHEDULER RA MSG4 DCI]");
			
			//printf_FUNCTION_IN("[SCHEDULER RA MSG4 PAYLOAD]");
			//	check msg4 resource
			rep = dl_rep[msg4_nodes->ce_level];
			num_msg4_subframe = 1*rep;   //  8 subframes
			msg4_i_delay = find_suit_i_delay(rmax, r, dci_candidate);
			for(i=msg4_i_delay; i<8; ++i){
				msg4_i_delay = (msg4_i_delay==8)?0:msg4_i_delay;
				msg4_subframe = dci_end_subframe+4+get_scheduling_delay(msg4_i_delay, rmax);
				msg4_node = (available_resource_DL_t *)check_resource_DL(mac_inst, msg4_subframe, num_msg4_subframe*rep, &msg4_end_subframe, &msg4_first_subframe);
				if((available_resource_DL_t *)0 != msg4_node){
					LOG_D(MAC,"%d msg4 %d - %d\n", abs_subframe, msg4_first_subframe, msg4_end_subframe);
					break;
				}
			}
			if(8==i){
				//failed
				fail|=2;
			}
            //printf_FUNCTION_OUT("[SCHEDULER RA MSG4 PAYLOAD]");
            
            //printf_FUNCTION_IN("[SCHEDULER RA MSG4 HARQ]");
            rep = mac_inst->rrc_config.mac_NPRACH_ConfigSIB[msg4_nodes->ce_level].mac_numRepetitionsPerPreambleAttempt_NB_IoT;
			for(HARQ_delay=0;HARQ_delay<4;++HARQ_delay){
	            end_flagHARQ=Check_UL_resource(msg4_end_subframe+get_HARQ_delay(1, HARQ_delay), rep, &HARQ_info, 0, 1);	//	RA_template->R
				if(0 == end_flagHARQ){
					harq_subframe = msg4_end_subframe + get_HARQ_delay(1, HARQ_delay);
					harq_end_subframe = harq_subframe + 2*rep -1;
					HARQ_info.ACK_NACK_resource_field=get_resource_field_value(HARQ_info.subcarrier_indication, get_scheduling_delay(HARQ_delay, rmax));
					break;
				}
			}
			if(4 == HARQ_delay){
				fail |= 4;
			}
			//printf_FUNCTION_OUT("[SCHEDULER RA MSG4 HARQ]");

			if(0==fail){
			    LOG_D(MAC,"[%04d][RA scheduler][MSG4][CE%d] rnti: %d scheduling success\n", abs_subframe-1, msg4_nodes->ce_level, msg4_nodes->ue_rnti);
			    msg4_nodes->wait_msg4_ack = 1;	
				DCIFormatN1_t *dci_n1_msg4 = (DCIFormatN1_t *)malloc(sizeof(DCIFormatN1_t));
				//	dci entity
				dci_n1_msg4->type = 1;
				dci_n1_msg4->orderIndicator = 0;
				dci_n1_msg4->Scheddly = msg4_i_delay;
				dci_n1_msg4->ResAssign = 0;
				dci_n1_msg4->mcs = 0;
				dci_n1_msg4->RepNum = 1;
				dci_n1_msg4->ndi = 1;
				dci_n1_msg4->HARQackRes = HARQ_info.ACK_NACK_resource_field;
				dci_n1_msg4->DCIRep = 1;

				//	for dci
				dci_result = (schedule_result_t *)malloc(sizeof(schedule_result_t));
				dci_result->output_subframe = dci_first_subframe;//dci_subframe;
				dci_result->end_subframe = dci_end_subframe;
				dci_result->sdu_length = 0;
				dci_result->direction = DL;
				dci_result->DCI_release = 0;
				dci_result->channel = NPDCCH;
				dci_result->rnti = msg4_nodes->ue_rnti;
				dci_result->rnti_type = 1;
				dci_result->npusch_format = 0; //useless
				dci_result->R_harq = 0;
				dci_result->next = (schedule_result_t *)0;
				dci_result->DCI_pdu = (void *)dci_n1_msg4;
				//dci_result->dl_sdly = msg4_subframe - dci_end_subframe;
				//dci_result->ul_sdly = harq_subframe - msg4_end_subframe;
				//dci_result->num_sf = msg4_end_subframe - msg4_subframe+1;
				//dci_result->harq_round = msg4_nodes->msg4_retransmit_count;
				
				//	for msg4
				msg4_result = (schedule_result_t *)malloc(sizeof(schedule_result_t));
				msg4_result->output_subframe = msg4_first_subframe;// msg4_subframe;
				msg4_result->end_subframe = msg4_end_subframe;
				msg4_result->sdu_length = 0;
				msg4_result->direction = DL;
				msg4_result->DCI_release = 0;
				msg4_result->channel = NPDSCH;
				msg4_result->rnti = msg4_nodes->ue_rnti;
		    	msg4_result->rnti_type = 1;
		    	msg4_result->npusch_format = 0;	//useless
		    	msg4_result->R_harq = 0;
				msg4_result->next = (schedule_result_t *)0;
				msg4_result->DCI_pdu = (void *)dci_n1_msg4;
				//msg4_result->harq_round = msg4_nodes->msg4_retransmit_count;

				harq_result = (schedule_result_t *)malloc(sizeof(schedule_result_t));
				harq_result->rnti = msg4_nodes->ue_rnti;
			    harq_result->output_subframe = harq_subframe;
			    harq_result->end_subframe = harq_end_subframe;
			    harq_result->sdu_length = 0;
			    harq_result->direction = UL;
			    harq_result->rnti_type = 3;
			    harq_result->DLSCH_pdu = NULL;
			    harq_result->DCI_pdu = (void *)dci_n1_msg4;
			    harq_result->DCI_release = 1;
			    harq_result->channel = NPUSCH;
			    harq_result->next = (schedule_result_t *)0;
				
				/*if(msg4_nodes->msg4_retransmit_count==0){
			        dci_result->printf_str = str3;
			        msg4_result->printf_str = str4;
			        harq_result->printf_str = str5;
                }else{
                    dci_result->printf_str = str8;
			        msg4_result->printf_str = str9;
			        harq_result->printf_str = str10;
                }*/
				
				//simulate_rx(&simulate_rx_msg4_list, msg4_nodes->ue_rnti, harq_subframe);
				
				LOG_D(MAC,"[%04d][RA scheduler][MSG4] UE:%x MSG4DCI %d-%d MSG4 %d-%d HARQ %d-%d\n", abs_subframe-1, msg4_nodes->ue_rnti, dci_first_subframe, dci_end_subframe, msg4_first_subframe, msg4_end_subframe, HARQ_info.sf_start, HARQ_info.sf_end);
	            LOG_D(MAC,"[%04d][RA scheduler][MSG4][CE%d] MSG4 DCI %d-%d MSG4 %d-%d HARQ %d-%d\n", abs_subframe-1, msg4_nodes->ce_level, dci_first_subframe, dci_end_subframe, msg4_first_subframe, msg4_end_subframe, HARQ_info.sf_start, HARQ_info.sf_end);
	            msg4_nodes->msg4_retransmit_count++;
	            
				//	fill dci resource
				fill_resource_DL(mac_inst, dci_node, dci_first_subframe, dci_end_subframe, dci_result);

                //	fill msg4 resource
				fill_resource_DL(mac_inst, msg4_node, msg4_first_subframe, msg4_end_subframe, msg4_result);

				//	fill ack/nack resource
				insert_schedule_result(&schedule_result_list_UL, harq_subframe, harq_result);
				adjust_UL_resource_list(&HARQ_info);
                
				//	active ue_list ul/dl
				UE_list_NB_IoT_t *UE_list = mac_inst->UE_list_spec;
				for(i=0; i<MAX_NUMBER_OF_UE_MAX_NB_IoT; ++i){
					if(UE_list->UE_template_NB_IoT[i].active == 1 && UE_list->UE_template_NB_IoT[i].rnti == msg4_nodes->ue_rnti){
						UE_list->UE_template_NB_IoT[i].direction = rand()&1;
					}
				}	
			}else{
			    LOG_D(MAC,"[%04d][RA scheduler][MSG4] fail vector %d\n", abs_subframe, fail );
			    LOG_D(MAC,"[%04d][RA scheduler][MSG4] rnti: %d preamble: %d fail vector %d\n", abs_subframe-1, msg4_nodes->ra_rnti, msg4_nodes->preamble_index, fail);
            
	       }
		}
        msg4_nodes = msg4_nodes->next;
	}
	
	//printf_FUNCTION_OUT("[SCHEDULER RA MSG4]");
	return ;
}

void schedule_RA_NB_IoT(eNB_MAC_INST_NB_IoT *mac_inst){
    //printf_FUNCTION_IN("[SCHEDULER RA]");
    uint32_t schedule_subframe = mac_inst->current_subframe + 1;
    schedule_subframe = schedule_subframe % 1048576;    //  20 bits, 10 bits + 10 bits
    
    //	this is the priority order in current stage.
    schedule_msg3_retransimission_NB_IoT(mac_inst, schedule_subframe);
    schedule_rar_NB_IoT(mac_inst, schedule_subframe);
	schedule_msg4_NB_IoT(mac_inst, schedule_subframe);

    //printf_FUNCTION_OUT("[SCHEDULER RA]");
	return ;
}

//  7bytes	TODO: CHECK
void fill_rar_NB_IoT(
	eNB_MAC_INST_NB_IoT *inst, 
	RA_TEMPLATE_NB_IoT *ra_template,
	uint8_t msg3_schedule_delay,
	uint8_t msg3_rep,
	sched_temp_UL_NB_IoT_t *schedule_template
)
//------------------------------------------------------------------------------
{
	uint8_t *dlsch_buffer = &ra_template->rar_buffer[0];
	RA_HEADER_RAPID_NB_IoT *rarh = (RA_HEADER_RAPID_NB_IoT *)dlsch_buffer;
	int i;
//,ra_idx = -1;
//	uint16_t rballoc;
//	uint8_t mcs,TPC,ULdelay,cqireq;
	
	for(i=0; i<7; ++i){
	    dlsch_buffer[i] = 0x0;
    }
	
	// subheader fixed
	rarh->E                     = 0; // First and last RAR
	rarh->T                     = 1; // 0 for E/T/R/R/BI subheader, 1 for E/T/RAPID subheader
	rarh->RAPID                 = ra_template->preamble_index; // Respond to Preamble 0 only for the moment
	
	uint8_t *rar = (uint8_t *)(dlsch_buffer+1);
	//	ta
	ra_template->ta >>= 4;
	rar[0] = (uint8_t)(ra_template->ta>>(2+4)); // 7 MSBs of timing advance + divide by 4
	rar[1] = (uint8_t)(ra_template->ta<<(4-2))&0xf0; // 4 LSBs of timing advance + divide by 4
	
	//	msg3 grant (15bits)
	//	subcarrier spacing:1 subcarrier indication:6 scheduling delay:2 msg3 repetition:3 MCS index: 3
	uint8_t subcarrier_spacing = 1;	// 1bit 15kHz
	uint8_t subcarrier_indication = schedule_template->subcarrier_indication; // 6bits
	uint8_t i_delay = msg3_schedule_delay; // 2bits
	uint8_t msg3_repetition = msg3_rep;// 3bit
	uint8_t mcs_index = 0;//3bit, msg3 88bits 3'b000
	
	rar[1] |= (subcarrier_spacing<<4) | (subcarrier_indication>>3);
	rar[2] = (uint8_t)(subcarrier_indication<<5) | (i_delay<<3) | msg3_repetition;
	rar[3] = (mcs_index<<5)&0xe0;  //  maped
	
	//	tc-rnti
	rar[4] = (uint8_t)(ra_template->ue_rnti>>8);
	rar[5] = (uint8_t)(ra_template->ue_rnti&0xff);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////// NB-IoT testing /////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////

void initiate_ra_proc_NB_IoT(module_id_t module_idP, int CC_id,frame_t frameP, uint16_t preamble_index,int16_t timing_offset,uint8_t sect_id,sub_frame_t subframeP,
                      uint8_t f_id)
{

  uint8_t i;
  RA_TEMPLATE *RA_template = (RA_TEMPLATE *)&eNB_mac_inst[module_idP].common_channels[CC_id].RA_template[0];

  printf("xxxxxxxxxxxxxxxx NB-IoT xxxxxxxxxxxxxx");
  for (i=0; i<NB_RA_PROC_MAX; i++) {
    if (RA_template[i].RA_active==FALSE &&
        RA_template[i].wait_ack_Msg4 == 0) {
     // int loop = 0;
      RA_template[i].RA_active=TRUE;
      RA_template[i].generate_rar=1;
      RA_template[i].generate_Msg4=0;
      RA_template[i].wait_ack_Msg4=0;
      RA_template[i].timing_offset=timing_offset;
      RA_template[i].RA_rnti = 1 + (frameP/4);
      RA_template[i].preamble_index = preamble_index;
      /* TODO: find better procedure to allocate RNTI */
    /*  do {
        RA_template[i].rnti = taus();
        loop++;
      } while (loop != 100 &&
               // TODO: this is not correct, the rnti may be in use without
               // being in the MAC yet. To be refined.
                //
      ///         !(find_UE_id(module_idP, RA_template[i].rnti) == -1 &&
                 // 1024 and 60000 arbirarily chosen, not coming from standard //
   //              RA_template[i].rnti >= 1024 && RA_template[i].rnti < 60000));
      if (loop == 100) {
       printf("%s:%d:%s: FATAL ERROR! contact the authors\n", __FILE__, __LINE__, __FUNCTION__); abort(); }

      RA_template[i].RA_rnti = 1 + (frameP/4);
      RA_template[i].preamble_index = preamble_index;   /// preamble_index=000000;

      LOG_D(MAC,"[eNB %d][RAPROC] CC_id %d Frame %d Activating RAR generation for process %d, rnti %x, RA_active %d\n",
            module_idP,CC_id,frameP,i,RA_template[i].rnti,
            RA_template[i].RA_active);*/

      return;
    }
  }

  LOG_E(MAC,"[eNB %d][RAPROC] FAILURE: CC_id %d Frame %d Initiating RA procedure for preamble index %d\n",module_idP,CC_id,frameP,preamble_index);
}