/******************************************************************************/
// @copyright   Copyright Notification
//   No part may be reproduced except as authorized by written permission.
//   The copyright and the foregoing restriction extend to reproduction in all media.
//   Trademark 2010, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TTA, TTC).
//   All rights reserved.
// @version: IWD_10wk37
// $Date: 2010-09-17 00:56:42 +0200 (Fri, 17 Sep 2010) $
// $Rev: 3946 $
/******************************************************************************/

module UpperTesterFunctions {
  import from UpperTesterDefs all;
  import from CommonDefs all;
  import from Parameters all;
  import from EPS_NAS_TypeDefs all;
  import from NAS_CommonTypeDefs all;

  //============================================================================
  // TEMPLATES (used in this module only)
  //-----------------------------------------------------------------------------

  template UT_COMMON_CNF car_UT_CnfAny :=
  { /* @status    APPROVED */
    Result          := ?,
    ResultString    := *
  };

  template (value) UT_COMMON_CMD cas_UT_Req (template (value) Ut_Common_Req_Type p_Cmd,
                                             template (value) Ut_CnfReq_Type p_Cnf,
                                             template (omit)  Ut_ParameterList_Type p_Parameters) :=
  { /* @status    APPROVED */
    Cmd := p_Cmd,
    CnfReq := p_Cnf,
    ParameterList := p_Parameters
  };

  //============================================================================
  // Common Parameters/Attributes
  //-----------------------------------------------------------------------------

  template (value) Ut_Parameter_Type cs_Ut_Parameter_Common ( charstring p_Name,
                                                              template (value) charstring p_Value ) :=
  { /* @status    APPROVED */
    Name := p_Name,
    Value := p_Value
  };

  template (value) Ut_Parameter_Type cs_Ut_Parameter_Cid ( charstring p_Value ) :=
    /* @status    APPROVED */
    cs_Ut_Parameter_Common ( "Cid", p_Value);

  template (value) Ut_Parameter_Type cs_Ut_Parameter_QoS ( charstring p_Value ) :=
    /* @status    APPROVED */
    cs_Ut_Parameter_Common ( "QoS", p_Value);

  //============================================================================
  // Parameter lists for UT primitives
  //-----------------------------------------------------------------------------

  template (value) Ut_ParameterList_Type cs_CheckPlmn ( charstring p_Value ) :=
  {
    cs_Ut_Parameter_Common ( "PLMN", p_Value)
  };

  template (value) Ut_ParameterList_Type cs_DialNumber ( charstring p_Value ) :=
  {
    cs_Ut_Parameter_Common ( "DIAL", p_Value)
  };

  template (value) Ut_ParameterList_Type cs_InsertUsim (template (value) charstring p_Value ) :=
  { /* @status    APPROVED */
    cs_Ut_Parameter_Common ( "USIM", p_Value)
  };

  template (value) Ut_ParameterList_Type cs_SecondaryPDP (charstring p_DedId,
                                                          charstring p_DefId) :=
  { /* @status    APPROVED */
    cs_Ut_Parameter_Cid ( p_DedId ),
    cs_Ut_Parameter_Common ( "DefId", p_DefId)
  };

  template (value) Ut_ParameterList_Type cs_PDP_Cid (charstring p_Cid) :=
  { /* @status    APPROVED */
    cs_Ut_Parameter_Cid ( p_Cid )
  };
  
  template (value) Ut_ParameterList_Type cs_EPSQoS (charstring p_QoSParams) :=
  { /* @status    APPROVED */
    cs_Ut_Parameter_QoS ( p_QoSParams )
  };

  template (value) Ut_ParameterList_Type cs_TFT (charstring p_TFTParams) :=
  { /* @status    APPROVED */
    cs_Ut_Parameter_Common ( "TFT", p_TFTParams)
  };

  template (value) Ut_ParameterList_Type cs_RequestPDP (charstring p_PDPParams) :=
  { /* @status    APPROVED */
    cs_Ut_Parameter_Common ( "RequestPDP", p_PDPParams )
  };
  
  template (value) Ut_ParameterList_Type cs_DeleteMessage_Withflag (charstring p_Index,
                                                                    charstring p_Delflag) :=
  {
    cs_Ut_Parameter_Common ( "Index", p_Index ),
    cs_Ut_Parameter_Common ( "Delflag", p_Delflag )
  };
  
  template (value) Ut_ParameterList_Type cs_MessageService (charstring p_Service) :=
  {
    cs_Ut_Parameter_Common ( "Service", p_Service)
  };
  
  template (value) Ut_ParameterList_Type cs_PreferredStorage (charstring p_Mem1,
                                                              charstring p_Mem2,
                                                              charstring p_Mem3) :=
  {
    cs_Ut_Parameter_Common ( "Mem1", p_Mem1 ),
    cs_Ut_Parameter_Common ( "Mem2", p_Mem2 ),
    cs_Ut_Parameter_Common ( "Mem3", p_Mem3 )
  };

  template (value) Ut_ParameterList_Type cs_MessageFormat (charstring p_Mode) :=
  {
    cs_Ut_Parameter_Common ( "Mode", p_Mode )
  };

  template (value) Ut_ParameterList_Type cs_SelectCharacterSet (charstring p_Chset) :=
  {
    cs_Ut_Parameter_Common ( "Chset", p_Chset )
  };

  template (value) Ut_ParameterList_Type cs_ServiceCentreAddress (charstring p_Sca, charstring p_Tosca) :=
  { /* @status    (APPROVED) */
    cs_Ut_Parameter_Common ( "Sca", p_Sca ),
    cs_Ut_Parameter_Common ( "Tosca", p_Tosca )
  };

