/*******************************************************************************
    OpenAirInterface
    Copyright(c) 1999 - 2014 Eurecom

    OpenAirInterface is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.


    OpenAirInterface is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with OpenAirInterface.The full GNU General Public License is
    included in this distribution in the file called "COPYING". If not,
    see <http://www.gnu.org/licenses/>.

  Contact Information
  OpenAirInterface Admin: openair_admin@eurecom.fr
  OpenAirInterface Tech : openair_tech@eurecom.fr
  OpenAirInterface Dev  : openair4g-devel@lists.eurecom.fr

  Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE

*******************************************************************************/

/*! \file rrc_config.c
* \brief rrc cinfiguration
* \author Raymond Knopp and Navid Nikaein
* \date 2011
* \version 1.0
* \company Eurecom
* \email: raymond.knopp@eurecom.fr and  navid.nikaein@eurecom.fr
*/


#include "defs.h"

#include "extern.h"


#ifdef PHY_EMUL
#include "SIMULATION/simulation_defs.h"
extern EMULATION_VARS *Emul_vars;
#endif
extern CH_MAC_INST *CH_mac_inst;
extern UE_MAC_INST *UE_mac_inst;
#ifdef BIGPHYSAREA
extern void *bigphys_malloc(int);
#endif

void rrc_init_ch_req(unsigned char Mod_id, rrm_init_ch_req_t  *smsg)
{
  uint16_t Index;
  MAC_CONFIG_REQ Mac_config_req;
  // MAC_MEAS_REQ Mac_meas_req;

  msg("-----------------------------------------------------------------------------------------------------------------\n");
  printk("[RRC_CONFIG]OPENAIR RRC INIT CH %d...\n",Mod_id);

  Mac_config_req.Lchan_type = smsg->Lchan_desc_srb0.Lchan_t;
  memcpy(&Mac_config_req.Lchan_desc[0],(LCHAN_DESC*)&smsg->Lchan_desc_srb0,LCHAN_DESC_SIZE); //0 rx, 1 tx
  memcpy(&Mac_config_req.Lchan_desc[1],(LCHAN_DESC*)&smsg->Lchan_desc_srb0,LCHAN_DESC_SIZE); //0 rx, 1 tx
  Mac_config_req.UE_CH_index=0;
  Mac_config_req.Lchan_id.Index=(0 << RAB_SHIFT2) + BCCH;
  msg("Calling Lchan_config\n");
  Index=Mac_rlc_xface->mac_config_req(Mod_id,ADD_LC,&Mac_config_req);
  msg("[OPENAIR][RRC][RRC_ON] NODE %d, Config BCCH %d done\n",CH_rrc_inst[Mod_id].Node_id,Index);
  CH_rrc_inst[Mod_id].Srb0.Srb_id = Index;

  memcpy(&CH_rrc_inst[Mod_id].Srb0.Lchan_desc[0],(LCHAN_DESC*)&smsg->Lchan_desc_srb0,LCHAN_DESC_SIZE); //0 rx, 1 tx
  memcpy(&CH_rrc_inst[Mod_id].Srb0.Lchan_desc[1],(LCHAN_DESC*)&smsg->Lchan_desc_srb0,LCHAN_DESC_SIZE); //0 rx, 1 tx

  rrc_config_buffer(&CH_rrc_inst[Mod_id].Srb0,BCCH,0);
  ((CH_BCCH_HEADER*)(&CH_rrc_inst[Mod_id].Srb0.Tx_buffer.Header[0]))->Rv_tb_idx=0;
  msg("[OPENAIR][RRC][RRC_ON] NODE %d, Config BCCH for TB_size %d\n",NODE_ID[Mod_id],
      CH_rrc_inst[Mod_id].Srb0.Lchan_desc[1].transport_block_size);
  CH_rrc_inst[Mod_id].Srb0.Tx_buffer.generate_fun=ch_rrc_generate_bcch;
  CH_rrc_inst[Mod_id].Srb0.Active=1;

  Mac_config_req.Lchan_type = smsg->Lchan_desc_srb1.Lchan_t;
  memcpy(&Mac_config_req.Lchan_desc[0],(LCHAN_DESC*)&smsg->Lchan_desc_srb1,LCHAN_DESC_SIZE); //0 rx, 1 tx
  memcpy(&Mac_config_req.Lchan_desc[1],(LCHAN_DESC*)&smsg->Lchan_desc_srb1,LCHAN_DESC_SIZE); //0 rx, 1 tx
  Mac_config_req.UE_CH_index=0;
  Mac_config_req.Lchan_id.Index=(0 << RAB_SHIFT2) + CCCH;
  // printk("Calling Lchan_config\n");
  Index=Mac_rlc_xface->mac_config_req(Mod_id,ADD_LC,&Mac_config_req);
  msg("[OPENAIR][RRC][RRC_ON] NODE %d, Config BCCH %d done\n",CH_rrc_inst[Mod_id].Node_id,Index);
  CH_rrc_inst[Mod_id].Srb1.Srb_id = Index;

  memcpy(&CH_rrc_inst[Mod_id].Srb1.Lchan_desc[0],(LCHAN_DESC*)&smsg->Lchan_desc_srb1,LCHAN_DESC_SIZE); //0 rx, 1 tx
  memcpy(&CH_rrc_inst[Mod_id].Srb1.Lchan_desc[1],(LCHAN_DESC*)&smsg->Lchan_desc_srb1,LCHAN_DESC_SIZE); //0 rx, 1 tx


  rrc_config_buffer(&CH_rrc_inst[Mod_id].Srb1,CCCH,1);
  ((CH_CCCH_HEADER*)(&CH_rrc_inst[Mod_id].Srb1.Tx_buffer.Header[0]))->Rv_tb_idx=0;
  printk("[OPENAIR][RRC][RRC_ON] NODE %d, Config CCCH %d done, TB_size=%d,%d\n",NODE_ID[Mod_id],Index,
         CH_rrc_inst[Mod_id].Srb1.Tx_buffer.Tb_size,CH_rrc_inst[Mod_id].Srb1.Rx_buffer.Tb_size);
  CH_rrc_inst[Mod_id].Srb1.Tx_buffer.generate_fun=ch_rrc_generate_ccch;
  CH_rrc_inst[Mod_id].Srb1.Active=1;

  //CH_rrc_inst[Mod_id].Info.UE_list[i].L2_id[0]=i;

  //      CH_rrc_inst[Mod_id].Info.UE_list[0]=0;

}

