/******************************************************************************/
// @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-13 12:42:27 +0200 (Mon, 13 Sep 2010) $
// $Rev: 3856 $
/******************************************************************************/

module MTC_Main {
  import from MTC_Component all;
  import from EUTRA_Component all;
  import from UTRAN_Component all;
  import from GERAN_Component all;
  import from CDMA2000_Component all;
  import from NasEmu_Component all;
  import from MTC_UpperTester all;
  import from NasEmu all;      // f_NASEMU_MainLoop
  import from IP_PTC_Component all;
  import from IP_PTC_Main all;
  import from CommonDefs all;

  //============================================================================
  /*
   * @desc      Terminate the MTC
   * @param     p_Verdict
   * @status    APPROVED
   */
  function fl_MTC_Stop(verdicttype p_Verdict)
  {
    /* Note: the assignment of the final verdict is according to table 28 in the TTCN-3 core spec (cl. 24.1);
       i.e. at the end of a test case "pass" may always be assigned since it overrules "none" only */
    setverdict(p_Verdict);
    all component.stop;                       // stop the NAS emulator and IP PTC
    mtc.stop;
  }
  //============================================================================
  /*
   * @desc      Create IP PTC and start the main loop
   * @status    APPROVED
   */
  function f_MTC_CreateAndStartIP() runs on MTC
  {
    var IP_PTC v_IP_PTC := IP_PTC.create alive;

    if (vc_Components.Eutra != null) {
      connect(vc_Components.Eutra:IP, v_IP_PTC:EUTRA_CTRL);
    }
    if (vc_Components.Utran != null) {
      //connect(vc_Components.Utran:IP, v_IP_PTC:UTRAN_CTRL);
    }
    if (vc_Components.Geran != null) {
      //connect(vc_Components.Geran:IP, v_IP_PTC:GERAN_CTRL);
    }

    map(v_IP_PTC:IP_CTRL, system:IP_CTRL);
    map(v_IP_PTC:IP_SOCK, system:IP_SOCK);

    v_IP_PTC.start(f_IP_PTC_MainLoop());
  }
  //============================================================================
  /*
   * @desc      Connect all PTCs
   * @param     p_Eutra EUTRA_PTC
   * @param     p_Utran UTRAN_PTC
   * @param     p_Geran GERAN_PTC
   * @param     p_Cdma2000 CDMA2000_PTC
   * @status    APPROVED
   */
  function f_MTC_ConnectPTCs(EUTRA_PTC p_Eutra,
                             UTRAN_PTC p_Utran,
                             GERAN_PTC p_Geran,
                             CDMA2000_PTC p_Cdma2000) runs on MTC
  { /* @sic R5-104796 change 12: CDMA2000 added sic@ */
    var NASEMU_PTC v_NASEMU_PTC := null;

    vc_Components.Eutra := p_Eutra;
    vc_Components.Utran := p_Utran;
    vc_Components.Geran := p_Geran;
    vc_Components.Cdma2000 := p_Cdma2000;

    // map MTC's system ports:
    map(self:Ut, system:Ut);

    if (p_Eutra == null) {
      FatalError (__FILE__, __LINE__, "invalid configuration");
      mtc.stop;

    } else {

      v_NASEMU_PTC := NASEMU_PTC.create alive;

      // ***** EUTRA PTC *****

      // create EUTRA's UT connection to the MTC:
      connect(vc_Components.Eutra:UT,       self:E_Ut);

      // create and connect NAS emulation:
      connect(vc_Components.Eutra:NASCTRL,  v_NASEMU_PTC:CTRL);
      connect(vc_Components.Eutra:SRB,      v_NASEMU_PTC:TC_SRB);

      // map system ports:
      map(vc_Components.Eutra:SYS,      system:E_SYS);
      map(vc_Components.Eutra:SYSIND,   system:E_SYSIND);
      map(vc_Components.Eutra:DRB,      system:E_DRB);

      map(v_NASEMU_PTC:SYS_SRB,  system:E_SRB);

      v_NASEMU_PTC.start(f_NASEMU_MainLoop());

    }
    if (p_Utran != null) {
      // ***** UTRAN PTC *****

      // create UTRAN's UT connection to the MTC:
      connect(vc_Components.Utran:UT,    self:U_Ut);

      // create connection for coordination messages between EUTRA an UTRAN
      connect(vc_Components.Eutra:UTRAN, vc_Components.Utran:EUTRA);

      // map system ports:
      map(vc_Components.Utran:U_AM,    system:S_U_AM);
      map(vc_Components.Utran:U_TM,    system:S_U_TM);
      map(vc_Components.Utran:U_UM,    system:S_U_UM);
      map(vc_Components.Utran:U_CPHY,  system:S_U_CPHY);
      map(vc_Components.Utran:U_CMAC,  system:S_U_CMAC);
      map(vc_Components.Utran:U_CRLC,  system:S_U_CRLC);
      map(vc_Components.Utran:U_Dc,    system:S_U_Dc);

    }
    if (p_Geran != null) {
      // ***** GERAN PTC *****

      // create GERAN's UT connection to the MTC:
      connect(vc_Components.Geran:UT,    self:G_Ut);

      // create connection for coordination messages between EUTRA and GERAN
      connect(vc_Components.Eutra:GERAN, vc_Components.Geran:EUTRA);

      // map system ports:
      map(vc_Components.Geran:G_CL1,   system:S_G_CL1);
      map(vc_Components.Geran:G_CLLC,  system:S_G_CLLC);
      map(vc_Components.Geran:G_CRLC,  system:S_G_CRLC);
      map(vc_Components.Geran:G_L2,    system:S_G_L2);
      map(vc_Components.Geran:G_LLC,   system:S_G_LLC);
      map(vc_Components.Geran:G_RLC,   system:S_G_RLC);

    }
    if (p_Cdma2000 != null) {
      // ***** CDMA2000 PTC *****

      // create CDMA2000's UT connection to the MTC:
      connect(vc_Components.Cdma2000:UT,    self:CDMA2000_Ut);

      // create connection for coordination messages between EUTRA and CDMA2000
      connect(vc_Components.Eutra:CDMA2000, vc_Components.Cdma2000:EUTRA);

      // map system ports:
      map(vc_Components.Cdma2000:SYS,        system:CDMA2000_SYS);
      map(vc_Components.Cdma2000:SYSCMD_IND, system:CDMA2000_SYSCMD_IND);
      map(vc_Components.Cdma2000:RLP_FLOW,   system:CDMA2000_RLP_FLOW);
    }

    if ((p_Geran != null) and (p_Utran != null)) {
      // FFS: any connection between GERAN and UTRAN needed ???
      // connect(p_Utran:PortToGERAN, p_Geran:PortToUtran);        // connect UTRAN and GERAN
    }

    f_MTC_CreateAndStartIP();
  }
  //----------------------------------------------------------------------------
  /*
   * @desc      Interface to control the other components
   * @status    APPROVED
   */
  altstep a_PTC_Control() runs on MTC {
  [] any component.killed
    { // at a component something's gone wrong and it killed itself, so have to stop everything else
      all component.kill;
      mtc.stop;
    }
  [] any component.done
    { /* since the NAS emulator is a parallel component which does not terminate on its own we need to check all components;
         NOTE: acc. to ES 201 873-1 Annex F.1.1 an error verdict shall be assignd when "running" is applied on any uninitialised component */
      if ((vc_Components.Eutra != null) and vc_Components.Eutra.running) {        // EUTRA is still running
        // do nothing
      } else if ((vc_Components.Utran != null) and vc_Components.Utran.running) { // UTRAN is still running
        // do nothing
      } else if ((vc_Components.Geran != null) and vc_Components.Geran.running) { // GERAN is still running
        // do nothing
      } else {                                  // neither EUTRA nor UTRAN nor GERAN is running anymore
        fl_MTC_Stop(pass);                      // stop the NAS emulator and the mtc; 'pass' will overrule 'none' only
      }
    }
  }
  //============================================================================
  /*
   * @desc      Main loop of the MTC
   * @param     p_GuardTimer timer
   * @status    APPROVED
   */
  function f_MTC_MainLoop(timer p_GuardTimer) runs on MTC
  {
    var UT_Ctrl_Type v_UT_Ctrl := f_UT_Ctrl_Init();

    f_UT_InitialPowerOffUE();

    while (true) {      /* mtc will be stopped by a_PTC_Control or due to timeout of the guard timer;
                           => neither a_PTC_Control nor a_UpperTester needs to use 'repeat' */
      alt {
        [] a_PTC_Control();             // handle 'done' and 'killed' of PTCs: MTC will be stopped, when all PTCs are terminated or a fatal error occurs
        [] a_UpperTester(v_UT_Ctrl);    // handle upper tester
        [] p_GuardTimer.timeout {fl_MTC_Stop(fail);}    /* acc. to the assumption that preamble and postamble are short compared to the testbody
                                                           a FAIL verdict is assigned (rather than an INCONC) */
      }
    }
  }
}