  template (value) Ut_ParameterList_Type cs_WriteMessageToMemory (charstring p_Da, charstring p_Toda, charstring p_Text) :=
  {
    cs_Ut_Parameter_Common ( "Da", p_Da ),
    cs_Ut_Parameter_Common ( "Toda", p_Toda ),
    cs_Ut_Parameter_Common ( "Text", p_Text )
  };

  template (value) Ut_ParameterList_Type cs_SendMessageFromStorage (charstring p_Index) :=
  {
    cs_Ut_Parameter_Common ( "Index", p_Index )
  };

  template (value) Ut_ParameterList_Type cs_ChkMsgDisplayed (charstring p_Length, charstring p_Msg) :=
  {
    cs_Ut_Parameter_Common ( "Length", p_Length ),
    cs_Ut_Parameter_Common ( "Msg", p_Msg )
  };

  template (value) Ut_ParameterList_Type cs_SetTextModeParameters (charstring p_Fo) :=
  {
    cs_Ut_Parameter_Common ( "Fo", p_Fo )
  };
  // For SMS end
  
  template (value) Ut_ParameterList_Type cs_QoS_Profile (charstring p_Cid,
                                                         charstring p_QoSParams) :=
  {
    cs_Ut_Parameter_Cid ( p_Cid ),
    cs_Ut_Parameter_QoS ( p_QoSParams )
  };
 
  template (value) Ut_ParameterList_Type cs_OperatorFormat (charstring p_Format) :=
  {
    cs_Ut_Parameter_Common ("Format", p_Format )
  };
 
  //============================================================================
  // local functions
  //----------------------------------------------------------------------------
  /*
   * @desc      local function to send command and get confirmation
   * @param     p_Port
   * @param     p_Cmd
   * @status    APPROVED
   */
  function fl_UT_ApplyCommand(UT_PTC_MTC_PORT p_Port,
                              template (value) UT_COMMON_CMD p_Cmd)
  {
    p_Port.send(p_Cmd);
    if (match(CNF_REQUIRED, p_Cmd.CnfReq)) {
      p_Port.receive(car_UT_CnfAny);
    }
  }
  function fl_UT_ApplyCommandRetCnfValue(UT_PTC_MTC_PORT p_Port,
                              template (value) UT_COMMON_CMD p_Cmd) return UT_COMMON_CNF
  {
    var UT_COMMON_CNF v_Cnf;
    p_Port.send(p_Cmd);
    p_Port.receive(car_UT_CnfAny)
           -> value v_Cnf;
    return v_Cnf;
  }
  //============================================================================
  // public functions
  //----------------------------------------------------------------------------

  function f_UT_ConfigureCombinedAttach(UT_PTC_MTC_PORT p_Port) {
    // Objective: To ask the operator configure Combined Attach in the UE
    //TTCN waits until operation is confirmed before continuing
    if (pc_Combined_Attach and pc_Attach) { // The message is only needed if both options are supported R5-103815
      fl_UT_ApplyCommand(p_Port, cas_UT_Req(CONFIGURE_COMBINED_ATTACH, CNF_REQUIRED, omit));
    }
  }
  //----------------------------------------------------------------------------
  /*
   * @desc      Objective: To ask the operator configure EPS Attach in the UE
   *            TTCN waits until operation is confirmed before continuing
   * @param     p_Port
   * @status    APPROVED
   */
  function f_UT_ConfigureEPSAttach(UT_PTC_MTC_PORT p_Port)
  {
    if (pc_Combined_Attach and pc_Attach) { // The message is only needed if both options are supported R5-103815
      fl_UT_ApplyCommand(p_Port, cas_UT_Req(CONFIGURE_EPS_ATTACH, CNF_REQUIRED, omit));
    }
  }
  //----------------------------------------------------------------------------

