/***************************************************************************
                          rrc_rg_process.c  -  description
                             -------------------
    begin                : May 29, 2002
    copyright            : (C) 2002, 2010 by Eurecom
    email                : Michelle.Wetterwald@eurecom.fr
 **************************************************************************
  Procedures associated with the rrc_rg.c file generated by Esterel Studio
 ***************************************************************************/
/********************
//OpenAir definitions
 ********************/
#include "LAYER2/MAC/extern.h"
#include "UTIL/MEM/mem_block.h"

/********************
// RRC definitions
 ********************/
#include "rrc_rg_vars.h"
#include "rrc_messages.h"
//-----------------------------------------------------------------------------
#include "rrc_proto_fsm.h"
#include "rrc_proto_intf.h"
#include "rrc_proto_msg.h"
//#include "rlc.h"

//-----------------------------------------------------------------------------
/* Generic function to encode RRC messages */
void encode_message (int *Message_Id, int UE_Id, int Message_Type){
//-----------------------------------------------------------------------------
  #ifdef DEBUG_RRC_STATE
   msg ("[RRC][FSM-PROC]encode message %d for UE %d\n", Message_Type, UE_Id);
  #endif
  if (protocol_bs->rrc.Mobile_List[UE_Id].rg_msg_infos.msg_length) {
    #ifdef DEBUG_RRC_STATE
     msg ("\n\n[RRC_MSG] There is already one message pending %d\n", protocol_bs->rrc.Mobile_List[UE_Id].rg_msg_infos.msg_Id);
    #endif
  } else {
    switch (Message_Type) {
      case RRC_CONN_SETUP:
        rrc_rg_msg_connsetup (UE_Id, Message_Id);
        protocol_bs->rrc.Mobile_List[UE_Id].conn_complete_timer = 1;
        break;
      case RRC_CONN_REJECT:
        rrc_rg_msg_connreject (UE_Id, Message_Id);
        break;
      case RRC_CONN_RELEASE: // not in 1st step
        break;
      case RB_SETUP:
        rrc_rg_msg_rbsetup (UE_Id, Message_Id);
        break;
      case RB_RELEASE:
        rrc_rg_msg_rbrelease (UE_Id, Message_Id);
        break;
      case CELL_UPDATE_CONFIRM:
        rrc_rg_msg_cellupdatecnfccch (UE_Id, Message_Id);
        break;
      case UE_CAPABILITY_INFO_CONF:
        rrc_rg_msg_ueCapInfoCnf(UE_Id, Message_Id);
        break;
      default:
        msg ("\n\n[RRC_MSG] unknown message type %d\n", Message_Type);
        break;
    }
  }
}

//-------------------------------------------------------------------
int Current_State (int UE_Id){
//-------------------------------------------------------------------
  int curr_state;
  curr_state = protocol_bs->rrc.Mobile_List[UE_Id].state;

  #ifdef DEBUG_RRC_STATE
   msg ("[RRC_RG][FSM-PROC]returning state %d for mobile %d. \n", curr_state, UE_Id);
  #endif
  // rrc_mt_list_print(UE_Id);
  return curr_state;
}

//-------------------------------------------------------------------
int INTEGER_COMBINE (int Id1, int Id2){
//-------------------------------------------------------------------
  // signals an error in the automata. Combination should never occur.
  return 999;
}

//-------------------------------------------------------------------
int BOOLEAN_COMBINE (int Id1, int Id2){
//-------------------------------------------------------------------
  // signals an error in the automata. Combination should never occur.
  return FALSE;
}


/* Management of Mobile Nodes
 */