void rrc_init_mr_req(unsigned char Mod_id, rrci_init_mr_req_t  *smsg)
{
  uint16_t Index;
  MAC_CONFIG_REQ Mac_config_req;
  // MAC_MEAS_REQ Mac_meas_req;
  msg("-----------------------------------------------------------------------------------------------------------------\n");
  msg("[RRC_CONFIG]: Node %d: INIT MR REQUEST for CH %d\n",NODE_ID[Mod_id],smsg->CH_index);
  Mac_config_req.Lchan_type = smsg->Lchan_desc_srb0.Lchan_t;
  memcpy(&Mac_config_req.Lchan_desc[0],(LCHAN_DESC*)&smsg->Lchan_desc_srb0,LCHAN_DESC_SIZE); //0 rx, 1 tx
  memcpy(&Mac_config_req.Lchan_desc[1],(LCHAN_DESC*)&smsg->Lchan_desc_srb0,LCHAN_DESC_SIZE); //0 rx, 1 tx

  Mac_config_req.UE_CH_index=smsg->CH_index;
  Mac_config_req.Lchan_id.Index=(smsg->CH_index << RAB_SHIFT2) + BCCH;
  Index=Mac_rlc_xface->mac_config_req(Mod_id,ADD_LC,&Mac_config_req);
  msg("[OPENAIR][RRC][RRC_CONFIG] NODE %d, Config BCCH %d done\n",UE_rrc_inst[Mod_id-NB_CH_INST].Node_id,Index);

  UE_rrc_inst[Mod_id].Srb0[smsg->CH_index].Srb_id = Index;
  memcpy(& UE_rrc_inst[Mod_id-NB_CH_INST].Srb0[smsg->CH_index].Lchan_desc[0],(LCHAN_DESC*)&smsg->Lchan_desc_srb0,LCHAN_DESC_SIZE); //0 rx, 1 tx
  memcpy(& UE_rrc_inst[Mod_id-NB_CH_INST].Srb0[smsg->CH_index].Lchan_desc[1],(LCHAN_DESC*)&smsg->Lchan_desc_srb0,LCHAN_DESC_SIZE); //0 rx, 1 tx

  rrc_config_buffer(&UE_rrc_inst[Mod_id-NB_CH_INST].Srb0[smsg->CH_index],BCCH,0);
  ((CH_BCCH_HEADER*)(&UE_rrc_inst[Mod_id-NB_CH_INST].Srb0[smsg->CH_index].Rx_buffer.Header[0]))->Rv_tb_idx=0;
  UE_rrc_inst[Mod_id-NB_CH_INST].Srb0[smsg->CH_index].Active=1;
  /*
      Mac_meas_req.Lchan_id.Index = Index;
      Mac_meas_req.UE_CH_index = i;
      Mac_meas_req.Meas_trigger = BCCH_MEAS_TRIGGER;
      Mac_meas_req.Mac_avg = BCCH_MEAS_AVG;
      Mac_meas_req.Rep_amount = 0;
      Mac_meas_req.Rep_interval = 1000;
      UE_rrc_inst[Mod_id].Srb0[i].Meas_entry=Mac_rlc_xface->mac_meas_req(Mod_id+NB_CH_INST,&Mac_meas_req);
      UE_rrc_inst[Mod_id].Srb0[i].Meas_entry->Status=RADIO_CONFIG_OK;
      UE_rrc_inst[Mod_id].Srb0[i].Meas_entry->Last_report_frame=Rrc_xface->Frame_index;
      UE_rrc_inst[Mod_id].Srb0[i].Meas_entry->Next_check_frame=Rrc_xface->Frame_index+1000;
  */

  //printk("[OPENAIR][RRC][RRC_ON] NODE %d, Config CCCH %d done\n",NODE_ID[Mod_id],Index);
  //      printk("check meas, LC_Index %d, Next %d, Last %d, Int %d \n",UE_rrc_inst[Mod_id].Srb0[i].Meas_entry->Mac_meas_req.Lchan_id.Index,UE_rrc_inst[Mod_id].Srb0[i].Meas_entry->Next_check_frame,UE_rrc_inst[Mod_id].Srb0[i].Meas_entry->Last_report_frame,UE_rrc_inst[Mod_id].Srb0[i].Meas_entry->Mac_meas_req.Rep_interval);

  Mac_config_req.Lchan_type = smsg->Lchan_desc_srb1.Lchan_t;
  memcpy(&Mac_config_req.Lchan_desc[0],(LCHAN_DESC*)&smsg->Lchan_desc_srb1,LCHAN_DESC_SIZE); //0 rx, 1 tx
  memcpy(&Mac_config_req.Lchan_desc[1],(LCHAN_DESC*)&smsg->Lchan_desc_srb1,LCHAN_DESC_SIZE); //0 rx, 1 tx

  Mac_config_req.UE_CH_index=smsg->CH_index;
  Mac_config_req.Lchan_id.Index=(smsg->CH_index << RAB_SHIFT2) + CCCH;
  Index=Mac_rlc_xface->mac_config_req(Mod_id,ADD_LC,&Mac_config_req);
  msg("[OPENAIR][RRC][RRC_CONFIG] NODE %d, Config CCCH %d done\n",NODE_ID[Mod_id],Index);
  UE_rrc_inst[Mod_id-NB_CH_INST].Srb1[smsg->CH_index].Srb_id = Index;
  memcpy(&UE_rrc_inst[Mod_id-NB_CH_INST].Srb1[smsg->CH_index].Lchan_desc[0],(LCHAN_DESC*)&smsg->Lchan_desc_srb1,LCHAN_DESC_SIZE); //0 rx, 1 tx
  memcpy(&UE_rrc_inst[Mod_id-NB_CH_INST].Srb1[smsg->CH_index].Lchan_desc[1],(LCHAN_DESC*)&smsg->Lchan_desc_srb1,LCHAN_DESC_SIZE); //0 rx, 1 tx
  rrc_config_buffer(&UE_rrc_inst[Mod_id-NB_CH_INST].Srb1[smsg->CH_index],CCCH,1);
  ((CH_CCCH_HEADER*)(&UE_rrc_inst[Mod_id-NB_CH_INST].Srb1[smsg->CH_index].Rx_buffer.Header[0]))->Rv_tb_idx=0;
  UE_rrc_inst[Mod_id-NB_CH_INST].Srb1[smsg->CH_index].Active=1;
  /*

  Mac_meas_req.Lchan_id.Index = Index;
  //    Mac_meas_req.UE_CH_index = i;
  Mac_meas_req.Meas_trigger = CCCH_MEAS_TRIGGER;
  Mac_meas_req.Mac_avg = CCCH_MEAS_AVG;
  Mac_meas_req.Rep_amount = 0;
  Mac_meas_req.Rep_interval = 1000;
  UE_rrc_inst[Mod_id].Srb1[i].Meas_entry=Mac_rlc_xface->mac_meas_req(Mod_id+NB_CH_INST,&Mac_meas_req);
  UE_rrc_inst[Mod_id].Srb1[i].Meas_entry->Status=RADIO_CONFIG_OK;
  UE_rrc_inst[Mod_id].Srb1[i].Meas_entry->Last_report_frame=Rrc_xface->Frame_index;
  UE_rrc_inst[Mod_id].Srb1[i].Meas_entry->Next_check_frame=Rrc_xface->Frame_index+1000;
  //printk("[OPENAIR][RRC][RRC_ON] NODE %d, Config CCCH %d done\n",NODE_ID[Mod_id],Index);
  */


}