  function f_UT_DisableEPS(UT_PTC_MTC_PORT p_Port) {
    // Objective: To ask the operator disable EPS in the UE
    //TTCN waits until operation is confirmed before continuing

    fl_UT_ApplyCommand(p_Port, cas_UT_Req(DISABLE_EPS, CNF_REQUIRED, omit));
  }
  //----------------------------------------------------------------------------
  /*
   * @desc      Objective: To make the operator remove the USIM card
   *            TTCN waits until operation is confirmed before continuing
   * @param     p_Port
   * @status    APPROVED
   */
  function f_UT_USIM_Remove(UT_PTC_MTC_PORT p_Port)
  {
    fl_UT_ApplyCommand(p_Port, cas_UT_Req(REMOVE_USIM, CNF_REQUIRED, omit));
  }
  //----------------------------------------------------------------------------
  /*
   * @desc      Objective: To make the operator insert the USIM card
   *            TTCN waits until operation is confirmed before continuing
   * @param     p_Port
   * @param     p_USIM_ID
   * @status    APPROVED
   */
  function f_UT_USIM_Insert(UT_PTC_MTC_PORT p_Port, template (omit) charstring p_USIM_ID )
  {
    if (isvalue(p_USIM_ID)) {
      fl_UT_ApplyCommand(p_Port, cas_UT_Req(INSERT_USIM, CNF_REQUIRED, cs_InsertUsim ( p_USIM_ID ) ) );
    } else {
      fl_UT_ApplyCommand(p_Port, cas_UT_Req(INSERT_USIM, CNF_REQUIRED, omit ) );
    }

  }
  //----------------------------------------------------------------------------
  /*
   * @desc      Objective: To power off the UE
   *            TTCN waits until operation is confirmed before continuing
   * @param     p_Port
   * @status    APPROVED
   */
  function f_UT_PowerOffUE(UT_PTC_MTC_PORT p_Port)
  {
    fl_UT_ApplyCommand(p_Port, cas_UT_Req(POWER_OFF, CNF_REQUIRED, omit));
  }
  //----------------------------------------------------------------------------
  /*
   * @desc      switch on the UE
   * @param     p_Port
   * @param     p_USIM_Rmvd
   * @status    APPROVED
   */
  function f_UT_SwitchOnUE(UT_PTC_MTC_PORT p_Port,
                           boolean p_USIM_Rmvd)
  {
    var Ut_Common_Req_Type v_Request;

    if (p_USIM_Rmvd and pc_USIM_Rmv) {  // SIM needs to be inserted
      v_Request := INSERT_USIM;
    } else if (pc_SwitchOnOff) {        // switch on the UE
      v_Request := SWITCH_ON;
    } else if (pc_USIM_Rmv) {           // UE doesn't support switch off, so SIM needs to be inserted R5-104083
      v_Request := INSERT_USIM;
    } else {                            // power on the UE
      v_Request := POWER_ON;
    }
    fl_UT_ApplyCommand(p_Port, cas_UT_Req(v_Request, NO_CNF_REQUIRED, omit));
  }
  //----------------------------------------------------------------------------
  /*
   * @desc      switch off the UE
   * @param     p_Port
   * @param     p_USIM_Rmvd
   * @status    APPROVED
   */
  function f_UT_SwitchOffUE(UT_PTC_MTC_PORT p_Port,
                            boolean p_USIM_Rmvd)
  {
    if (p_USIM_Rmvd and pc_USIM_Rmv) {  // SIM needs to be removed
      fl_UT_ApplyCommand(p_Port, cas_UT_Req(REMOVE_USIM, CNF_REQUIRED, omit));
    } else if (pc_SwitchOnOff) {        // switch off the UE
      fl_UT_ApplyCommand(p_Port, cas_UT_Req(SWITCH_OFF, NO_CNF_REQUIRED, omit));
    } else if (pc_USIM_Rmv) {  // UE doesn't support switch off, but does support SIM removal, so remove it R5-104083
      fl_UT_ApplyCommand(p_Port, cas_UT_Req(REMOVE_USIM, CNF_REQUIRED, omit));
    } else {                            // power off the UE - last resort
      fl_UT_ApplyCommand(p_Port, cas_UT_Req(POWER_OFF, CNF_REQUIRED, omit));
    }
  }
  //----------------------------------------------------------------------------
  /*
   * @desc      To convert all TFT parameters into the correct charstring format for the AT command
   * @param     p_DedicatedId
   * @param     p_Filter
   * @return    charstring
   * @status    APPROVED
   */
  function fl_GenerateATForTFTPacketFilter (integer p_DedicatedId,
                                            PacketFilter p_Filter) return charstring
  {
    var B8_Type v_Bit;
    var charstring v_IPAddress := "";
    var charstring v_ProtIdNextHeader := "";
    var charstring v_LocalPort := "";
    var charstring v_RemotePort := "";
    var charstring v_SecurityIndex := "";
    var charstring v_ToS := "";
    var charstring v_FlowLabel := "";
    var integer v_Direction;
    var charstring v_Filterstring := "";
    var PacketFilter v_Filter := p_Filter;
    var integer v_LengthOfContents := sizeof(v_Filter.contents);
    var integer i;


    v_Bit := oct2bit(v_Filter.iei);
    v_Filterstring := int2str(p_DedicatedId);
    v_Filterstring := v_Filterstring & "," & int2str(bit2int(substr(v_Bit, 4, 4))); // identifier
    v_Direction := bit2int(substr(v_Bit, 0, 4));
    v_Filterstring := v_Filterstring & "," & int2str(bit2int(v_Filter.precedence)); // precedence

    for (i := 0; i < v_LengthOfContents; i := i + 1) {
      if (ischosen(v_Filter.contents[i].packetFilterComponentValue.ipv4RemoteAddress)) { //IPv4
        v_IPAddress := fl_TFTIPAdd (v_Filter.contents[i].packetFilterComponentValue.ipv4RemoteAddress);
      }
      else if (ischosen (v_Filter.contents[i].packetFilterComponentValue.ipv6RemoteAddress)) { //IPv6
        v_IPAddress := fl_TFTIPAdd (v_Filter.contents[i].packetFilterComponentValue.ipv6RemoteAddress);
      }
      else if (ischosen(v_Filter.contents[i].packetFilterComponentValue.protocolIdNextHeader)) { //Protocol id/next header
        v_ProtIdNextHeader := fl_TFTProtHeader (v_Filter.contents[i].packetFilterComponentValue.protocolIdNextHeader);
      }
      else if (ischosen (v_Filter.contents[i].packetFilterComponentValue.singleLocalPort)) { //single local port
        v_LocalPort := fl_TFTPort (v_Filter.contents[i].packetFilterComponentValue.singleLocalPort);
      }
      else if (ischosen(v_Filter.contents[i].packetFilterComponentValue.localPortRange)) { //local port range
        v_LocalPort := fl_TFTPort (v_Filter.contents[i].packetFilterComponentValue.localPortRange);
      }
      else if (ischosen (v_Filter.contents[i].packetFilterComponentValue.singleRemotePort)) { //Single remote port
        v_RemotePort := fl_TFTPort (v_Filter.contents[i].packetFilterComponentValue.singleRemotePort);
      }
      else if (ischosen (v_Filter.contents[i].packetFilterComponentValue.remotePortRange)) { //remote port range
        v_RemotePort := fl_TFTPort (v_Filter.contents[i].packetFilterComponentValue.remotePortRange);
      }
      else if (ischosen (v_Filter.contents[i].packetFilterComponentValue.securityParameterIndex)) { //Security parameter index
        v_SecurityIndex := fl_TFTSecurity (v_Filter.contents[i].packetFilterComponentValue.securityParameterIndex);
      }
      else if (ischosen (v_Filter.contents[i].packetFilterComponentValue.typeOfServiceTrafficClass)) { //Type of Service
        v_ToS :=  fl_TFTToS (v_Filter.contents[i].packetFilterComponentValue.typeOfServiceTrafficClass);
      }
      else if (ischosen (v_Filter.contents[i].packetFilterComponentValue.flowLabel)) { //Flow Label
        v_FlowLabel := fl_TFTFlow (v_Filter.contents[i].packetFilterComponentValue.flowLabel);
      }
    }

    if (v_IPAddress == "") {
      v_Filterstring := v_Filterstring & ",";
    } else {
      v_Filterstring := v_Filterstring & "," & v_IPAddress;
    }
    if (v_ProtIdNextHeader == "") {
      v_Filterstring := v_Filterstring & ",";
    } else {
      v_Filterstring := v_Filterstring & "," & v_ProtIdNextHeader;
    }
    if (v_RemotePort == "") {
      v_Filterstring := v_Filterstring & ",";
    } else {
      v_Filterstring := v_Filterstring & "," & v_RemotePort;
    }
    if (v_LocalPort == "") {
      v_Filterstring := v_Filterstring & ",";
    } else {
      v_Filterstring := v_Filterstring & "," & v_LocalPort;
    }
    if (v_SecurityIndex == "") {
      v_Filterstring := v_Filterstring & ",";
    } else {
      v_Filterstring := v_Filterstring & "," & v_SecurityIndex;
    }
    if (v_ToS == "") {
      v_Filterstring := v_Filterstring & ",";
    } else {
      v_Filterstring := v_Filterstring & "," & v_ToS;
    }
    if (v_FlowLabel == "") {
      v_Filterstring := v_Filterstring & ",";
    } else {
      v_Filterstring := v_Filterstring & "," & v_FlowLabel;
    }
    if (v_Direction == 1) {  // Uplink and downlink are different values in AT cmd
      v_Direction := 2;
    } else if (v_Direction == 2) {
      v_Direction := 1;
    }
    v_Filterstring := v_Filterstring & "," & int2str(v_Direction);
    return (v_Filterstring);
  }
  //----------------------------------------------------------------------------
  /*
   * @desc      To convert a TFT parameter into the correct charstring format for the AT command
   * @param     p_Input
   * @return    charstring
   * @status    APPROVED
   */
  function fl_TFTIPAdd (octetstring p_Input) return charstring
  {
    var integer v_Length := lengthof (p_Input);
    var charstring v_Result:= """";
    var integer i;

    for (i := 0; i < v_Length; i := i + 1) {
      v_Result := v_Result & int2str(oct2int(p_Input[i]));
      if (i != (v_Length-1)) {
        v_Result := v_Result & ".";
      }
    }
    v_Result := v_Result & """";
    return v_Result;
  }
  //----------------------------------------------------------------------------
  /*
   * @desc      To convert a TFT parameter into the correct charstring format for the AT command
   * @param     p_Input
   * @return    charstring
   * @status    APPROVED
   */
  function fl_TFTProtHeader (octetstring p_Input) return charstring
  {
    return int2str(oct2int(p_Input));
  }
  //----------------------------------------------------------------------------
  /*
   * @desc      To convert a TFT parameter into the correct charstring format for the AT command
   * @param     p_Input
   * @return    charstring
   * @status    APPROVED
   */
  function fl_TFTPort (octetstring p_Input) return charstring
  {
    var integer v_Length := lengthof (p_Input);
    var charstring v_Result := "";

    v_Result := """";

    if (v_Length == 4) {
      v_Result := v_Result & int2str(oct2int(substr(p_Input, 0, 2)));      // @sic R5s100362 sic@
      v_Result := v_Result & "." & int2str(oct2int(substr(p_Input, 2, 2)));
    } else { // @sic R5s100362 sic@
      v_Result := v_Result & int2str(oct2int(p_Input)) & "." & int2str(oct2int(p_Input)); // only given one value, so put the same in both
    }
    
    v_Result := v_Result & """";
    return v_Result;
  }
  //----------------------------------------------------------------------------
  /*
   * @desc      To convert a TFT parameter into the correct charstring format for the AT command
   * @param     p_Input
   * @return    charstring
   * @status    APPROVED
   */
  function fl_TFTSecurity (octetstring p_Input) return charstring
  {
    return oct2str(p_Input);
  }
  //----------------------------------------------------------------------------
  /*
   * @desc      To convert a TFT parameter into the correct charstring format for the AT command
   * @param     p_Input
   * @return    charstring
   * @status    APPROVED
   */
  function fl_TFTToS (octetstring p_Input) return charstring
  {
    var charstring v_Result := "";
    v_Result := int2str(oct2int(substr(p_Input, 0, 1)));
    v_Result := v_Result & "." & int2str(oct2int(substr(p_Input, 1, 1)));
    return v_Result;
  }
  //----------------------------------------------------------------------------
  /*
   * @desc      To convert a TFT parameter into the correct charstring format for the AT command
   * @param     p_Input
   * @return    charstring
   * @status    APPROVED
   */
  function fl_TFTFlow (octetstring p_Input) return charstring
  {
    return hex2str(substr(oct2hex(p_Input), 1, 5));
  }
  //----------------------------------------------------------------------------
  function f_UT_RequestCSCall (UT_PTC_MTC_PORT p_Port,
                               charstring p_NumToDial := "01234567890")
  {
    fl_UT_ApplyCommand(p_Port, cas_UT_Req(REQUEST_CS_CALL, NO_CNF_REQUIRED, cs_DialNumber (p_NumToDial)));
  }
  //----------------------------------------------------------------------------
  function f_UT_PLMN_Check ( UT_PTC_MTC_PORT p_Port, charstring p_PLMN_ID ) {
    // Objective: To make the operator check the indicated PLMN
    // TTCN waits until operation is confirmed before continuing

    fl_UT_ApplyCommand ( p_Port, cas_UT_Req(CHECK_PLMN, CNF_REQUIRED, cs_CheckPlmn (p_PLMN_ID) ) );
  }
  //----------------------------------------------------------------------------
  /*
   * @desc      To set manual PLMN selection
   * @param     p_Port
   * @status
   */
  function f_UT_ManualPLMN_Set ( UT_PTC_MTC_PORT p_Port ) {
    // Objective: To make the operator change the UE into manual mode
    // TTCN waits until operation is confirmed before continuing

    fl_UT_ApplyCommand ( p_Port, cas_UT_Req(PLMN_MANUAL, CNF_REQUIRED, omit  ) );
  }