//-------------------------------------------------------------------
void create_Mobile (int UE_Id){
//-------------------------------------------------------------------
  // rrm_simulate_download_configuration(); /*      Added, 1/10/02 by DN      */
  #ifdef DEBUG_RRC_STATE
   msg ("[RRC_RG][FSM-PROC]creating Mobile %d with state Conn_Received. \n", UE_Id);
  #endif
  protocol_bs->rrc.Mobile_List[UE_Id].mt_id = UE_Id;
  protocol_bs->rrc.Mobile_List[UE_Id].state = Conn_Received;
  //this is an implementation choice and agreement with NAS
  protocol_bs->rrc.Mobile_List[UE_Id].local_connection_ref = UE_Id;
  protocol_bs->rrc.Mobile_List[UE_Id].established_background = FALSE;
  protocol_bs->rrc.Mobile_List[UE_Id].num_rb = 0 ;
  // Initialize message area
  protocol_bs->rrc.Mobile_List[UE_Id].rg_msg_infos.msg_length = 0;
  protocol_bs->rrc.Mobile_List[UE_Id].rg_msg_infos.msg_Id = 0;
  protocol_bs->rrc.Mobile_List[UE_Id].rg_msg_infos.msg_ptr = 0;
  protocol_bs->rrc.Mobile_List[UE_Id].rg_msg_infos.mem_block_ptr = 0;
  protocol_bs->rrc.Mobile_List[UE_Id].ul_nas_message_lgth = 0;
  protocol_bs->rrc.Mobile_List[UE_Id].dl_nas_message_lgth = 0;
  protocol_bs->rrc.Mobile_List[UE_Id].paging_message_lgth = 0;

}

//-------------------------------------------------------------------
void update_Mobile (int UE_Id, int new_state){
//-------------------------------------------------------------------
  #ifdef DEBUG_RRC_STATE
   msg ("[RRC_RG][FSM-PROC]updating Mobile %d to new state %d .\n", UE_Id, new_state);
  #endif
  protocol_bs->rrc.Mobile_List[UE_Id].mt_id = UE_Id;
  protocol_bs->rrc.Mobile_List[UE_Id].state = new_state;
  protocol_bs->rrc.protocol_state[UE_Id] = new_state;
}

//-------------------------------------------------------------------
void delete_Mobile (int UE_Id){
//-------------------------------------------------------------------
  int j;
  #ifdef DEBUG_RRC_STATE
   msg ("[RRC_RG][FSM-PROC]deleting Mobile %d .\n", UE_Id);
  #endif
  protocol_bs->rrc.Mobile_List[UE_Id].mt_id = 999;
  protocol_bs->rrc.Mobile_List[UE_Id].local_connection_ref = 999;
  protocol_bs->rrc.Mobile_List[UE_Id].u_rnti = 999;
  protocol_bs->rrc.Mobile_List[UE_Id].state = RRC_CELL_IDLE;
  protocol_bs->rrc.protocol_state[UE_Id] = RRC_CELL_IDLE;
  strcpy (protocol_bs->rrc.Mobile_List[UE_Id].IMEI, "01231234564569");
  for (j = 4; j < maxRB; j++) {
    protocol_bs->rrc.Mobile_List[UE_Id].rg_established_rbs[j].rb_identity = 99;
    protocol_bs->rrc.Mobile_List[UE_Id].rg_established_rbs[j].rb_started = RB_STOPPED;
    protocol_bs->rrc.Mobile_List[UE_Id].rg_established_rbs[j].qos_class = 0;
    protocol_bs->rrc.Mobile_List[UE_Id].rg_established_rbs[j].dscp_code = 0;
    protocol_bs->rrc.Mobile_List[UE_Id].rg_established_rbs[j].sap_id = 3;
  }
  protocol_bs->rrc.Mobile_List[UE_Id].num_rb = 0;
  protocol_bs->rrc.Mobile_List[UE_Id].establishment_cause = 0;
  protocol_bs->rrc.Mobile_List[UE_Id].prot_error_indicator = FALSE;
  protocol_bs->rrc.Mobile_List[UE_Id].established_background = FALSE;
}

/* Other processes for ESTEREL
 */