void rrc_config_req(Instance_t Mod_id, void *smsg, unsigned char Action,Transaction_t Trans_id)
{

  MAC_CONFIG_REQ Mac_config_req;
  MAC_MEAS_REQ Mac_meas_req;
  unsigned short Idx,UE_index,In_idx;


  switch(Action) {

  case RRM_RB_ESTABLISH_REQ: {
    rrm_rb_establish_req_t *p = (rrm_rb_establish_req_t *) smsg ;
    msg("[RRC]CH %d: config req for CH L2_id %d to MR L2_id %d\n",NODE_ID[Mod_id],p->L2_id[0].L2_id[0],p->L2_id[1].L2_id[0]);
    UE_index=rrc_find_ue_index(Mod_id, p->L2_id[1]);

    if(UE_index > NB_CNX_CH) {
      msg("[FATAL ERROR] NO MORE UE_INDEX!!!!!\n");
      return;
    }

    if(p->Lchan_desc.Lchan_t==DCCH) {
      Mac_config_req.Lchan_type = p->Lchan_desc.Lchan_t;
      Mac_config_req.UE_CH_index = UE_index;
      memcpy(&Mac_config_req.Lchan_desc[0],(LCHAN_DESC*)&p->Lchan_desc,LCHAN_DESC_SIZE); //0 rx, 1 tx
      memcpy(&Mac_config_req.Lchan_desc[1],(LCHAN_DESC*)&p->Lchan_desc,LCHAN_DESC_SIZE); //0 rx, 1 tx
      Mac_config_req.Lchan_id.Index=( UE_index << RAB_SHIFT2) + DCCH;
      Idx = Mac_rlc_xface->mac_config_req(Mod_id,ADD_LC,&Mac_config_req);
      CH_rrc_inst[Mod_id].Srb2[UE_index].Active = 1;
      CH_rrc_inst[Mod_id].Srb2[UE_index].Next_check_frame = Rrc_xface->Frame_index + 250;
      CH_rrc_inst[Mod_id].Srb2[UE_index].Status = NEED_RADIO_CONFIG;//RADIO CFG
      CH_rrc_inst[Mod_id].Srb2[UE_index].Srb_info.Srb_id = Idx;


      memcpy(&CH_rrc_inst[Mod_id].Srb2[UE_index].Srb_info.Lchan_desc[0],(LCHAN_DESC*)&p->Lchan_desc,LCHAN_DESC_SIZE); //0 rx, 1 tx
      memcpy(&CH_rrc_inst[Mod_id].Srb2[UE_index].Srb_info.Lchan_desc[1],(LCHAN_DESC*)&p->Lchan_desc,LCHAN_DESC_SIZE); //0 rx, 1 tx
      //      CH_rrc_inst[Mod_id].Srb2[UE_index].Srb_info.Lchan_desc[0] = &DCCH_LCHAN_DESC;
      //      CH_rrc_inst[Mod_id].Srb2[UE_index].Srb_info.Lchan_desc[1] = &DCCH_LCHAN_DESC;

      //CH_rrc_inst[Mod_id].Rab[In_idx][UE_index].Rb_info.Lchan_desc[0] = &msg->Lchan_desc;
      // CH_rrc_inst[Mod_id].Rab[In_idx][UE_index].Rb_info.Lchan_desc[1] = &msg-;
      //Configure a correponding measurement process
      //  msg("[RRC]Inst %d: Programing RADIO CONFIG of DCCH LCHAN %d\n",Mod_id,Idx);
      //CH_rrc_inst[Mod_id].Nb_rb[UE_index]++;
      //msg("[OPENAIR][RRC] CALLING RLC CONFIG RADIO BEARER %d\n",Idx);
      Mac_rlc_xface->rrc_rlc_config_req(Mod_id,CONFIG_ACTION_ADD,Idx,SIGNALLING_RADIO_BEARER,Rlc_info_um);
      /*
      CH_rrc_inst[Mod_id].Srb2[UE_index].Srb_info.CH_ip_addr_type=p->L3_info_t;
      if(p->L3_info_t == IPv4_ADDR){

        memcpy(CH_rrc_inst[Mod_id].Srb2[UE_index].Srb_info.CH_ip_addr,p->L3_info,4);
      }
      else
        memcpy(UE_rrc_inst[Mod_id].Srb2[UE_index].Srb_info.CH_ip_addr,p->L3_info,16);
      */




      //      if(msg->Mac_rlc_meas_desc !=NULL){
      CH_rrc_inst[Mod_id].Def_meas[UE_index]= &CH_mac_inst[Mod_id].Def_meas[UE_index];
      CH_rrc_inst[Mod_id].Def_meas[UE_index]->Active = 1;
      CH_rrc_inst[Mod_id].Def_meas[UE_index]->Status = NEED_RADIO_CONFIG;
      CH_rrc_inst[Mod_id].Def_meas[UE_index]->Forg_fact=1;
      CH_rrc_inst[Mod_id].Def_meas[UE_index]->Rep_interval=50;
      CH_rrc_inst[Mod_id].Def_meas[UE_index]->Last_report_frame=Rrc_xface->Frame_index;
      CH_rrc_inst[Mod_id].Def_meas[UE_index]->Next_check_frame=Rrc_xface->Frame_index +200 ;
      // }
    } else {
      msg("RRC_config: Inst %d:, UE_index %d",Mod_id,UE_index);
      Mac_config_req.Lchan_type = p->Lchan_desc.Lchan_t;
      Mac_config_req.UE_CH_index = UE_index;
      memcpy(&Mac_config_req.Lchan_desc[0],&p->Lchan_desc,LCHAN_DESC_SIZE); //0 rx, 1 tx
      memcpy(&Mac_config_req.Lchan_desc[1],&p->Lchan_desc,LCHAN_DESC_SIZE); //0 rx, 1 tx
      In_idx=find_free_dtch_position(Mod_id,UE_index);
      Mac_config_req.Lchan_id.Index=(UE_index << RAB_SHIFT2) + DTCH + In_idx;
      Idx = Mac_rlc_xface->mac_config_req(Mod_id,ADD_LC,&Mac_config_req);
      CH_rrc_inst[Mod_id].Rab[In_idx][UE_index].Active = 1;
      CH_rrc_inst[Mod_id].Rab[In_idx][UE_index].Next_check_frame = Rrc_xface->Frame_index + 250;
      CH_rrc_inst[Mod_id].Rab[In_idx][UE_index].Status = NEED_RADIO_CONFIG;//RADIO CFG
      CH_rrc_inst[Mod_id].Rab[In_idx][UE_index].Rb_info.Rb_id = Idx;

      memcpy(&CH_rrc_inst[Mod_id].Rab[In_idx][UE_index].Rb_info.Lchan_desc[0],&p->Lchan_desc,LCHAN_DESC_SIZE); //0 rx, 1 tx
      memcpy(&CH_rrc_inst[Mod_id].Rab[In_idx][UE_index].Rb_info.Lchan_desc[1],&p->Lchan_desc,LCHAN_DESC_SIZE); //0 rx, 1 tx

      //Configure a correponding measurement process
      msg("[RRC]Inst %d: Programing RADIO CONFIG of DTCH LCHAN %d\n",Mod_id,Idx);
      //CH_rrc_inst[Mod_id].Nb_rb[UE_index]++;
      //msg("[OPENAIR][RRC] CALLING RLC CONFIG RADIO BEARER %d\n",Idx);

      //  if(p->Mac_rlc_meas_desc !=NULL){
      if(p->Lchan_desc.Lchan_t!=DTCH) {
        Mac_meas_req.Lchan_id.Index = Idx;
        Mac_meas_req.UE_CH_index = UE_index;
        Mac_meas_req.Meas_trigger = p->Mac_rlc_meas_desc.Meas_trigger;
        Mac_meas_req.Mac_avg = p->Mac_rlc_meas_desc.Mac_avg;
        Mac_meas_req.Rep_amount = p->Mac_rlc_meas_desc.Rep_amount;
        Mac_meas_req.Rep_interval = p->Mac_rlc_meas_desc.Rep_interval;
        CH_rrc_inst[Mod_id].Rab[In_idx][UE_index].Rb_info.Meas_entry=Mac_rlc_xface->mac_meas_req(Mod_id,&Mac_meas_req);
        CH_rrc_inst[Mod_id].Rab_meas[In_idx][UE_index].Status=NEED_RADIO_CONFIG;
        CH_rrc_inst[Mod_id].Rab_meas[In_idx][UE_index].Mac_meas_req.Lchan_id.Index=Idx;
        CH_rrc_inst[Mod_id].Rab_meas[In_idx][UE_index].Last_report_frame=Rrc_xface->Frame_index;
        CH_rrc_inst[Mod_id].Rab_meas[In_idx][UE_index].Next_check_frame=Rrc_xface->Frame_index+Mac_meas_req.Rep_interval;
      }


      if(p->Lchan_desc.Lchan_t==DTCH) {
        CH_rrc_inst[Mod_id].Rab[In_idx][UE_index].Status = RADIO_CONFIG_OK;//RADIO CFG
        Mac_rlc_xface->rrc_rlc_config_req(Mod_id,CONFIG_ACTION_ADD,Idx,RADIO_ACCESS_BEARER,Rlc_info_um);
        CH_rrc_inst[Mod_id].IP_addr_type = p->L3_info_t;

        if(CH_rrc_inst[Mod_id].IP_addr_type == IPv4_ADDR) {
          memcpy(CH_rrc_inst[Mod_id].IP_addr,p->L3_info,4);
        } else {
          memcpy(CH_rrc_inst[Mod_id].IP_addr,p->L3_info,16);
        }
      } else {
        Mac_rlc_xface->rrc_rlc_config_req(Mod_id,CONFIG_ACTION_ADD,Idx,RADIO_ACCESS_BEARER,Rlc_info_am_config);
      }
    }

    if(p->Lchan_desc.Lchan_t==DTCH) {
      send_msg(&S_rrc,msg_rrc_rb_establish_cfm(Mod_id,Idx,0,Trans_id));
    } else {
      send_msg(&S_rrc,msg_rrc_rb_establish_cfm(Mod_id,Idx,1,Trans_id));
    }
  }
  break;


  case RRM_RB_MODIFY_REQ: {
    //rrm_rb_modify_req_t *p = (rrm_rb_modify_req_t *) msg ;
  }

  case RRM_RB_RELEASE_REQ: {
    //rrm_rb_release_req_t *p = (rrm_rb_release_req_t *) msg ;
  }
  }



}