  //----------------------------------------------------------------------------
  /*
   * @desc      To request manual PLMN selection of PLMN
   * @param     p_Port
   * @status
   */
  function f_UT_DisplayManualPLMN_AndSelect ( UT_PTC_MTC_PORT p_Port, charstring p_PLMN_ID ) {
    // Objective: To make the operator select the specified PLMN manually (f_UT_ManualPLMN_Set MUST have already been called)
    // TTCN waits until operation is confirmed before continuing

    fl_UT_ApplyCommand ( p_Port, cas_UT_Req(SELECT_PLMN, CNF_REQUIRED, cs_CheckPlmn (p_PLMN_ID)  ) );
  }

  //----------------------------------------------------------------------------
  /*
   * @desc      To set manual PLMN selection and select PLMNN (i.e. both of the above in 1 function)
   * @param     p_Port
   * @status
   */
  function f_UT_ManualPLMN_Select ( UT_PTC_MTC_PORT p_Port, charstring p_PLMN_ID ) {
    // Objective: To make the operator change the UE into manual mode, then select the specified PLMN manually
    // TTCN waits until operation is confirmed before continuing

    fl_UT_ApplyCommand ( p_Port, cas_UT_Req(PLMN_MANUAL, CNF_REQUIRED, omit  ) );
    fl_UT_ApplyCommand ( p_Port, cas_UT_Req(SELECT_PLMN, CNF_REQUIRED, cs_CheckPlmn (p_PLMN_ID)  ) );
  }
  //----------------------------------------------------------------------------
  /*
   * @desc      To request automatic PLMN selection
   * @param     p_Port
   * @status    APPROVED
   */
  function f_UT_AutomaticPLMN_Select ( UT_PTC_MTC_PORT p_Port )
  { // Objective: To make the operator change the UE into automatic mode
    //            TTCN waits until operation is confirmed before continuing
    fl_UT_ApplyCommand ( p_Port, cas_UT_Req(PLMN_AUTOMATIC, CNF_REQUIRED, omit ) );
  }