//-------------------------------------------------------------------
//void proc_RB_List (int *Message_Id, int rb_id){
void proc_RB_List(int *Message_Id, int rb_id, int UE_Id){
//-------------------------------------------------------------------
  #ifdef DEBUG_RRC_STATE
  //  msg ("[RRC_RG][FSM-PROC]proc_RB_List(), %d .\n", rb_id);
   msg("[RRC_RG][FSM-PROC]proc_RB_List(), %d , UE_Id = %d.\n",  rb_id, UE_Id);
  #endif
  protocol_bs->rrc.Mobile_List[UE_Id].rg_established_rbs[rb_id].rb_identity = protocol_bs->rrc.Mobile_List[UE_Id].requested_rbId;
  protocol_bs->rrc.Mobile_List[UE_Id].rg_established_rbs[rb_id].qos_class = protocol_bs->rrc.Mobile_List[UE_Id].requested_QoSclass;
  protocol_bs->rrc.Mobile_List[UE_Id].rg_established_rbs[rb_id].dscp_code = protocol_bs->rrc.Mobile_List[UE_Id].requested_dscp;
  protocol_bs->rrc.Mobile_List[UE_Id].rg_established_rbs[rb_id].rb_started = RB_STOPPED;
  //Temp
  *Message_Id = 555;
}

//-------------------------------------------------------------------
void release_DCH_Resources (int UE_Id){
//-------------------------------------------------------------------
  #ifdef DEBUG_RRC_STATE
   msg ("[RRC_RG][FSM-PROC]releasing DCH resources for Mobile %d .\n", UE_Id);
  #endif
  //rrc_rg_connection_mac_release(UE_Id);
  //rrc_rg_connection_srb_release(UE_Id);
  //rrc_rg_connection_rb_release(UE_Id);
  #ifndef BYPASS_L1
  //rrc_rg_connection_L1_release(UE_Id);
  #endif
  cmac_config_req (UE_Id, 0);
  crb_config_req (0);
  #ifndef BYPASS_L1
  CPHY_config_req (rrm_config, 0, 0);
  #endif
}

//-------------------------------------------------------------------
void restore_former_config (int UE_Id){
//-------------------------------------------------------------------
  #ifdef DEBUG_RRC_STATE
   msg ("[RRC_RG][FSM-PROC]NI--restoring former Radio configuration for Mobile %d.\n", UE_Id);
  #endif
}

//-------------------------------------------------------------------
void rg_clear_transaction (int UE_Id, int Message_Type){
//-------------------------------------------------------------------
  int i;
  #ifdef DEBUG_RRC_STATE
   msg ("[RRC_RG][FSM-PROC]clearing transaction ID for message %d and Mobile %d.\n", Message_Type, UE_Id);
  #endif
  protocol_bs->rrc.Mobile_List[UE_Id].xmit_trans[0].transaction_Id = 0;
  //save valid configuration for ms
  memcpy (&(protocol_bs->rrc.saved_configuration.mt_config[UE_Id]), &(rrm_config)->mt_config[UE_Id], sizeof (MT_CONFIG));
  //save valid configuration for bs
  memcpy (&(protocol_bs->rrc.saved_configuration.rg_config), &(rrm_config->rg_config), sizeof (RG_CONFIG));
  //clean commands in configuration
  for (i = 0; i < JRRM_MAX_COMMANDS_PER_TRANSACTION; i++) {
    (&(rrm_config->rg_config))->rrm_commands[i].rrm_action = 0;
  }
  for (i = 0; i < JRRM_MAX_COMMANDS_PER_TRANSACTION; i++) {
    (&(rrm_config)->mt_config[UE_Id])->rrm_commands[i].rrm_action = 0;
  }
  switch (Message_Type) {
    case RRC_CONN_SETUP:
      break;
    case RB_SETUP:
    case RB_RELEASE:
      //protocol_bs->rrc.Mobile_List[UE_Id].requested_rbId = 0;
      //protocol_bs->rrc.Mobile_List[UE_Id].requested_QoSclass = 0;
      //protocol_bs->rrc.Mobile_List[UE_Id].requested_dscp = 0;
      break;
    default:
      break;
  }
  // transaction is closed. Clear rrc_UE_updating Id with out of range value
  protocol_bs->rrc.rrc_UE_updating = maxUsers;
}