  //----------------------------------------------------------------------------
  /*
   * @desc      To activate a dedicated LTE EPS bearer
   * @param     p_Port
   * @param     p_ActivateOrModify
   * @param     p_DedicatedId
   * @param     p_DefaultId
   * @param     p_QoS
   * @param     p_Tft
   * @status    APPROVED
   */
  function fl_UT_RequestActivateOrModifyDedicatedBearer (UT_PTC_MTC_PORT p_Port,
                                                         template (value) Ut_Common_Req_Type p_ActivateOrModify,
                                                         integer p_DedicatedId,
                                                         integer p_DefaultId,
                                                         template (value) EPS_QualityOfService p_QoS,
                                                         template (value) TrafficFlowTemplate p_Tft )
  {
    // @sic R5s100470 change 3 sic@
    var EPS_QualityOfService v_QoS := valueof (p_QoS); // need to do this to then manipulate it in the charstring
    var TrafficFlowTemplate v_Tft := valueof (p_Tft); // need to do this to then manipulate it in the charstring
    var charstring v_QoSstring := "";
    var integer v_NoOfPacketFilters := bit2int (v_Tft.noOfPktFilter);
    var integer i;

    v_QoSstring := int2str(p_DedicatedId);
    v_QoSstring := v_QoSstring &","& int2str(bit2int(v_QoS.qci));
    v_QoSstring := v_QoSstring &","& int2str(bit2int(v_QoS.guaranteedBitRateDl));
    v_QoSstring := v_QoSstring &","& int2str(bit2int(v_QoS.guaranteedBitRateUl));
    v_QoSstring := v_QoSstring &","& int2str(bit2int(v_QoS.maxBitRateDl));
    v_QoSstring := v_QoSstring &","& int2str(bit2int(v_QoS.maxBitRateUl));
    // Extended rates are not dealt with at the moment (all set to 0 in current 36.508) FFS

    fl_UT_ApplyCommand(p_Port, cas_UT_Req(REQUEST_DED_BEARER, NO_CNF_REQUIRED, cs_SecondaryPDP(int2str(p_DedicatedId), int2str(p_DefaultId))));
    fl_UT_ApplyCommand(p_Port, cas_UT_Req(DEFINE_EPS_QOS, NO_CNF_REQUIRED, cs_EPSQoS(v_QoSstring)));

    if (v_NoOfPacketFilters != 0) {
      for (i := 0; i < v_NoOfPacketFilters; i := i + 1)
        {
          fl_UT_ApplyCommand(p_Port, cas_UT_Req(DEFINE_TFT, NO_CNF_REQUIRED, cs_TFT(fl_GenerateATForTFTPacketFilter (p_DedicatedId, v_Tft.packetFilterList[i]))));
        }
    }
    fl_UT_ApplyCommand(p_Port, cas_UT_Req(p_ActivateOrModify, NO_CNF_REQUIRED, cs_PDP_Cid(int2str(p_DedicatedId))));
  }
  
  //----------------------------------------------------------------------------
  /*
   * @desc      To activate a dedicated LTE EPS bearer
   * @param     p_Port
   * @param     p_DedicatedId
   * @param     p_DefaultId
   * @param     p_QoS
   * @param     p_Tft
   * @status    APPROVED
   */
  function f_UT_RequestModifyDedicatedBearer (UT_PTC_MTC_PORT p_Port,
                                              integer p_DedicatedId,
                                              integer p_DefaultId,
                                              template (value) EPS_QualityOfService p_QoS,
                                              template (value) TrafficFlowTemplate p_Tft )
  {
    fl_UT_RequestActivateOrModifyDedicatedBearer (p_Port, MODIFY_BEARER, p_DedicatedId, p_DefaultId, p_QoS, p_Tft);
  }

  //----------------------------------------------------------------------------
  /*
   * @desc      To activate a dedicated LTE EPS bearer
   * @param     p_Port
   * @param     p_DedicatedId
   * @param     p_DefaultId
   * @param     p_QoS
   * @param     p_Tft
   * @status    APPROVED
   */
  function f_UT_RequestActivateDedicatedBearer (UT_PTC_MTC_PORT p_Port,
                                                integer p_DedicatedId,
                                                integer p_DefaultId,
                                                template (value) EPS_QualityOfService p_QoS,
                                                template (value) TrafficFlowTemplate p_Tft )
  {
    fl_UT_RequestActivateOrModifyDedicatedBearer (p_Port, ACTIVATE_BEARER, p_DedicatedId, p_DefaultId, p_QoS, p_Tft);
  }

  //----------------------------------------------------------------------------
  /*
   * @desc      To deactivate either an EPS bearer or UTRAN/GERAN PDP context
   * @param     p_Port
   * @param     p_DedicatedId
   * @status    APPROVED
   */
  function f_UT_DeactivateBearer (UT_PTC_MTC_PORT p_Port,
                                  integer p_DedicatedId)
  {
    fl_UT_ApplyCommand(p_Port, cas_UT_Req(DEACTIVATE_BEARER, NO_CNF_REQUIRED, cs_PDP_Cid(int2str(p_DedicatedId))));
  }
  //----------------------------------------------------------------------------
  /*
   * @desc      To create a PDP context on either UTRAN or GERAN
   * @param     p_Port
   * @status
   */
  function f_UT_ActivatePDPContextUTRAN (UT_PTC_MTC_PORT p_Port,
                                         integer p_CId,
                                         template (value) octetstring p_PDP_Address,
                                         template (value) QualityOfService p_QoSParams,
                                         charstring p_APN := "")  {
  var QualityOfService v_QoS := valueof (p_QoSParams);  // need to do this to then manipulate the string
  var charstring v_QoSstring := "";
  var charstring v_PDP_CtxtString := "";
  var integer v_SSDesc := bit2int(v_QoS.sourceStatisticsDescriptor);

  // string produced: "p_PDP_Type","p_AccessPointName","p_PDP_Address"
    if (p_APN != "") {
      v_PDP_CtxtString := """&p_APN&""";
    }
    v_PDP_CtxtString := v_PDP_CtxtString &",""& int2str(oct2int(valueof(p_PDP_Address))) & """;
    
  if (v_SSDesc > 1) {
    v_SSDesc := 1;  // Only allowed values are 0 or 1
  }

    v_QoSstring := v_QoSstring &","& int2str(bit2int(v_QoS.trafficClass));
    v_QoSstring := v_QoSstring &","& int2str(bit2int(v_QoS.maxBitRateUL));
    v_QoSstring := v_QoSstring &","& int2str(bit2int(v_QoS.maxBitRateDL));
    v_QoSstring := v_QoSstring &","&","&","& int2str(bit2int(v_QoS.deliveryOrder));
    v_QoSstring := v_QoSstring &","& int2str(bit2int(v_QoS.maxSduSize));
    v_QoSstring := v_QoSstring &",""& int2str(bit2int(v_QoS.sduErrorRatio))&""";
    v_QoSstring := v_QoSstring &",""& int2str(bit2int(v_QoS.residualBER))&""";
    v_QoSstring := v_QoSstring &","& int2str(bit2int(v_QoS.deliveryErrorSDU));
    v_QoSstring := v_QoSstring &","& int2str(bit2int(v_QoS.transferDelay));
    v_QoSstring := v_QoSstring &","& int2str(bit2int(v_QoS.trafficHandlingPrio));
    v_QoSstring := v_QoSstring &","& int2str(v_SSDesc);
    v_QoSstring := v_QoSstring &","& int2str(bit2int(v_QoS.signallingInd));

    fl_UT_ApplyCommand(p_Port, cas_UT_Req(DEFINE_QOS, NO_CNF_REQUIRED, cs_QoS_Profile (int2str(p_CId), v_QoSstring)));
    fl_RequestPDPContext(p_Port, p_CId, v_PDP_CtxtString);
    fl_UT_ApplyCommand(p_Port, cas_UT_Req(ACTIVATE_BEARER, NO_CNF_REQUIRED, cs_PDP_Cid(int2str(p_CId))));
  }
  //----------------------------------------------------------------------------
  /*
   * @desc      To request an additional PDN connection - to be associated with an already existing bearer (p_BearerId)
   * @param     p_Port
   * @param     p_BearerId - The id of the already existing bearer
   * @param     p_APN
   * @status    APPROVED
   */
  function f_UT_RequestAdditionalPDNConnectivity (UT_PTC_MTC_PORT p_Port,
                                                  integer p_BearerId,
                                                  charstring p_APN := "") // @sic R5s100466 sic@
  {
    var charstring v_Cmd := "";
    
    if (p_APN != "") {
      v_Cmd := """&p_APN&"""; // @sic R5s100466 sic@
    }
    fl_RequestPDPContext(p_Port, p_BearerId, v_Cmd);
    fl_UT_ApplyCommand(p_Port, cas_UT_Req(ACTIVATE_BEARER, NO_CNF_REQUIRED, cs_PDP_Cid(int2str(p_BearerId))));
  }
  //----------------------------------------------------------------------------
  /*
   * @desc      Used by LTE, UTRAN and GERAN to send the DCONT AT command
   * @param     p_Port
   * @param     p_BearerId
   * @param     p_RestOfCmd
   * @status    APPROVED
   */
  function fl_RequestPDPContext (UT_PTC_MTC_PORT p_Port,
                                 integer p_BearerId,
                                 charstring p_RestOfCmd)
  { // @sic R5s100466 change 5 sic@
    var charstring v_Cmd := "";
    var charstring v_Type := """IP""";

    if ( pc_IPv6 and (not pc_IPv4)) {
      v_Type := """IPV6""";
    }
    if ( pc_IPv6 and pc_IPv4) {
      v_Type := """IPV4V6""";
    }
    v_Cmd := v_Cmd & int2str(p_BearerId);
    v_Cmd := v_Cmd & "," & v_Type;

    v_Cmd := v_Cmd & "," & p_RestOfCmd; // @sic R5s100520 sic@
    fl_UT_ApplyCommand(p_Port, cas_UT_Req(REQUEST_PDPCONTEXT, NO_CNF_REQUIRED, cs_RequestPDP(v_Cmd)));
  }
  //----------------------------------------------------------------------------
  /*
   * @desc      To attach for PS services
   * @param     p_Port
   * @status    APPROVED
   */
  function f_UT_TriggerAttach (UT_PTC_MTC_PORT p_Port)
  {
    fl_UT_ApplyCommand(p_Port, cas_UT_Req(ATTACH, NO_CNF_REQUIRED, omit));
  }
  //----------------------------------------------------------------------------
  /*
   * @desc      To detach for PS services only
   * @param     p_Port
   * @status    APPROVED
   */
  function f_UT_InitiateDetach_EPSOnly (UT_PTC_MTC_PORT p_Port)
  {
    fl_UT_ApplyCommand(p_Port, cas_UT_Req(DETACH, NO_CNF_REQUIRED, omit));
  }