//-------------------------------------------------------------------
void clear_rbsetup_variables(int UE_Id){
//-------------------------------------------------------------------
  int new_cctrch;
  int rb_id;
  int qos_class;

  //Temp - Store cctrch
  #ifdef DEBUG_RRC_STATE
   msg ("[RRC_RG][FSM-PROC] clear_rbsetup_variables - Store cctrch %d.\n", new_cctrch);
  #endif
  // commented for OpenAir
  //new_cctrch = rrm_get_ue_cctrch_index_ul (UE_Id, protocol_bs->rrc.Mobile_List[UE_Id].requested_rbId);
  new_cctrch = 0;
  rrc_rg_CPHY_Synch_rx (new_cctrch);

  #ifdef DEBUG_RRC_STATE
   msg("[RRC_RG][FSM-PROC] clearing variables after RB setup completion for Mobile %d.\n", UE_Id);
  #endif
  rb_id = protocol_bs->rrc.Mobile_List[UE_Id].requested_rbId;
  protocol_bs->rrc.Mobile_List[UE_Id].rg_established_rbs[rb_id].rb_started = RB_STARTED;
  qos_class = protocol_bs->rrc.Mobile_List[UE_Id].requested_QoSclass;
  if (qos_class == 7 || qos_class == 8 || qos_class == 9) {
    protocol_bs->rrc.Mobile_List[UE_Id].established_background = TRUE;
  }
  protocol_bs->rrc.Mobile_List[UE_Id].requested_rbId = 0;
  protocol_bs->rrc.Mobile_List[UE_Id].requested_QoSclass = 0;
  protocol_bs->rrc.Mobile_List[UE_Id].requested_dscp = 0;
  protocol_bs->rrc.Mobile_List[UE_Id].requested_MTrbId = 0;
  protocol_bs->rrc.Mobile_List[UE_Id].requested_sapid = 0;
  rrm_add_radio_access_bearer_confirm(UE_Id, rb_id);

}

//-------------------------------------------------------------------
void clear_rbrelease_variables(int UE_Id){
//-------------------------------------------------------------------
  #ifdef DEBUG_RRC_STATE
   msg("[RRC_RG][FSM-PROC] clearing variables after RB release completion for Mobile %d.\n", UE_Id);
  #endif
}

//-------------------------------------------------------------------
void rg_update_UE_numrb(int UE_Id, int Action){
//-------------------------------------------------------------------
  #ifdef DEBUG_RRC_STATE
   msg("[RRC_RG][FSM-PROC] rg_update_UE_numrb (action %d) for Mobile %d.\n", Action, UE_Id);
  #endif
  switch (Action){
    case E_ADD_RB:
      ++protocol_bs->rrc.Mobile_List[UE_Id].num_rb;
      break;
    case E_REL_RB:
      --protocol_bs->rrc.Mobile_List[UE_Id].num_rb; //Temp
      break;
    default:
      break;
  }
}

//-------------------------------------------------------------------
/* See comments in rrc_constant.h
   TEMP - This should be part of the Esterel FSM  */
void rrc_rg_temp_checkConnection(int UE_Id){
//-------------------------------------------------------------------
 if (protocol_bs->rrc.Mobile_List[UE_Id].conn_complete_timer < RG_CONN_TIMEOUT)
    protocol_bs->rrc.Mobile_List[UE_Id].conn_complete_timer ++;
 else if (protocol_bs->rrc.Mobile_List[UE_Id].conn_complete_timer == RG_CONN_TIMEOUT){
    msg("\n[RRC_RG][XXFSM-PROCXX] ERROR - Timeout expired before receiving CONN_SETUP_COMPLETE \n");
    msg("\t Calling FSM to clean MT resources\n\n");
    protocol_bs->rrc.Mobile_List[UE_Id].conn_complete_timer =0;
    rrc_rg_fsm_control(UE_Id, RG_CRLC_STATUS);
 }
}

//-----------------------------------------------------------------------------
// TEMP - This should be part of the Esterel FSM
void rrc_RG_UE_Cap_Info_rx(int UE_Id){
//-----------------------------------------------------------------------------
  int msgId;
  //Send the message UE Capability Confirm.
  #ifdef DEBUG_RRC_STATE
    msg("[RRC_RG][XXFSM-PROCXX] UE Capability Received from UE.\n");
  #endif
  encode_message(&msgId, UE_Id, UE_CAPABILITY_INFO_CONF);
  RRC_RG_O_O_SEND_DCCH_AM(msgId);
}