  //----------------------------------------------------------------------------
  // Function to check that the result string starts with specific value
  function f_CheckStringStartWith(charstring p_SourceString, charstring p_StartString)
  return boolean
  {
    var integer v_Length := lengthof(p_StartString);
    var charstring v_SubStr :="";

    if (v_Length > lengthof(p_SourceString))
    {
       return false;
    }

    v_SubStr := substr(p_SourceString, 0, v_Length);
    if( v_SubStr == p_StartString )
    {
       return true;
    }
    else
    {
       return false;
    }
  } // f_CheckStringStartWith

  //----------------------------------------------------------------------------
  function f_UT_SelectMessageService (UT_PTC_MTC_PORT p_Port, charstring p_Service) return charstring {
    var UT_COMMON_CNF v_Cnf;
    v_Cnf := fl_UT_ApplyCommandRetCnfValue(p_Port, cas_UT_Req(SELECT_MESSAGE_SERVICE, CNF_REQUIRED, cs_MessageService(p_Service)));

    if(ispresent(v_Cnf.ResultString) == false)
    {
        return "";
    }

    return v_Cnf.ResultString;
  }
  //----------------------------------------------------------------------------
  function f_UT_SetPreferredMessageStorage (UT_PTC_MTC_PORT p_Port, charstring p_Mem1, charstring p_Mem2, charstring p_Mem3) return charstring {
    var UT_COMMON_CNF v_Cnf;
    v_Cnf := fl_UT_ApplyCommandRetCnfValue(p_Port, cas_UT_Req(SET_PREFERRED_STORAGE, CNF_REQUIRED, cs_PreferredStorage(p_Mem1, p_Mem2, p_Mem3)));

    if(ispresent(v_Cnf.ResultString) == false)
    {
        return "";
    }

    return v_Cnf.ResultString;
  }
  //----------------------------------------------------------------------------
  function f_UT_SetMessageFormat (UT_PTC_MTC_PORT p_Port, charstring p_Mode) return charstring {
    var UT_COMMON_CNF v_Cnf;
    v_Cnf := fl_UT_ApplyCommandRetCnfValue(p_Port, cas_UT_Req(MESSAGE_FORMAT, CNF_REQUIRED, cs_MessageFormat(p_Mode)));

    if(ispresent(v_Cnf.ResultString) == false)
    {
        return "";
    }

    return v_Cnf.ResultString;
  }
  //----------------------------------------------------------------------------
  function f_UT_SelectCharacterSet (UT_PTC_MTC_PORT p_Port, charstring p_Chset) return charstring {
    var UT_COMMON_CNF v_Cnf;
    v_Cnf := fl_UT_ApplyCommandRetCnfValue(p_Port, cas_UT_Req(SELECT_CHARACTER_SET, CNF_REQUIRED, cs_SelectCharacterSet(p_Chset)));

    if(ispresent(v_Cnf.ResultString) == false)
    {
        return "";
    }

    return v_Cnf.ResultString;
  }

  //----------------------------------------------------------------------------
  function f_UT_DeleteMessageFromStorage_DELFLAG (UT_PTC_MTC_PORT p_Port, integer p_Index, integer p_Delflag) return charstring {
    var UT_COMMON_CNF v_Cnf;
    v_Cnf := fl_UT_ApplyCommandRetCnfValue(p_Port, cas_UT_Req(DELETE_MESSAGE_WITHFLAG, CNF_REQUIRED, cs_DeleteMessage_Withflag(int2str(p_Index), int2str(p_Delflag))));

    if(ispresent(v_Cnf.ResultString) == false)
    {
        return "";
    }

    return v_Cnf.ResultString;
  }

  //----------------------------------------------------------------------------
  function f_UT_ServiceCentreAddress (UT_PTC_MTC_PORT p_Port, charstring p_Sca, integer p_Tosca) return charstring {
    var UT_COMMON_CNF v_Cnf;
    v_Cnf := fl_UT_ApplyCommandRetCnfValue(p_Port, cas_UT_Req(SERVICE_CENTRE_ADDRESS, CNF_REQUIRED, cs_ServiceCentreAddress(p_Sca, int2str(p_Tosca))));

    if(ispresent(v_Cnf.ResultString) == false)
    {
        return "";
    }

    return v_Cnf.ResultString;
  }
  //----------------------------------------------------------------------------
  function f_UT_WriteMessageToMemoryText (UT_PTC_MTC_PORT p_Port, charstring p_Da, charstring p_Toda, charstring p_Text) return charstring {
    var UT_COMMON_CNF v_Cnf;
    v_Cnf := fl_UT_ApplyCommandRetCnfValue(p_Port, cas_UT_Req(WRITE_MESSAGE_TOMEMORY_TEXTMODE, CNF_REQUIRED, cs_WriteMessageToMemory(p_Da, p_Toda, p_Text)));

    if(ispresent(v_Cnf.ResultString) == false)
    {
        return "";
    }

    return v_Cnf.ResultString;
  }
  //----------------------------------------------------------------------------
  function f_UT_SendStoredOneMessage (UT_PTC_MTC_PORT p_Port, integer p_Index) return charstring {
    var UT_COMMON_CNF v_Cnf;
    v_Cnf := fl_UT_ApplyCommandRetCnfValue(p_Port, cas_UT_Req(SEND_STORED_MESSAGE_ONE, CNF_REQUIRED, cs_SendMessageFromStorage(int2str(p_Index))));

    if(ispresent(v_Cnf.ResultString) == false)
    {
        return "";
    }

    return v_Cnf.ResultString;
  }
  //----------------------------------------------------------------------------
  function f_UT_SetTextModeParameters (UT_PTC_MTC_PORT p_Port, integer p_Fo) return charstring {
    var UT_COMMON_CNF v_Cnf;
    v_Cnf := fl_UT_ApplyCommandRetCnfValue(p_Port, cas_UT_Req(SET_TEXTMODE_PARAMETERS, CNF_REQUIRED, cs_SetTextModeParameters(int2str(p_Fo))));

    if(ispresent(v_Cnf.ResultString) == false)
    {
        return "";
    }

    return v_Cnf.ResultString;
  }
  //----------------------------------------------------------------------------
  function f_UT_ChkMsgDisplayed(UT_PTC_MTC_PORT p_Port, integer p_Length, charstring p_Msg) return boolean {
    // To make the operator check an MT Short Message received
    var UT_COMMON_CNF v_Cnf;
    v_Cnf := fl_UT_ApplyCommandRetCnfValue(p_Port, cas_UT_Req(CHECK_MESSAGE_DISPLAYED, CNF_REQUIRED, cs_ChkMsgDisplayed(int2str(p_Length), p_Msg)));

    return v_Cnf.Result;
  }
  //----------------------------------------------------------------------------
  /*
   * @desc      To request the current time - returned in the format "yy/MM/dd,hh:mm:ss?zz",
   *            where characters indicate year (two last digits), month, day, hour, minutes, seconds and time zone
   * @param     p_Port
   * @status
   */
  function f_UT_ChkTimeZone (UT_PTC_MTC_PORT p_Port) return charstring {
    var UT_COMMON_CNF v_Cnf;
    var charstring v_Time := "";
    var integer v_Length, v_TimeZone;
    v_Cnf := fl_UT_ApplyCommandRetCnfValue(p_Port, cas_UT_Req(CHECK_CLOCK, CNF_REQUIRED, omit));

    if(ispresent(v_Cnf.ResultString) == false)
    {
        return "";
    }
    
    v_Time := v_Cnf.ResultString;
    v_Length := lengthof (v_Time);
    if (v_Time [v_Length-2] == "+" ) { // if 3rd to last character is +
      v_TimeZone := str2int(v_Time[v_Length-1])/4; // The AT command stores the timezone as a multiple of 1/4 of an hour
      v_Time := substr(v_Time, 0, v_Length-1 ) & int2str (v_TimeZone); // So adjust it to no. of hours and then put it back
    }

    return v_Time;
  }
  //----------------------------------------------------------------------------
  type enumerated UT_OPERATOR_FORMAT { LONG_NAME, SHORT_NAME, NUMERIC_ONLY}
  /*
   * @desc      To request the name of the operator currently camped on
   * @param     p_Port
   * @param     p_Format - Use the enumerated type defined just above to select the UE to return the operator name in long short or numeric only format
   * @status
   */
  function f_UT_ChkOperatorName (UT_PTC_MTC_PORT p_Port, UT_OPERATOR_FORMAT p_Format) return charstring {
    var UT_COMMON_CNF v_Cnf;
    v_Cnf := fl_UT_ApplyCommandRetCnfValue(p_Port, cas_UT_Req(CHECK_OPERATOR_NAME, CNF_REQUIRED, cs_OperatorFormat(int2char(enum2int(p_Format)))));

    if(ispresent(v_Cnf.ResultString) == false)
    {
        return "";
    }

    return v_Cnf.ResultString;
  }
  //----------------------------------------------------------------------------
  /*
   * @desc      To answer a CS call
   * @param     p_Port
   * @status
   */
  function f_UT_AnswerCSCall (UT_PTC_MTC_PORT p_Port)
  {
    fl_UT_ApplyCommand(p_Port, cas_UT_Req(ANSWER_CS_CALL, NO_CNF_REQUIRED, omit));
  }
    
  
}
