DUTs

E_GasType

TYPE E_GasType :
(

    none := 0,
    Neon,
    Argon,
    Krypton,
    Xenon

);
END_TYPE

E_HomeState

TYPE E_HomeState :
(
    H_READY,
    H_INIT,
    H_RESET_LL,
    H_RESET_HL,
    H_ENABLE,
    H_MOVING,
    H_MOVING2,
    H_CHECK,
    H_RESET,
    H_SET_POS,
    H_ERROR,
    H_WRITE_LL,
    H_WRITE_HL,
    H_DONE

) UDINT;
END_TYPE

E_MoveState

TYPE E_MoveState :
(
    ABORT,
    INIT,
    ENABLE,
    FORWARD,
    BACKWARDS,
    READY,
    MOVING,
    NEWTARGETPOSITION,
    NEWTARGETPOSITION2,
    ERROR,
    RESET,
    HALT,
    HOME
) UDINT;
END_TYPE

ST_HV

TYPE ST_HV :
STRUCT
    {attribute 'pytmc' := '
    pv: HV_SW;
    io: io;
    '}
    HV_sw: BOOL:=True; // EPICS control for switching the HV on or off.
    {attribute 'pytmc' := '
    pv: HV_DO;
    io: i;
    '}
    q_HV_DO: BOOL; // Readout of the HV's ouput value
    {attribute 'pytmc' := '
    pv: ILK_OK;
    io: i;
    '}
    xIlkOK  :       BOOL := FALSE; // Interlock Bit
    {attribute 'pytmc' := '
    pv: PRO_SP;
    io: io;
    '}
    rPRO_SP: REAL := 0.0001; // Pressure below which the HV signal may turn o
END_STRUCT
END_TYPE

ST_VGP

TYPE ST_VGP :
STRUCT

    {attribute 'pytmc' := '
    pv: POS_RBV;
    io: i;
    '}
    // Inputs
    i_iPosition     :       REAL; //Encoder position readback (if it exists)
    {attribute 'pytmc' := '
    pv: ENC_RBV;
    io: i;
    '}
    // Inputs
    rEnoder_Position        :       REAL; //Encoder position readback (if it exists)
    {attribute 'pytmc' := '
    pv: ERROR;
    field: ZNAM FALSE;
     field: ONAM TRUE;
    io: i;
    '}
    // Inputs
    pv_xError       :       BOOL;

    {attribute 'pytmc' := '
    pv: IS_HOMED;
    field: ZNAM FALSE;
     field: ONAM TRUE;
    io: i;
    '}
    // Inputs
    pv_xHomed       :       BOOL :=false;


    //Softvariables
    {attribute 'pytmc' := '
    pv: ILK_OK;
    field: ZNAM FALSE;
     field: ONAM TRUE;
    io: i;
    '}
    xIlkOK  :       BOOL := FALSE; // Interlock Bit
    //Manually Pressing valve "Open/Close" on EDM
    {attribute 'pytmc' := '
    pv: OPN_SW;
    field: ZNAM FALSE;
     field: ONAM TRUE;
    io: io;
    '}
    pv_xOPN_SW      : BOOL;

    {attribute 'pytmc' := '
    pv: GO_SW;
    field: ZNAM FALSE;
    field: ONAM TRUE;
    io: io;
    '}
    pv_xGo_SW       : BOOL;

    {attribute 'pytmc' := '
    pv: HOME_SW;
    field: ZNAM FALSE;
     field: ONAM TRUE;
    io: io;
    '}
    pv_xHome_SW     : BOOL;

    {attribute 'pytmc' := '
    pv: Reset_SW;
    field: ZNAM FALSE;
     field: ONAM TRUE;
    io: io;
    '}
    pv_xReset_SW    : BOOL;

    {attribute 'pytmc' := '
    pv: Busy;
    field: ZNAM FALSE;
     field: ONAM TRUE;
    io: io;
    '}
    xBusy   : BOOL;

    {attribute 'pytmc' := '
    pv: ABORT;
     field: ZNAM FALSE;
     field: ONAM TRUE;
    io: io;
    '}
    pv_xABORT_SW    : BOOL;


    {attribute 'pytmc' := '
    pv: POS_CTRL;
    io: io;
    '}
    rReqPosition    :       REAL;
    // Outputs
    {attribute 'pytmc' := '
    pv: POS_DES;
    io: io;
    '}
    q_iRawPosition  :       INT; //Position control
    {attribute 'pytmc' := '
    pv: STATE;
    type: mbbi ;
    field: ZRST CLOSE ;
    field: ONST OPEN;
    field: TWST PRESS CNTRL;
    field: THST MANUAL CNTRL ;
    io: io;
    '}
    eValveControl   :       E_VCN := CloseValve; // Valve control state
    /// state machine state
    {attribute 'pytmc' := '
    pv: Axis_STATE;
    io: io;
    '}
    eState: E_MoveState; //Axis Move state
    ftIlk   :       F_TRIG;
    {attribute 'pytmc' := '
    pv: ERR_ID;
    io: i;
    '}
    nErrorID: UDINT;

    {attribute 'pytmc' := '
    pv: ERR_MSG;
    io: i;
    '}
    sErrorMessage : STRING;

END_STRUCT
END_TYPE

GVLs

GVL_Devices

VAR_GLOBAL

{attribute 'pytmc' :=' pv: EM2K0:XGMD:OVERRIDE_INJ '}
    xOverrideMode : BOOL:= false;

    {attribute 'pytmc' :=' pv: EM2K0:XGMD:GHC:50 '}
    GHC_50 : FB_ITR90;

    {attribute 'pytmc' :=' pv: EM2K0:XGMD:VCN:50 '}
    VCN_50 : FB_VCN;
    {attribute 'pytmc' :=' pv: EM2K0:XGMD:VGP:50 '}
    VGP_50 : FB_VGP;

    {attribute 'pytmc' :=' pv: EM2K0:XGMD:GCM:80 '}
    GCM_80 : FB_GCM;

    {attribute 'pytmc' :=' pv: EM2K0:XGMD:VVC:80 '}
    VVC_80:FB_VVC;
    {attribute 'pytmc' :=' pv: EM2K0:XGMD:VVC:81 '}
    VVC_81:FB_VVC;
    {attribute 'pytmc' :=' pv: EM2K0:XGMD:VVC:82 '}
    VVC_82:FB_VVC;
    {attribute 'pytmc' :=' pv: EM2K0:XGMD:VVC:83 '}
    VVC_83 : FB_VVC;
    {attribute 'pytmc' :=' pv: EM2K0:XGMD:VVC:84 '}
    VVC_84 : FB_VVC;
    {attribute 'pytmc' :=' pv: EM2K0:XGMD:VVC:85 '}
    VVC_85 : FB_VVC;
    {attribute 'pytmc' :=' pv: EM2K0:XGMD:VVC:86 '}
    VVC_86 : FB_VVC;


    (* Pressure Control*)
    {attribute 'pytmc' := ' pv: EM2K0:XGMD:GCP:50 '}
    GCP: ST_VG;
    {attribute 'pytmc' :=' pv: EM2K0:XGMD:CNTRL:SP;
    field: HOPR 1000;
    field: LOPR 0;
    field: PREC 2;
    field: EGU "TORR";
    '}
    fSetpointValue :REAL;
    {attribute 'pytmc' :=' pv:  EM2K0:XGMD:CNTRL:GO;
     field: ZNAM STOP;
     field: ONAM START;
     io: io;        '}
    bGo: BOOL;
    {attribute 'pytmc' :=' pv: EM2K0:XGMD:CNTRL:RESET;
     field: ZNAM FALSE;
     field: ONAM TRUE;
     io: io;
     '}
    bReset : BOOL;
    {attribute 'pytmc' :=' pv:  EM2K0:XGMD:CNTRL:ERROR;
    field: ZNAM FALSE;
     field: ONAM TRUE;
     io: io;
     '}
    bError : BOOL;
    {attribute 'pytmc' :=' pv:  EM2K0:XGMDCNTRL:Kp1 '}
    fKp1 : REAL:= 0.5;
    {attribute 'pytmc' :=' pv:  EM2K0:XGMD:CNTRL:Tn1 '}
    fTn1 : REAL:= 0.5;
    {attribute 'pytmc' :=' pv:  EM2K0:XGMD:CNTRL:Kp2 '}
    fKp2 : REAL:= 0.01;
    {attribute 'pytmc' :=' pv:  EM2K0:XGMD:CNTRL:Tn2 '}
    fTn2 : REAL:= 0.5;

    (*Additional VCN Interlock*)
    {attribute 'pytmc' :=' pv:  EM2K0:XGMD:VCN_ILK;
    field: ZNAM FALSE;
     field: ONAM TRUE;
     io: io;
     '}
    bAdditionalVCNIlk : BOOL:=TRUE;

    (*HV*)
    {attribute 'pytmc' :=' pv: EM2K0:XGMD:PSV:1 '}
    hv1 : FB_HighVoltage;
    //{attribute 'pytmc' :=' pv: EM2K0:XGMD:PSV '}
    //hv2 : FB_HighVoltage;

    (*RTD*)

    {attribute 'pytmc' :=' pv: EM2K0:XGMD:RTD:1 '}
    {attribute 'TcLinkTo' := '.iRaw := TIIB[EL3202_03_08]^RTD Inputs Channel 1^Value;
                              .bError := TIIB[EL3202_03_08]^RTD Inputs Channel 1^Status^Error;
                              .bUnderrange := TIIB[EL3202_03_08]^RTD Inputs Channel 1^Status^Underrange;
                              .bOverrange := TIIB[EL3202_03_08]^RTD Inputs Channel 1^Status^Overrange'}
    RTD_1 : FB_TempSensor;

    {attribute 'pytmc' :=' pv: EM2K0:XGMD:RTD:2 '}
    {attribute 'TcLinkTo' := '.iRaw := TIIB[EL3202_03_08]^RTD Inputs Channel 2^Value;
                              .bError := TIIB[EL3202_03_08]^RTD Inputs Channel 2^Status^Error;
                              .bUnderrange := TIIB[EL3202_03_08]^RTD Inputs Channel 2^Status^Underrange;
                              .bOverrange := TIIB[EL3202_03_08]^RTD Inputs Channel 2^Status^Overrange'}
    RTD_2 : FB_TempSensor;

END_VAR

GVL_GMD

VAR_GLOBAL

// FB_MKS317

{attribute 'pytmc' := ' pv: EM2K0:XGMD:GPI:10 '}
fb_EM2K0_XGMD_GPI_10 : FB_MKS317;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:GPI:50 '}
fb_EM2K0_XGMD_GPI_50 : FB_MKS317;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:GPI:90 '}
fb_EM2K0_XGMD_GPI_90 : FB_MKS317;

// FB_PTM_TwisTorr

{attribute 'pytmc' := ' pv: EM2K0:XGMD:PTM:10 '}
fb_EM2K0_XGMD_PTM_10 : FB_PTM_TwisTorr;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:PTM:20 '}
fb_EM2K0_XGMD_PTM_20 : FB_PTM_TwisTorr;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:PTM:30 '}
fb_EM2K0_XGMD_PTM_30 : FB_PTM_TwisTorr;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:PTM:40 '}
fb_EM2K0_XGMD_PTM_40 : FB_PTM_TwisTorr;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:PTM:50 '}
fb_EM2K0_XGMD_PTM_50 : FB_PTM_TwisTorr;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:PTM:60 '}
fb_EM2K0_XGMD_PTM_60 : FB_PTM_TwisTorr;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:PTM:70 '}
fb_EM2K0_XGMD_PTM_70 : FB_PTM_TwisTorr;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:PTM:80 '}
fb_EM2K0_XGMD_PTM_80 : FB_PTM_TwisTorr;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:PTM:90 '}
fb_EM2K0_XGMD_PTM_90 : FB_PTM_TwisTorr;
// FB_VRC

{attribute 'pytmc' := ' pv: EM2K0:XGMD:VRC:10 '}
fb_EM2K0_XGMD_VRC_10 : FB_VRC;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:VRC:20 '}
fb_EM2K0_XGMD_VRC_20 : FB_VRC;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:VRC:30 '}
fb_EM2K0_XGMD_VRC_30 : FB_VRC;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:VRC:40 '}
fb_EM2K0_XGMD_VRC_40 : FB_VRC;
//{attribute 'pytmc' := ' pv: EM2K0:XGMD:VRC:50 '}
//fb_EM2K0_XGMD_VRC_50 : FB_VRC;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:VRC:60 '}
fb_EM2K0_XGMD_VRC_60 : FB_VRC;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:VRC:70 '}
fb_EM2K0_XGMD_VRC_70 : FB_VRC;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:VRC:80 '}
fb_EM2K0_XGMD_VRC_80 : FB_VRC;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:VRC:90 '}
fb_EM2K0_XGMD_VRC_90 : FB_VRC;

// FB_MKS422

{attribute 'pytmc' := ' pv: EM2K0:XGMD:GCC:10 '}
fb_EM2K0_XGMD_GCC_10 : FB_MKS422;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:GCC:20 '}
fb_EM2K0_XGMD_GCC_20 : FB_MKS422;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:GCC:30 '}
fb_EM2K0_XGMD_GCC_30 : FB_MKS422;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:GCC:40 '}
fb_EM2K0_XGMD_GCC_40 : FB_MKS422;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:GCC:50 '}
fb_EM2K0_XGMD_GCC_50 : FB_MKS422;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:GCC:60 '}
fb_EM2K0_XGMD_GCC_60 : FB_MKS422;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:GCC:70 '}
fb_EM2K0_XGMD_GCC_70 : FB_MKS422;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:GCC:80 '}
fb_EM2K0_XGMD_GCC_80 : FB_MKS422;
{attribute 'pytmc' := ' pv: EM2K0:XGMD:GCC:90 '}
fb_EM2K0_XGMD_GCC_90 : FB_MKS422;

// FB_EbaraEVA

{attribute 'pytmc' := ' pv: EM2K0:XGMD:PRT:50 '}
fb_EM2K0_XGMD_PRT_50 : FB_EbaraEVA;

// FB_VVC
{attribute 'pytmc' := ' pv: EM2K0:XGMD:VVC:50 '}
fb_EM2K0_XGMD_VVC_50 : FB_VVC;

//Roughing DC Valves
{attribute 'pytmc' := ' pv: EM2K0:XGMD:VRO:50 '}
{attribute 'TcLinkTo' :=    '.q_xOPN_DO     :=      TIIB[EL2212_02_19]^DOX Control Channel 2^Control^Output'}
fb_EM1K0_GMD_VRO_50 : FB_VVC;

END_VAR

GVL_VAC_INTF

VAR_GLOBAL
    ads_watch_dog : FB_ADS_WATCHDOG;
END_VAR

GVL_VARIABLES

VAR_GLOBAL

    {attribute 'pytmc' :=' pv: EM2K0:XGMD:OVERRIDE_VAC '}
    xSystemOverrideMode : BOOL; (* Global system override for the prototype section*)

    {attribute 'pytmc' :=' pv: EM2K0:XGMD:AUTO_VVC_50 '}
    bAutoVVC50 : BOOL := TRUE;

    // Purge COMMANDS FROM epics
    //pragma
    {attribute 'pytmc' :=' pv: EM2K0:XGMD:Purge_SW'}
    bStartPurge_sw : BOOL :=false;
    {attribute 'pytmc' :=' pv: EM2K0:XGMD:Purge_Active'}
    bPurgeActive : BOOL:=false;
    {attribute 'pytmc' :=' pv: EM2K0:XGMD:PurgeDone'}
    bPurgeDone : BOOL :=false;
    {attribute 'pytmc' := '
    pv: EM2K0:XGMD:GAS_TYPE ;
    type: mbbi ;
    field: ZRST none ;
    field: ONST Neon;
    field: TWST Argon ;
    field: THST Krypton ;
    field: FRST Xenon ;
    io: i
    '}
    SelectedGas: E_GasType;

END_VAR

POUs

F_HV_ILK

FUNCTION F_HV_ILK : BOOL
VAR_INPUT
    IG      :       ST_VG; // Gauge used for interlocking the high voltage supply
    HV      :       ST_HV; // Structure representing HV control
END_VAR
VAR
END_VAR
F_HV_ILK := ((IG.xPRESS_OK = TRUE)
                    AND (IG.rPRESS < HV.rPRO_SP));

END_FUNCTION

F_TURBO_PROT_SLND_ILK

(*
    Interlock function for solenoid valve located behind the central turbo pump.
*)
FUNCTION F_TURBO_PROT_SLND_ILK : BOOL
VAR_INPUT
    i_Turbo : ST_PTM; // Turbo Pump
    i_stISG : ST_VG; //Gauge measuring inlet Pressure e.g Pirani
    i_stBSG : ST_VG; //Gauge measuring backing Pressure e.g Pirani
    ScrollPump : ST_RoughPump; // Roughing pump
END_VAR
VAR
END_VAR
F_TURBO_PROT_SLND_ILK := (i_stISG.xPRESS_OK AND i_stISG.rPRESS < i_Turbo.rInletPressureSP)
                                                AND (i_stBSG.xPRESS_OK AND i_stBSG.rPRESS < i_Turbo.rBackingPressureSP)
                            AND (ScrollPump.eState = pumpRUNNING)
                                                    AND (i_Turbo.eState = pumpRUNNING);

END_FUNCTION

F_TurboGateValve_Protection_ILK_local

(* This Function Block evaluates the ILK condition of the Turbo Gate valve *)
(* The logic Protects the Turbo pump from inlet pressure above the SP*)
(* And Protects the Turbo pump from backing pressure above the SP*)
(* And Protects the Turbo pump in the case of backing pump not running*)

(* This is to be used whle the vacuum library has not yet updated to watch for the pumpRUNNING state. Switch to the vacuum library's version at earliest convenience. *)

FUNCTION F_TurboGateValve_Protection_ILK_local : BOOL(* function return TRUE when ILK is OK*)
VAR_INPUT
    i_Turbo : ST_PTM; // Turbo Pump
    i_stISG : ST_VG; //Gauge measuring inlet Pressure e.g Pirani
    i_stBSG : ST_VG; //Gauge measuring backing Pressure e.g Pirani
    ScrollPump      :       ST_RoughPump; // Roughing pump
END_VAR
VAR
END_VAR
(* This Function Block evaluates the ILK condition of the Turbo Gate valve *)
(* The logic Protects the Turbo pump from inlet pressure above the SP*)
F_TurboGateValve_Protection_ILK_local := (i_Turbo.eState = pumpRUNNING)
                                            AND (i_stISG.xPRESS_OK AND i_stISG.rPRESS < i_Turbo.rInletPressureSP)
                                            AND (i_stBSG.xPRESS_OK AND i_stBSG.rPRESS < i_Turbo.rBackingPressureSP)
                                            AND (ScrollPump.eState = pumpRUNNING);

END_FUNCTION

FB_HighVoltage

FUNCTION_BLOCK FB_HighVoltage
VAR_INPUT
    i_xExtIlkOK     :       BOOL; //External Interlock, SET to TRUE if not used
END_VAR
VAR_OUTPUT
    {attribute 'pytmc' := '
    pv:
    '}
    hv:ST_HV;
END_VAR
VAR
    (*outputs*)
    q_HV_DO AT %Q*: BOOL;
END_VAR
hv.xIlkOK := i_xExtIlkOK;

q_HV_DO := hv.HV_sw AND hv.xIlkOK;

(*soft io mapping*)
hv.q_HV_DO := q_HV_DO;

END_FUNCTION_BLOCK

FB_VGP

(* This function implements the Basic functions for the Vat Motorized valve*)
{attribute 'no_check'}
FUNCTION_BLOCK FB_VGP
VAR_INPUT
    i_xExtIlkOK     :       BOOL; //External Interlock, SET to TRUE if not used
    i_xOpenIlkOK: BOOL; //Interlock Bit that allows the valve to open
    i_xCloseIlkOK: BOOL; //Interlock Bit that allows the valve to Close

    i_ReqPos        :       REAL; //Requested position

    arrTable        : ARRAY[1..14,1..2] OF FLOAT;
END_VAR
VAR_OUTPUT
    {attribute 'pytmc' := '
    pv:
    '}
    q_stVGP :       ST_VGP; // valve structure
END_VAR
VAR_IN_OUT

END_VAR

VAR CONSTANT
    rUpperLimit     :       REAL:=100;      //Percentage Upper limit on valve open
    rClosePosition : REAL:=0; // Encoder Min. Fully Closed
    rMaxDiffPressure: REAL:= 22.5; //Torr
END_VAR

VAR
    rOpenPosition: REAL:=1660; // Encoder MAX. Fully Open
    rTargetPosition : REAL;
    rTargetVelocity: REAL:=30;
    rHomingVelocity: REAL:=10;
    rHomingDistance: REAL:=-20;//every 150 is 10% , 1%  is 14.975
    rOldTargetPosition: REAL;
    rHyst:REAL :=10;
    //
    /// axis reference data structure
    Axis: AXIS_REF;
    //
    InfoData_State AT %I*: UINT ;

    // Axis MC functions

    fbPowerAxis: MC_Power;
    /// debug function block output data
    PowerAxisOut: ST_McOutputs;
    fbMoveAxisABS: MC_MoveAbsolute;
    /// debug function block output data
    MoveAbsoluteOut: ST_McOutputs;
    fbMoveAxisABS2: MC_MoveAbsolute;
    /// debug function block output data
    MoveAbsoluteOut2: ST_McOutputs;

    fbReset: MC_Reset;
    /// debug function block output data
    ResetOut: ST_McOutputs;
    MoveAxisREL: MC_MoveAbsolute;
    MoveRelativeOut: ST_McOutputs;



    rOverride: LREAL := 100;
    fbHalt: MC_Halt;


    // Homing Functions
    bGo:BOOL := FALSE; //to execute motion
    bHome:BOOL :=FALSE; // should be set to true
    bEnable:Bool; //to be removed
    fbMoveRel: MC_MoveRelative;
    fbSetPosition: MC_SetPosition;
    fbWriteParameter: MC_WriteBoolParameter;
    HomeState: E_HomeState;

    // For Monitoring while Axis moving
    rPrevEncoderPosition : REAL;
    // interpolation
    bInit : BOOL := TRUE;
    eMode           : E_CTRL_MODE;
    iCounter:INT;
    //CONTROL
    stCTRL_LIN_INTERPOLATION_PARAMS         : ST_CTRL_LIN_INTERPOLATION_PARAMS;
    fbCTRL_LIN_INTERPOLATION                                        : FB_CTRL_LIN_INTERPOLATION;
    arrTable_ENC : ARRAY[1..14,1..2] OF FLOAT;
    //Readdback
    stCTRL_LIN_INTERPOLATION_PARAMS_ENC             : ST_CTRL_LIN_INTERPOLATION_PARAMS;
    fbCTRL_LIN_INTERPOLATION_ENC                                    : FB_CTRL_LIN_INTERPOLATION;

    // Logger
     // For logging
    fbLogger : FB_LogMessage := (eSubsystem:=E_SubSystem.VACUUM);
    ePrevState : E_VCN;
    tErrorPresent : R_TRIG;
    tAction : R_TRIG; // Primary action of this device (OPN_DO, PUMP_RUN, etc.)

    rt_close :R_TRIG;
    rt_Open :R_TRIG;
END_VAR
/// Interpolation  function initialization
ACT_INIT();

// Interlocking
q_stVGP.xIlkOK := i_xExtIlkOK;
(*Checking which Control mode is selected*)
IF i_xExtIlkOK AND NOT (q_stVGP.pv_xError) THEN
    IF q_stVGP.eValveControl = OpenValve THEN
            q_stVGP.rReqPosition := rUpperLimit;
    ELSIF q_stVGP.eValveControl = CloseValve THEN
            q_stVGP.rReqPosition := 0;
    ELSIF q_stVGP.eValveControl = ManualControl THEN
            q_stVGP.rReqPosition := LIMIT(0, q_stVGP.rReqPosition, rUpperLimit);
    ELSIF q_stVGP.eValveControl = PressureControl THEN
             q_stVGP.rReqPosition := LIMIT(0, i_ReqPos, rUpperLimit);
    END_IF
ELSIF NOT i_xExtIlkOK THEN
    q_stVGP.rReqPosition := 0;
    q_stVGP.eValveControl := CloseValve;//CloseValve;
END_IF

rt_close (CLK:= q_stVGP.eValveControl = CloseValve);
rt_Open (CLK:= q_stVGP.eValveControl = OpenValve);

IF (rt_close.Q) OR (rt_Open.Q) THEN
    q_stVGP.pv_xGo_SW:=TRUE;
END_IF
//Check the Drive State

IF (*(InfoData_State<>16#8) OR*) (q_stVGP.eState = ERROR) THEN
    q_stVGP.pv_xError:=TRUE;
ELSE
    q_stVGP.pv_xError:=FALSE;
    // Call function to execute move
    // call motion function blocks???
END_IF


IF (q_stVGP.pv_xABORT_SW ) THEN
    q_stVGP.pv_xABORT_SW := FALSE;
    q_stVGP.eState:= ABORT;
    HomeState:= H_READY;
END_IF


ACT_LIN_INTERPOLATION();
ACT_AXIS();
ACT_HOME();
ACT_MONITOR();

END_FUNCTION_BLOCK
ACTION ACT_AXIS:
//update the axis status
AXIS();
q_stVGP.rEnoder_Position := LREAL_TO_REAL(Axis.NcToPlc.ActPos); // encoder position

(*
IF NOT (i_xExtIlkOK) THEN
    q_stVGP.eState := NEWTARGETPOSITION;
END_IF*)
//Homing STATE is missing

// state machine for axis motion
    (* move axis using a state machine *)
    CASE q_stVGP.eState OF

            INIT :  (* initialisation *)
                    (* initialize all function blocks *)
                    fbMoveAxisABS.Execute := FALSE;
                    fbMoveAxisABS2.Execute := FALSE;
                    fbReset.Execute := FALSE;
                    fbHALT.Execute :=FALSE;//
                    q_stVGP.eState := ENABLE; // Check homing first
                    HomeState:= H_READY;

            ENABLE :
                    fbPowerAxis.Enable :=  TRUE;
                    fbPowerAxis.Enable_Positive := TRUE;
                    fbPowerAxis.Enable_Negative := TRUE;
                    IF fbPowerAxis.Status THEN
                            q_stVGP.eState := READY;
                    ELSIF fbPowerAxis.Error THEN
                            q_stVGP.eState := ERROR;
                    END_IF

            READY: // waiting for move command
                    IF NOT fbPowerAxis.Status THEN
                            q_stVGP.eState := ENABLE;
                    ELSIF fbPowerAxis.Error THEN
                            q_stVGP.eState := ERROR;
                    END_IF
                    IF (HomeState = H_READY) AND (q_stVGP.pv_xHome_SW) THEN
                                    HomeState:= H_INIT;
                                    q_stVGP.pv_xHome_SW:=false;
                                    q_stVGP.eState := HOME;
                                    ELSE
                                    q_stVGP.eState := READY;
                            END_IF
                    IF (q_stVGP.pv_xGo_SW) AND q_stVGP.pv_xHomed(* AND( rOldTargetPosition <> rTargetPosition) *) THEN
                            q_stVGP.pv_xGo_SW := false;
                            q_stVGP.eState := NEWTARGETPOSITION;
                            rOldTargetPosition := rTargetPosition;
                    END_IF


            HOME:
                            if (HomeState = H_DONE) THEN
                                     q_stVGP.eState := INIT;
                                     q_stVGP.pv_xHomed := TRUE;
                                     HomeState := H_READY;
                            END_IF

                            if (HomeState = H_ERROR) THEN
                                    q_stVGP.eState := ERROR;
                                      q_stVGP.pv_xHomed := FALSE;
                            END_IF

            NEWTARGETPOSITION:
                    fbMoveAxisABS.Position := rTargetPosition;
                    fbMoveAxisABS.Velocity := rTargetVelocity;
                    //fbMoveAxisABS.BufferMode := MC_BlendingNext;
                    fbMoveAxisABS.Execute := TRUE;
                    IF fbMoveAxisABS.Active  THEN
                            (* axis is executing job but is not yet finished *)
                            fbMoveAxisABS.Execute := FALSE;
                            (* leave this state and buffer a second command *)
                            q_stVGP.eState := MOVING;
                    ElSIF fbMoveAxisABS.Done THEN
                            fbMoveAxisABS.Execute := FALSE;
                            q_stVGP.eState := READY;
                    ELSIF fbMoveAxisABS.CommandAborted OR fbMoveAxisABS.Error THEN
                            q_stVGP.eState := ERROR;
                    END_IF


            MOVING://
                    IF fbMoveAxisABS.CommandAborted OR fbMoveAxisABS.Error THEN
                            q_stVGP.eState := ERROR;
                    END_IF
                    IF NOT ( Axis.Status.Moving) OR (fbMoveAxisABS.Done) THEN //(fbMoveAxisABS.Done) AND (fbMoveAxisABS2.Done) THEN
                            q_stVGP.eState := READY;
                    END_IF


            HALT:
                    fbHALT.Execute :=TRUE;
                    IF Axis.Status.Error THEN
                            q_stVGP.eState := RESET;        (* axis error requires reset *)
                    ELSE
                            q_stVGP.eState := INIT;         (* function block errors don't need a reset *)
                    END_IF

            ERROR :
                    IF HomeState = H_READY THEN
                            q_stVGP.eState := RESET;
                    ELSE
                            q_stVGP.eState := HOME;
                    END_IF

            RESET :
                    //fbReset.Execute := TRUE;
                    IF fbReset.Done THEN q_stVGP.eState :=INIT;
                    //      HomeState := H_READY;
                    ELSIF fbReset.Error THEN
                            q_stVGP.eState := ERROR; (* keep trying to reset*)
                    END_IF

            ABORT:
                    fbMoveAxisABS.Execute := FALSE;
                    fbMoveAxisABS2.Execute := FALSE;
                    fbReset.Execute := FALSE;
                    (* save target position*)
                    rOldTargetPosition :=   q_stVGP.i_iPosition;
                    fbHALT.Execute :=FALSE;
                    fbPowerAxis.Enable := FALSE;
                    fbPowerAxis.Enable_Positive := FALSE;
                    fbPowerAxis.Enable_Negative := FALSE;
                    q_stVGP.eState := ENABLE; // Check homing first

    END_CASE






/// Motion Function Blocks
(* AXIS POWER*)
fbPowerAxis(
    Axis:= Axis,
    Enable:= ,
    Enable_Positive:= i_xOpenIlkOK,
    Enable_Negative:= ,
    Override:= rOverride,
    BufferMode:= ,
    Options:= ,
    Status=>  ,
    Busy=> PowerAxisOut.Busy ,
    Active=> PowerAxisOut.Active ,
    Error=> PowerAxisOut.Error,
    ErrorID=> PowerAxisOut.ErrorID);
(* AXIS MOVE ABSOLUTE*)
fbMoveAxisABS(
    Axis:= Axis ,
    Execute:= ,
    Position:= ,
    Velocity:= ,
    Acceleration:= ,
    Deceleration:= ,
    Jerk:= ,
    BufferMode:= MC_BlendingNext ,
    Options:= ,
    Done=>MoveAbsoluteOut.Done,
    Busy=> MoveAbsoluteOut.Busy,
    Active=> MoveAbsoluteOut.Active,
    CommandAborted=> MoveAbsoluteOut.CommandAborted ,
    Error=> MoveAbsoluteOut.Error,
    ErrorID=> MoveAbsoluteOut.ErrorID);
    (* AXIS MOVE ABSOLUTE*)
fbMoveAxisABS2(
    Axis:= Axis ,
    Execute:= ,
    Position:= ,
    Velocity:= ,
    Acceleration:= ,
    Deceleration:= ,
    Jerk:= ,
    BufferMode:= MC_BlendingNext ,
    Options:= ,
    Done=>MoveAbsoluteOut2.Done,
    Busy=> MoveAbsoluteOut2.Busy,
    Active=> MoveAbsoluteOut2.Active,
    CommandAborted=> MoveAbsoluteOut2.CommandAborted ,
    Error=> MoveAbsoluteOut2.Error,
    ErrorID=> MoveAbsoluteOut2.ErrorID);
(*AXIS RESET*)
fbReset(
    Axis:= Axis,
    Execute:= This^.q_stVGP.pv_xReset_SW ,
    Done=>ResetOut.Done ,
    Busy=>ResetOut.Busy ,
    Error=> ResetOut.Error,
    ErrorID=> ResetOut.ErrorID);

(*HALT*)
fbHalt(
    Axis:= Axis,
    Execute:= ,
    Deceleration:= ,
    Jerk:= ,
    BufferMode:= MC_BlendingNext ,
    Options:= ,
    Done=> ,
    Busy=> ,
    Active=> ,
    CommandAborted=> ,
    Error=> ,
    ErrorID=> );


/// ERROR
IF Axis.Status.Error  THEN
    q_stVGP.eState := ERROR;
END_IF;

// Error Handling
if( fbPowerAxis.Error and fbPowerAxis.Active ) then
    This^.q_stVGP.pv_xError:= fbPowerAxis.Error;
    This^.q_stVGP.nErrorID:= fbPowerAxis.ErrorID;
END_IF
if( fbMoveAxisABS.Error and fbMoveAxisABS.Active ) then
    This^.q_stVGP.pv_xError:= fbMoveAxisABS.Error;
    This^.q_stVGP.nErrorID:= fbMoveAxisABS.ErrorID;
END_IF

IF This^.q_stVGP.pv_xReset_SW THEN This^.q_stVGP.pv_xReset_SW:=FALSE; END_IF
(*Convert nErrorID to string*)
This^.q_stVGP.sErrorMessage:=WORD_TO_HEXSTR(in:=TO_WORD(This^.q_stVGP.nErrorID) , iPrecision:= 4, bLoCase:=0 );

This^.q_stVGP.xBusy := (NOT(q_stVGP.eState = READY) AND (HomeState = H_READY));
END_ACTION
ACTION ACT_HOME:
CASE HomeState OF
    H_READY:
            fbSetPosition.Execute := FALSE;
            fbWriteParameter.Execute := FALSE;
            fbMoveRel.Execute := FALSE;

    H_INIT:
    HomeState:=H_RESET_LL;


    H_RESET_LL:
            // disable soft limits in order to be able to move the drive
            fbWriteParameter.ParameterNumber := MC_AxisParameter.EnableLimitNeg;//EnableLimitPos;// .EnableLimitNeg;
            fbWriteParameter.Value := FALSE;
            fbWriteParameter.Execute := TRUE;
            if (fbWriteParameter.Done) THEN
                    fbWriteParameter.Execute := FALSE;
                    HomeState:= H_RESET_HL;
            END_IF

    H_RESET_HL:
            // disable soft limits in order to be able to move the drive
            fbWriteParameter.ParameterNumber := MC_AxisParameter.EnableLimitPos;
            fbWriteParameter.Value := FALSE;
            fbWriteParameter.Execute := TRUE;
            if (fbWriteParameter.Done) THEN
                    fbWriteParameter.Execute := FALSE;
                    HomeState:= H_ENABLE;
            END_IF

    H_ENABLE:
            // Make Sure drive is enabled
            fbPowerAxis.Enable :=  TRUE;
            fbPowerAxis.Enable_Positive := TRUE;
            fbPowerAxis.Enable_Negative := TRUE;
            IF fbPowerAxis.Status THEN
                    HomeState:= H_MOVING;
            ELSIF fbPowerAxis.Error THEN
                    HomeState := H_ERROR;
            END_IF

    H_MOVING:
            fbMoveRel.Execute := TRUE;
            IF fbMoveRel.Active  THEN
                    (* axis is executing job but is not yet finished *)
                    fbMoveRel.Execute := FALSE;
                    (* leave this state and buffer a second command *)
                    HomeState := H_MOVING2;
            ElSIF fbMoveRel.Done THEN
                    fbMoveRel.Execute := FALSE;
                    HomeState := H_MOVING;//2?
            ELSIF fbMoveRel.CommandAborted OR fbMoveRel.Error THEN
                    fbMoveRel.Execute := FALSE;
                    HomeState := H_CHECK;
            END_IF

    H_MOVING2:
            IF fbMoveRel.CommandAborted OR fbMoveRel.Error THEN
                    HomeState := H_CHECK;
            END_IF
            IF NOT ( Axis.Status.Moving) OR (fbMoveRel.Done) THEN //(fbMoveAxisABS.Done) AND (fbMoveAxisABS2.Done) THEN
                    HomeState := H_MOVING;
                    fbMoveRel.Execute := FALSE;
            END_IF

    H_CHECK:
            //Check position lag monitoring error
            if (Axis.Status.ErrorID = 16#00004550)THEN
                    This^.q_stVGP.pv_xReset_SW := TRUE;
                    HomeState := H_RESET;
            ELSE
                    HomeState := H_ERROR;
            END_IF

    H_RESET:
            IF fbReset.Done THEN
                    This^.q_stVGP.pv_xReset_SW := FALSE;
                    HomeState := H_SET_POS;
            END_IF

    H_SET_POS:
     // Set Current Position
            fbSetPosition.Position := 0;
            fbSetPosition.Execute := TRUE;
            IF ( fbSetPosition.Done ) THEN
                    fbSetPosition.Execute := FALSE;
                    HomeState:= H_WRITE_LL;
            ELSIF (fbSetPosition.Error) THEN
                    HomeState := H_ERROR;
            END_IF


    H_WRITE_LL:
    // Re Enable the Soft limits
            fbWriteParameter.ParameterNumber := MC_AxisParameter.AxisEnMinSoftPosLimit;//AxisEnMaxSoftPosLimit;// .AxisEnMinSoftPosLimit;
            fbWriteParameter.Value := TRUE;
            fbWriteParameter.Execute := TRUE;
            if (fbWriteParameter.Done) THEN
                    fbWriteParameter.Execute := FALSE;
                    HomeState:= H_WRITE_HL;
            END_IF

    H_WRITE_HL:
    // Re Enable the Soft limits
            fbWriteParameter.ParameterNumber := MC_AxisParameter.AxisEnMaxSoftPosLimit;
            fbWriteParameter.Value := TRUE;
            fbWriteParameter.Execute := TRUE;
            if (fbWriteParameter.Done) THEN
                    fbWriteParameter.Execute := FALSE;
                    HomeState:= H_DONE;
            END_IF


    H_ERROR:
            //taken care of in the axis motion state machine
    H_DONE:
            //taken care of in the axis motion state machine

END_CASE

// Move backward to fully closed
fbMoveRel(
    Axis:= Axis ,
    Execute:= ,
    Distance:= rHomingDistance ,
    Velocity:= rHomingVelocity,
    Acceleration:= ,
    Deceleration:= ,
    Jerk:= ,
    BufferMode:= MC_BlendingNext,
    Options:= ,
    Done=> ,
    Busy=> ,
    Active=> ,
    CommandAborted=> ,
    Error=> ,
    ErrorID=> );

// Set Encoder Position
fbSetPosition(
    Axis:= Axis ,
    Execute:= ,
    Position:= 0 ,
    Mode:= FALSE, //Absolute
    Options:= ,
    Done=> ,
    Busy=> ,
    Error=> ,
    ErrorID=> );

// Write Parameters
fbWriteParameter(
    Axis:= Axis ,
    Execute:= ,
    ParameterNumber:= ,
    Value:= ,
    Done=> ,
    Busy=> ,
    Error=> ,
    ErrorID=> );

If ( fbWriteParameter.Error) OR (fbSetPosition.Error)(* OR (fbMoveRel.Error) *)THEN
    HomeState:= H_ERROR;
    q_stVGP.eState := ERROR;
END_IF
END_ACTION
ACTION ACT_INIT:
{attribute no_check}
IF bInit THEN

(*
    (* init array with the interpolation points  *)
    (*      fIn                                      |              fOut            *)
    arrTable[1,1] := 0;                     arrTable[1,2] := 0;
    arrTable[2,1] := 5;                 arrTable[2,2] := 135;
    arrTable[3,1] := 10;            arrTable[3,2] := 245;
    arrTable[4,1] :=  20;       arrTable[4,2] := 405;
    arrTable[5,1] :=  30;       arrTable[5,2] := 535;
    arrTable[6,1] := 40;            arrTable[6,2] := 689;
    arrTable[7,1] := 50;            arrTable[7,2] := 830;
    arrTable[8,1] := 60;        arrTable[8,2] := 960;
    arrTable[9,1] := 70;        arrTable[9,2] := 1095;
    arrTable[10,1] := 80;           arrTable[10,2] := 1225;
    arrTable[11,1] := 90;           arrTable[11,2] := 1415;
    arrTable[12,1] := 95;           arrTable[12,2] := 1495;
    arrTable[13,1] := 98;           arrTable[13,2] := 1559;
    arrTable[14,1] := 100;          arrTable[14,2] := 1645;
    *)

    (* init parameter struct *)
    stCTRL_LIN_INTERPOLATION_PARAMS.tCtrlCycleTime                                  := T#10ms;
    stCTRL_LIN_INTERPOLATION_PARAMS.tTaskCycleTime                                  := T#10ms;
    stCTRL_LIN_INTERPOLATION_PARAMS.nDataTable_NumberOfRows         := INT_TO_UINT(14);

    (* set the addresses *)
    stCTRL_LIN_INTERPOLATION_PARAMS.pDataTable_ADR                  := ADR(arrTable);
    stCTRL_LIN_INTERPOLATION_PARAMS.nDataTable_SIZEOF               := SIZEOF(arrTable);

    (* set the mode to ACTIVE --> normal operation *)
    eMode                                                   := eCTRL_MODE_ACTIVE;


    (* init array with the interpolation points  *)
    (*      fIn                                      |              fOut            *)
     FOR iCounter:=1 TO 14 BY 1 DO
            arrTable_ENC[iCounter,1] := arrTable[iCounter,2];
            arrTable_ENC[iCounter,2] := arrTable[iCounter,1];
     END_FOR;
    (*
    arrTable_ENC[1,1] := 0;                 arrTable_ENC[1,2] := 0;
    arrTable_ENC[2,1] := 135;                   arrTable_ENC[2,2] := 5;
    arrTable_ENC[3,1] := 245;               arrTable_ENC[3,2] := 10;
    arrTable_ENC[4,1] :=  405;          arrTable_ENC[4,2] := 20;
    arrTable_ENC[5,1] :=  535;          arrTable_ENC[5,2] := 30;
    arrTable_ENC[6,1] := 689;               arrTable_ENC[6,2] := 40;
    arrTable_ENC[7,1] := 830;               arrTable_ENC[7,2] := 50;
    arrTable_ENC[8,1] := 960;           arrTable_ENC[8,2] := 60;
    arrTable_ENC[9,1] := 1095;          arrTable_ENC[9,2] := 70;
    arrTable_ENC[10,1] := 1225;             arrTable_ENC[10,2] := 80;
    arrTable_ENC[11,1] := 1415;             arrTable_ENC[11,2] := 90;
    arrTable_ENC[12,1] := 1495;             arrTable_ENC[12,2] := 95;
    arrTable_ENC[13,1] := 1559;             arrTable_ENC[13,2] := 98;
    arrTable_ENC[14,1] := 1645;             arrTable_ENC[14,2] := 100;*)


    (* init parameter struct *)
    stCTRL_LIN_INTERPOLATION_PARAMS_ENC.tCtrlCycleTime                                      := T#10ms;
    stCTRL_LIN_INTERPOLATION_PARAMS_ENC.tTaskCycleTime                                      := T#10ms;
    stCTRL_LIN_INTERPOLATION_PARAMS_ENC.nDataTable_NumberOfRows             := INT_TO_UINT(14);

    (* set the addresses *)
    stCTRL_LIN_INTERPOLATION_PARAMS_ENC.pDataTable_ADR                      := ADR(arrTable_ENC);
    stCTRL_LIN_INTERPOLATION_PARAMS_ENC.nDataTable_SIZEOF           := SIZEOF(arrTable_ENC);

    (* reset the init flag *)
    bInit                                                   := FALSE;

END_IF;
END_ACTION
ACTION ACT_LIN_INTERPOLATION:
{attribute 'no_check'}
fbCTRL_LIN_INTERPOLATION(
    fIn:= q_stVGP.rReqPosition ,
    fManValue:= 0,
    bExtrapolate:= ,
    eMode:= eMode,
    fOut=> ,
    bInIsGreaterThanMaxElement=> ,
    bInIsLessThanMinElement=> ,
    eState=> ,
    eErrorId=> ,
    bError=> ,
    stParams:= stCTRL_LIN_INTERPOLATION_PARAMS );

// Target position Calculation
rTargetPosition := LREAL_TO_REAL(fbCTRL_LIN_INTERPOLATION.fOut);
//rTargetPosition := LIMIT(rClosePosition, rTargetPosition, rOpenPosition);

fbCTRL_LIN_INTERPOLATION_ENC(
    fIn:= Axis.NcToPlc.ActPos ,
    fManValue:= 0,
    bExtrapolate:= ,
    eMode:= eMode,
    fOut=>  ,
    bInIsGreaterThanMaxElement=> ,
    bInIsLessThanMinElement=> ,
    eState=> ,
    eErrorId=> ,
    bError=> ,
    stParams:= stCTRL_LIN_INTERPOLATION_PARAMS_ENC );
q_stVGP.i_iPosition := LREAL_TO_REAL(fbCTRL_LIN_INTERPOLATION_ENC.fOut);
END_ACTION
ACTION ACT_MONITOR:
IF (This^.q_stVGP.xBusy) THEN
    rPrevEncoderPosition:= This^.q_stVGP.rEnoder_Position;
ELSIF NOT((rPrevEncoderPosition < This^.q_stVGP.rEnoder_Position +rHyst) AND (rPrevEncoderPosition > This^.q_stVGP.rEnoder_Position -rHyst)) AND NOT( q_stVGP.eState =HOME)  AND NOT( q_stVGP.eState =ERROR) THEN
      q_stVGP.eState := ERROR;
      q_stVGP.pv_xHomed := FALSE;
      This^.q_stVGP.pv_xError := TRUE;
      This^.q_stVGP.sErrorMessage := 'Encoder Position Error';

END_IF

tErrorPresent(CLK:=q_stVGP.pv_xError);
IF tErrorPresent.Q THEN fbLogger(sMsg:=q_stVGP.sErrorMessage, eSevr:=TcEventSeverity.Error); END_IF

// Log valve motion
tAction(CLK:= q_stVGP.pv_xGo_SW);
IF tAction.Q THEN fbLogger(sMsg:='Valve commanded to move', eSevr:=TcEventSeverity.Info); END_IF


IF ePrevState <> q_stVGP.eValveControl THEN
      CASE q_stVGP.eValveControl OF

            CloseValve:
                    fbLogger(sMsg:='Valve set to Close.', eSevr:=TcEventSeverity.Info);
            OpenValve:
                    fbLogger(sMsg:='Valve set to Open.', eSevr:=TcEventSeverity.Info);
            PressureControl:
                    fbLogger(sMsg:='Valve set to pressure control mode.', eSevr:=TcEventSeverity.Info);
            ManualControl:
                    fbLogger(sMsg:='Valve set to manual control mode.', eSevr:=TcEventSeverity.Info);
      END_CASE
      ePrevState := q_stVGP.eValveControl;
  END_IF
END_ACTION

MAIN

PROGRAM MAIN
VAR
    fbLogHandler : FB_LogHandler;
    gas_selection_debug_mode : BOOL := FALSE;
    vgp_debug_mode : BOOL := FALSE;
END_VAR
PRG_DIAGNOSTIC();
PRG_GMD();
PRG_VAC_INTF();

//MG
PRG_INJ();
PRG_PressureControl();
PRG_Gas_Selection();
PRG_Purge();
IF NOT vgp_debug_mode THEN
    PRG_VGP();
END_IF




// Call the RTD Function blocks
//RTD
RTD_1();
RTD_2();

// Operate high voltage interlocking logic
PRG_HV_ILK();
fbLogHandler();

END_PROGRAM

PRG_DIAGNOSTIC

PROGRAM PRG_DIAGNOSTIC
VAR
   fbTime : FB_LocalSystemTime := ( bEnable := TRUE, dwCycle := 1 );
   logTimer : TON := ( IN := TRUE, PT := T#1000ms );

   plcName : STRING[15];

   {attribute 'pytmc' := ' pv: simHeartbeat '}
   simHeartbeat AT %I* : UINT := 0;
   {attribute 'pytmc' := ' pv: plcHeartbeat '}
   plcHeartbeat : UDINT := 0;
   {attribute 'pytmc' := ' pv: plcInfo '}
   plcInfo : STRING[40];
   {attribute 'pytmc' := ' pv: plcLocalTime '}
   plcLocalTime : STRING[25];

END_VAR
plcHeartbeat := plcHeartbeat + 1;
IF plcHeartbeat > 4294967000
   THEN plcHeartbeat := 0;
END_IF

// get timestamp as string every second
fbTime();
logTimer( IN := fbTime.bValid );
IF logTimer.Q THEN
   logTimer( IN := FALSE ); logTimer( IN := fbTime.bValid );
   plcLocalTime := SYSTEMTIME_TO_STRING(fbTime.systemTime);
END_IF

// make an info string
plcName := 'Prototype PLC: ';
plcInfo := CONCAT(plcName, plcLocalTime);

END_PROGRAM

PRG_Gas_Selection

PROGRAM PRG_Gas_Selection
VAR

    CurrentGas: E_GasType;

END_VAR
(* Gas selection includes a purge and checks interlocks*)
//fix
// Initialize the selected gas
if ( VVC_83.iq_stValve.q_xOPN_DO) then
    SelectedGas := E_GasType.Neon;
    elsif ( VVC_84.iq_stValve.q_xOPN_DO) then
            SelectedGas := E_GasType.Argon;
            elsif ( VVC_85.iq_stValve.q_xOPN_DO) then
            SelectedGas := E_GasType.Krypton;
                    elsif ( VVC_86.iq_stValve.q_xOPN_DO) then
                    SelectedGas := E_GasType.Xenon;
                            //else SelectedGas := E_GasType.none;
END_IF

(*
If( CurrentGas <> SelectedGas) AND bStartPurge_sw  (*AND NOT (CurrentGas=E_GasType.none)*) THEN
    if NOT(bStartPurge_sw) AND NOT(bPurgeActive)AND(bPurgeDone) then
            case SelectedGas of
            E_GasType.none: // all valves closed
                    VVC_83.M_Set_OPN_SW(false);
                    VVC_84.M_Set_OPN_SW(false);
                    VVC_85.M_Set_OPN_SW(false);
                    VVC_86.M_Set_OPN_SW(false);
            E_GasType.Neon:
                    VVC_83.M_Set_OPN_SW(TRUE);
                    VVC_84.M_Set_OPN_SW(false);
                    VVC_85.M_Set_OPN_SW(false);
                    VVC_86.M_Set_OPN_SW(false);
            E_GasType.Argon:
                    VVC_83.M_Set_OPN_SW(false);
                    VVC_84.M_Set_OPN_SW(TRUE);
                    VVC_85.M_Set_OPN_SW(false);
                    VVC_86.M_Set_OPN_SW(false);
            E_GasType.Krypton:
                    VVC_83.M_Set_OPN_SW(false);
                    VVC_84.M_Set_OPN_SW(false);
                    VVC_85.M_Set_OPN_SW(TRUE);
                    VVC_86.M_Set_OPN_SW(false);
            E_GasType.Xenon:
                    VVC_83.M_Set_OPN_SW(false);
                    VVC_84.M_Set_OPN_SW(false);
                    VVC_85.M_Set_OPN_SW(false);
                    VVC_86.M_Set_OPN_SW(TRUE);
            END_CASE
    END_IF

END_IF
*)


/// vcn and vgp on manual or auto??

END_PROGRAM

PRG_GMD

PROGRAM PRG_GMD
VAR
END_VAR
// FB_MKS317

fb_EM2K0_XGMD_GPI_10(PG=>);
fb_EM2K0_XGMD_GPI_50(PG=>);
fb_EM2K0_XGMD_GPI_90(PG=>);

// FB_PTM_TwisTorr

fb_EM2K0_XGMD_PTM_10(i_xExtILKOk := F_TurboExtILKLogic_2(
    Turbo:= fb_EM2K0_XGMD_PTM_10.iq_stPtm,
    BackingGauge:= fb_EM2K0_XGMD_GPI_10.PG,
    InletGauge:= fb_EM2K0_XGMD_GCC_10.IG,
    ScrollPump:= fb_EM2K0_XGMD_PRT_50.stPump)
);
fb_EM2K0_XGMD_PTM_20(i_xExtILKOk := F_TurboExtILKLogic_2(
    Turbo:= fb_EM2K0_XGMD_PTM_20.iq_stPtm,
    BackingGauge:= fb_EM2K0_XGMD_GPI_10.PG,
    InletGauge:= fb_EM2K0_XGMD_GCC_20.IG,
    ScrollPump:= fb_EM2K0_XGMD_PRT_50.stPump)
);
fb_EM2K0_XGMD_PTM_30(i_xExtILKOk := F_TurboExtILKLogic_2(
    Turbo:= fb_EM2K0_XGMD_PTM_30.iq_stPtm,
    BackingGauge:= fb_EM2K0_XGMD_GPI_10.PG,
    InletGauge:= fb_EM2K0_XGMD_GCC_30.IG,
    ScrollPump:= fb_EM2K0_XGMD_PRT_50.stPump)
);
fb_EM2K0_XGMD_PTM_40(i_xExtILKOk := F_TurboExtILKLogic_2(
    Turbo:= fb_EM2K0_XGMD_PTM_40.iq_stPtm,
    BackingGauge:= fb_EM2K0_XGMD_GPI_10.PG,
    InletGauge:= fb_EM2K0_XGMD_GCC_40.IG,
    ScrollPump:= fb_EM2K0_XGMD_PRT_50.stPump)
);
fb_EM2K0_XGMD_PTM_50(i_xExtILKOk := F_TurboExtILKLogic_2(
    Turbo:= fb_EM2K0_XGMD_PTM_50.iq_stPtm,
    BackingGauge:= fb_EM2K0_XGMD_GPI_10.PG,
    InletGauge:= fb_EM2K0_XGMD_GPI_50.PG,
    ScrollPump:= fb_EM2K0_XGMD_PRT_50.stPump)
);
fb_EM2K0_XGMD_PTM_60(i_xExtILKOk := F_TurboExtILKLogic_2(
    Turbo:= fb_EM2K0_XGMD_PTM_60.iq_stPtm,
    BackingGauge:= fb_EM2K0_XGMD_GPI_10.PG,
    InletGauge:= fb_EM2K0_XGMD_GCC_60.IG,
    ScrollPump:= fb_EM2K0_XGMD_PRT_50.stPump)
);
fb_EM2K0_XGMD_PTM_70(i_xExtILKOk := F_TurboExtILKLogic_2(
    Turbo:= fb_EM2K0_XGMD_PTM_70.iq_stPtm,
    BackingGauge:= fb_EM2K0_XGMD_GPI_10.PG,
    InletGauge:= fb_EM2K0_XGMD_GCC_70.IG,
    ScrollPump:= fb_EM2K0_XGMD_PRT_50.stPump)
);
fb_EM2K0_XGMD_PTM_80(i_xExtILKOk := F_TurboExtILKLogic_2(
    Turbo:= fb_EM2K0_XGMD_PTM_80.iq_stPtm,
    BackingGauge:= fb_EM2K0_XGMD_GPI_10.PG,
    InletGauge:= fb_EM2K0_XGMD_GCC_80.IG,
    ScrollPump:= fb_EM2K0_XGMD_PRT_50.stPump)
);
fb_EM2K0_XGMD_PTM_90(i_xExtILKOk := F_TurboExtILKLogic_2(
    Turbo:= fb_EM2K0_XGMD_PTM_90.iq_stPtm,
    BackingGauge:= fb_EM2K0_XGMD_GPI_10.PG,
    InletGauge:= fb_EM2K0_XGMD_GCC_90.IG,
    ScrollPump:= fb_EM2K0_XGMD_PRT_50.stPump)
);

// FB_VRC

fb_EM2K0_XGMD_VRC_10(
    i_xExtILK_OK := F_TurboGateValve_Protection_ILK_local(
            i_Turbo := fb_EM2K0_XGMD_PTM_10.iq_stPtm,
            i_stISG := fb_EM2K0_XGMD_GPI_50.PG,
            i_stBSG := fb_EM2K0_XGMD_GPI_10.PG,
            ScrollPump := fb_EM2K0_XGMD_PRT_50.stPump
    ),
    i_xOverrideMode := xSystemOverrideMode
);
fb_EM2K0_XGMD_VRC_20(
    i_xExtILK_OK := F_TurboGateValve_Protection_ILK_local(
            i_Turbo := fb_EM2K0_XGMD_PTM_20.iq_stPtm,
            i_stISG := fb_EM2K0_XGMD_GPI_50.PG,
            i_stBSG := fb_EM2K0_XGMD_GPI_10.PG,
            ScrollPump := fb_EM2K0_XGMD_PRT_50.stPump
    ),
    i_xOverrideMode := xSystemOverrideMode
);
fb_EM2K0_XGMD_VRC_30(
    i_xExtILK_OK := F_TurboGateValve_Protection_ILK_local(
            i_Turbo := fb_EM2K0_XGMD_PTM_30.iq_stPtm,
            i_stISG := fb_EM2K0_XGMD_GPI_50.PG,
            i_stBSG := fb_EM2K0_XGMD_GPI_10.PG,
            ScrollPump := fb_EM2K0_XGMD_PRT_50.stPump
    ),
    i_xOverrideMode := xSystemOverrideMode
);
fb_EM2K0_XGMD_VRC_40(
    i_xExtILK_OK := F_TurboGateValve_Protection_ILK_local(
            i_Turbo := fb_EM2K0_XGMD_PTM_40.iq_stPtm,
            i_stISG := fb_EM2K0_XGMD_GPI_50.PG,
            i_stBSG := fb_EM2K0_XGMD_GPI_10.PG,
            ScrollPump := fb_EM2K0_XGMD_PRT_50.stPump
    ),
    i_xOverrideMode := xSystemOverrideMode
);
fb_EM2K0_XGMD_VRC_60(
    i_xExtILK_OK := F_TurboGateValve_Protection_ILK_local(
            i_Turbo := fb_EM2K0_XGMD_PTM_60.iq_stPtm,
            i_stISG := fb_EM2K0_XGMD_GPI_50.PG,
            i_stBSG := fb_EM2K0_XGMD_GPI_10.PG,
            ScrollPump := fb_EM2K0_XGMD_PRT_50.stPump
    ),
    i_xOverrideMode := xSystemOverrideMode
);
fb_EM2K0_XGMD_VRC_70(
    i_xExtILK_OK := F_TurboGateValve_Protection_ILK_local(
            i_Turbo := fb_EM2K0_XGMD_PTM_70.iq_stPtm,
            i_stISG := fb_EM2K0_XGMD_GPI_50.PG,
            i_stBSG := fb_EM2K0_XGMD_GPI_10.PG,
            ScrollPump := fb_EM2K0_XGMD_PRT_50.stPump
    ),
    i_xOverrideMode := xSystemOverrideMode
);
fb_EM2K0_XGMD_VRC_80(
    i_xExtILK_OK := F_TurboGateValve_Protection_ILK_local(
            i_Turbo := fb_EM2K0_XGMD_PTM_80.iq_stPtm,
            i_stISG := fb_EM2K0_XGMD_GPI_50.PG,
            i_stBSG := fb_EM2K0_XGMD_GPI_10.PG,
            ScrollPump := fb_EM2K0_XGMD_PRT_50.stPump
    ),
    i_xOverrideMode := xSystemOverrideMode
);
fb_EM2K0_XGMD_VRC_90(
    i_xExtILK_OK := F_TurboGateValve_Protection_ILK_local(
            i_Turbo := fb_EM2K0_XGMD_PTM_90.iq_stPtm,
            i_stISG := fb_EM2K0_XGMD_GPI_50.PG,
            i_stBSG := fb_EM2K0_XGMD_GPI_10.PG,
            ScrollPump := fb_EM2K0_XGMD_PRT_50.stPump
    ),
    i_xOverrideMode := xSystemOverrideMode
);

// FB_MKS422

fb_EM2K0_XGMD_GCC_10(PG := fb_EM2K0_XGMD_GPI_50.PG);
fb_EM2K0_XGMD_GCC_20(PG := fb_EM2K0_XGMD_GPI_50.PG);
fb_EM2K0_XGMD_GCC_30(PG := fb_EM2K0_XGMD_GPI_50.PG);
fb_EM2K0_XGMD_GCC_40(PG := fb_EM2K0_XGMD_GPI_50.PG);
fb_EM2K0_XGMD_GCC_50(PG := fb_EM2K0_XGMD_GPI_50.PG);
fb_EM2K0_XGMD_GCC_60(PG := fb_EM2K0_XGMD_GPI_50.PG);
fb_EM2K0_XGMD_GCC_70(PG := fb_EM2K0_XGMD_GPI_50.PG);
fb_EM2K0_XGMD_GCC_80(PG := fb_EM2K0_XGMD_GPI_50.PG);
fb_EM2K0_XGMD_GCC_90(PG := fb_EM2K0_XGMD_GPI_50.PG);

// FB_EbaraEVA
fb_EM2K0_XGMD_PRT_50(i_xExtIlkOK := TRUE);

// FB_VVC
IF bAutoVVC50 THEN
    IF fb_EM2K0_XGMD_PTM_50.iq_stPtm.eState = pumpRUNNING OR  fb_EM2K0_XGMD_PTM_50.iq_stPtm.eState = pumpStarting THEN
            fb_EM2K0_XGMD_VVC_50.M_Open(True);
    ELSE
            fb_EM2K0_XGMD_VVC_50.M_Open(False);
    END_IF
END_IF

fb_EM2K0_XGMD_VVC_50(
    i_xExtILK_OK := fb_EM2K0_XGMD_PTM_50.iq_stPtm.eState = pumpRUNNING OR  fb_EM2K0_XGMD_PTM_50.iq_stPtm.eState = pumpStarting,//F_TURBO_PROT_SLND_ILK(
       // i_Turbo := fb_EM2K0_XGMD_PTM_50.iq_stPtm,
       // i_stISG := fb_EM2K0_XGMD_GPI_50.PG,
       // i_stBSG := fb_EM2K0_XGMD_GPI_10.PG,
      //  ScrollPump := fb_EM2K0_XGMD_PRT_50.stPump
    //),
    i_xOverrideMode := xSystemOverrideMode,
);



// Roughing valve
IF( fb_EM2K0_XGMD_PRT_50.stPump.eState = pumpSTARTING ) OR ( fb_EM2K0_XGMD_PRT_50.stPump.eState = pumpRUNNING ) THEN fb_EM1K0_GMD_VRO_50.M_Open(TRUE); END_IF
fb_EM1K0_GMD_VRO_50(i_xExtILK_OK:= (fb_EM2K0_XGMD_PRT_50.stPump.eState = pumpRUNNING  OR  fb_EM2K0_XGMD_PRT_50.stPump.eState = pumpSTARTING ), i_xOverrideMode:= , iq_stValve=> );

END_PROGRAM

PRG_HV_ILK

PROGRAM PRG_HV_ILK
VAR
END_VAR
//evaluate the HV ILK_OK bit
//HV_ILK_OK := GCC_40.IG.xAT_VAC;

hv1(i_xExtIlkOK := F_HV_ILK(
    IG := fb_EM2K0_XGMD_GCC_50.IG,
    HV := hv1.hv)
);
//hv2(i_xExtIlkOK := HV_ILK_OK);

END_PROGRAM

PRG_INJ

PROGRAM PRG_INJ
VAR
    i:INT;
    fullScale: REAL :=2000;
    DefaultSP :REAL:=0;
    rFULL_SCALE:REAL:=3000;//psig
END_VAR
// GCM
GCM_80(i_rFULL_SCALE := fullScale );
GCM_80.M_SetBits(30518);


i:=i+1;
//GHC
GHC_50.M_SetBits(30518);
GHC_50(PG=> );

// Vent Valves
// interlock evaluation

VVC_80.i_xExtILK_OK := (VCN_50.iq_stVCN.eValveControl = E_VCN.CloseValve) OR( (NOT VVC_81.iq_stValve.q_xOPN_DO) AND(NOT VVC_82.iq_stValve.q_xOPN_DO)); // we need to purge all the way up to the VCN
VVC_81.i_xExtILK_OK :=  (VVC_82.iq_stValve.q_xOPN_DO) AND(NOT VVC_83.iq_stValve.q_xOPN_DO) AND(NOT VVC_84.iq_stValve.q_xOPN_DO) AND (NOT VVC_85.iq_stValve.q_xOPN_DO) AND (NOT VVC_86.iq_stValve.q_xOPN_DO);// AND (NOT VVC_80.iq_stValve.q_xOPN_DO);
VVC_82.i_xExtILK_OK := (NOT VVC_83.iq_stValve.q_xOPN_DO) AND(NOT VVC_84.iq_stValve.q_xOPN_DO) AND (NOT VVC_85.iq_stValve.q_xOPN_DO) AND (NOT VVC_86.iq_stValve.q_xOPN_DO);// AND (NOT VVC_80.iq_stValve.q_xOPN_DO);

// instanitation
VVC_80(i_xExtILK_OK:= , i_xOverrideMode:= xOverrideMode, iq_stValve=> );
VVC_81(i_xExtILK_OK:= , i_xOverrideMode:= xOverrideMode, iq_stValve=> );
VVC_82(i_xExtILK_OK:= , i_xOverrideMode:= xOverrideMode, iq_stValve=> );



// Gas panel

// Interlock evaluation
VVC_83.i_xExtILK_OK := (NOT VVC_84.iq_stValve.q_xOPN_DO) AND (NOT VVC_85.iq_stValve.q_xOPN_DO) AND (NOT VVC_86.iq_stValve.q_xOPN_DO) AND (NOT VVC_81.iq_stValve.q_xOPN_DO) AND (NOT VVC_82.iq_stValve.q_xOPN_DO) AND NOT bPurgeActive;
VVC_84.i_xExtILK_OK := (NOT VVC_83.iq_stValve.q_xOPN_DO) AND (NOT VVC_85.iq_stValve.q_xOPN_DO) AND (NOT VVC_86.iq_stValve.q_xOPN_DO) AND (NOT VVC_81.iq_stValve.q_xOPN_DO) AND (NOT VVC_82.iq_stValve.q_xOPN_DO) AND NOT bPurgeActive  ;
VVC_85.i_xExtILK_OK := (NOT VVC_83.iq_stValve.q_xOPN_DO) AND (NOT VVC_84.iq_stValve.q_xOPN_DO) AND (NOT VVC_86.iq_stValve.q_xOPN_DO) AND (NOT VVC_81.iq_stValve.q_xOPN_DO) AND (NOT VVC_82.iq_stValve.q_xOPN_DO) AND NOT bPurgeActive;
VVC_86.i_xExtILK_OK := (NOT VVC_83.iq_stValve.q_xOPN_DO) AND (NOT VVC_84.iq_stValve.q_xOPN_DO) AND (NOT VVC_85.iq_stValve.q_xOPN_DO) AND (NOT VVC_81.iq_stValve.q_xOPN_DO) AND (NOT VVC_82.iq_stValve.q_xOPN_DO) AND NOT bPurgeActive ;

//Gas Panel
VVC_83(i_xExtILK_OK:= , i_xOverrideMode:= xOverrideMode, iq_stValve=> );
VVC_84(i_xExtILK_OK:= , i_xOverrideMode:= xOverrideMode, iq_stValve=> );
VVC_85(i_xExtILK_OK:= , i_xOverrideMode:= xOverrideMode, iq_stValve=> );
VVC_86(i_xExtILK_OK:= , i_xOverrideMode:= xOverrideMode, iq_stValve=> );

END_PROGRAM

PRG_PressureControl

PROGRAM PRG_PressureControl
VAR CONSTANT
            nDataTable_NumberOfRows : INT:=9;
END_VAR
VAR

    fActualValue                            : FLOAT;
    fCtrlOutput                                             : FLOAT;
    fBasicCtrlOutput                                                : FLOAT;
    f_Rep_POS: Float;


    fManValue                                                                                       : FLOAT;
    bExtrapolate                                                                            : BOOL;
    fManSyncValue                   : FLOAT;
    bSync                                           : BOOL;

    bHold                                           : BOOL;

    eMode                                           : E_CTRL_MODE;
    stCTRL_PID_PARAMS               : ST_CTRL_PID_PARAMS;
    stCTRL_LIN_INTERPOLATION_PARAMS         : ST_CTRL_LIN_INTERPOLATION_PARAMS;

    eErrorId                                        : E_CTRL_ERRORCODES;
    bARWactive                              : BOOL;
    arrTable        : ARRAY[1..31,1..2] OF FLOAT;
    (* controller  *)
    fbCTRL_PID                                      : FB_CTRL_PID;
    fbCTRL_Normalize        : FB_CTRL_NORMALIZE;
    fbCTRL_LIN_INTERPOLATION                                        : FB_CTRL_LIN_INTERPOLATION;
    fbCTRL_DEADBAND                                         : FB_CTRL_DEADBAND;
    stCTRL_DEADBAND_PARAMS                  : ST_CTRL_DEADBAND_PARAMS;

    bInit                                           : BOOL          := TRUE;
    wait : time := T#10S;
    FTrig: F_TRIG;
END_VAR
//Set VRC upper limit
IF bInit
THEN
    VCN_50.M_SetThrottle(30); // default at start up, should be changed through epics pv
END_IF
//VCN //bAdditionalVCNIlk
IF (bAdditionalVCNIlk) THEN
    VCN_50.i_xExtIlkOK := ( fb_EM2K0_XGMD_GCC_10.IG.xAT_VAC AND  fb_EM2K0_XGMD_GCC_20.IG.xAT_VAC AND fb_EM2K0_XGMD_GCC_30.IG.xAT_VAC AND  fb_EM2K0_XGMD_GCC_40.IG.xAT_VAC
                                                    AND  fb_EM2K0_XGMD_GCC_50.IG.xAT_VAC AND  fb_EM2K0_XGMD_GCC_60.IG.xAT_VAC AND fb_EM2K0_XGMD_GCC_70.IG.xAT_VAC AND  fb_EM2K0_XGMD_GCC_80.IG.xAT_VAC  AND  fb_EM2K0_XGMD_GCC_90.IG.xAT_VAC)
                                                            AND  fb_EM2K0_XGMD_GPI_50.PG.xAT_VAC AND (NOT VVC_81.iq_stValve.q_xOPN_DO) AND(NOT VVC_82.iq_stValve.q_xOPN_DO);
    ELSE

            VCN_50.i_xExtIlkOK :=  fb_EM2K0_XGMD_GPI_50.PG.xAT_VAC AND (NOT VVC_81.iq_stValve.q_xOPN_DO) AND(NOT VVC_82.iq_stValve.q_xOPN_DO);
END_IF

VCN_50(i_xExtIlkOK :=, i_ReqPos:= );

(* Gauge selection *)
(*Assign reading to psuedo gauge*)
IF (fb_EM2K0_XGMD_GCC_50.IG.rPRESS <=0.0001) AND (fb_EM2K0_XGMD_GCC_50.IG.rPRESS >0) THEN GCP := fb_EM2K0_XGMD_GCC_50.IG;
                    ElSE GCP := fb_EM2K0_XGMD_GPI_50.PG;
END_IF


(*-------------------------------------------------------------------*)
(*             PI CONTROL          *)
(*-------------------------------------------------------------------*)


IF bInit
THEN
    (*FBCNTRL*)
    (* init parameter struct *)
    stCTRL_PID_PARAMS.tCtrlCycleTime                := T#10ms;
    stCTRL_PID_PARAMS.tTaskCycleTime                := T#10ms;
    stCTRL_PID_PARAMS.fKp                                   := fKp1;                        (* proportional gain Kp                         *)
    stCTRL_PID_PARAMS.tTn                                   := T#500ms;             (*  Tn                                                                  *)
    stCTRL_PID_PARAMS.tTv                                   := T#200ms;     (*  Tv                                                                  *)
    stCTRL_PID_PARAMS.tTd                                   := T#100ms;     (*  Td                                                                  *)
    stCTRL_PID_PARAMS.fOutMaxLimit                  :=  78;                 (* maximum output limit                         *)
    stCTRL_PID_PARAMS.fOutMinLimit                  :=  -100;                       (* minimum output limit                         *)


    (* init array with the interpolation points  *)
    (*      fIn                                      |              fOut            *)
(*  fIn                                      |              fOut            *)
    arrTable[1,1] := 0;             arrTable[1,2] := 5;
    arrTable[2,1] := 0.0000412;             arrTable[2,2] := 34;
    arrTable[3,1] := 0.001282;              arrTable[3,2] := 36;
    arrTable[4,1] :=  0.002136;         arrTable[4,2] := 38;
    arrTable[5,1] :=  0.005884;         arrTable[5,2] := 40;
    arrTable[6,1] := 0.00907;               arrTable[6,2] := 42;
    arrTable[7,1] := 0.01183;               arrTable[7,2] := 44;
    arrTable[8,1] := 0.01799;           arrTable[8,2] := 46;
    arrTable[9,1] := 0.0302;            arrTable[9,2] := 47;
    arrTable[10,1] := 0.0417;               arrTable[10,2] := 50;
    arrTable[11,1] := 0.06635;              arrTable[11,2] := 51;
    arrTable[12,1] := 0.08118;              arrTable[12,2] := 53;
    arrTable[13,1] := 0.0998;               arrTable[13,2] := 56;
    arrTable[14,1] := 0.10644;              arrTable[14,2] := 56.5;
    arrTable[15,1] := 0.1359;               arrTable[15,2] := 58;
    arrTable[16,1] := 0.1929;               arrTable[16,2] := 60;
    arrTable[17,1] := 0.2922;               arrTable[17,2] := 62;
    arrTable[18,1] := 0.3428;           arrTable[18,2] := 64;
    arrTable[19,1] :=  0.405;;          arrTable[19,2] :=66;
    arrTable[20,1] := 0.481;                arrTable[20,2] := 68;
    arrTable[21,1] := 0.5542;               arrTable[21,2] := 69;
    arrTable[22,1] := 0.6333;           arrTable[22,2] := 70;
    arrTable[23,1] := 0.7901;           arrTable[23,2] := 72;
    arrTable[24,1] := 0.9307;               arrTable[24,2] := 73.04;
    arrTable[25,1] := 1.0448;               arrTable[25,2] := 73.64;
    arrTable[26,1] := 1.31919;;             arrTable[26,2] := 74.45;
    arrTable[27,1] :=  1.324;               arrTable[27,2] :=74.46;
    arrTable[28,1] := 1.71941;      arrTable[28,2] := 75;
    arrTable[29,1] :=  1.963194;            arrTable[29,2] :=75.5;
    arrTable[30,1] := 1.99999;      arrTable[30,2] := 75.505;
    arrTable[31,1] := 2;    arrTable[31,2] := 75.55;


    (* init parameter struct *)
    stCTRL_LIN_INTERPOLATION_PARAMS.tCtrlCycleTime                                  := T#10ms;
    stCTRL_LIN_INTERPOLATION_PARAMS.tTaskCycleTime                                  := T#10ms;
    stCTRL_LIN_INTERPOLATION_PARAMS.nDataTable_NumberOfRows         := INT_TO_UINT(31);


    (* set the mode to ACTIVE --> normal operation *)
    eMode                                                   := eCTRL_MODE_ACTIVE;

    (* reset the init flag *)
    bInit                                                   := FALSE;
END_IF
(* set the addresses *)
    stCTRL_LIN_INTERPOLATION_PARAMS.pDataTable_ADR                  := ADR(arrTable);
    stCTRL_LIN_INTERPOLATION_PARAMS.nDataTable_SIZEOF               := SIZEOF(arrTable);

fSetpointValue:= LIMIT(0,fSetpointValue,0.001);

if (VVC_80.M_IsClosed() ) THEN
            //eMode := eCTRL_MODE_PASSIVE;
            fSetpointValue :=0;
END_IF

if (bGo) THEN
    VCN_50.i_ReqPos:=  fbCTRL_LIN_INTERPOLATION.fOut + fbCTRL_PID.fOut;
    IF (bReset) THEN
    (* set the mode to RESET*)
    eMode                                                   := eCTRL_MODE_RESET   ;
    VCN_50.M_ValveControl(CloseValve);
    //bReset := False;
    ELSE
            (* set the mode to ACTIVE --> normal operation *)
    eMode                                                   := eCTRL_MODE_ACTIVE   ;
    VCN_50.M_ValveControl(PressureControl);
    END_IF
END_IF
If(FTrig.Q)THEN
            eMode                                                   := eCTRL_MODE_PASSIVE;
            VCN_50.M_ValveControl(CloseValve);
            fSetpointValue :=0;
END_IF

(* call interpolation fb *)
fbCTRL_LIN_INTERPOLATION(
    fIn:= fSetpointValue ,
    fManValue:= fManValue ,
    bExtrapolate:= bExtrapolate,
    eMode:= eMode,
    stParams:= stCTRL_LIN_INTERPOLATION_PARAMS,
    fOut=> ,
    bInIsGreaterThanMaxElement=> ,
    bInIsLessThanMinElement=> ,
    eState=> ,
    eErrorId=> ,
    bError=> );



(* call controller *)
fbCTRL_PID(         fSetpointValue          := fSetpointValue,
                                    fActualValue            := ,
                                    fManSyncValue   := ,
                                    bSync                           := bSync,
                                    eMode                           := eMode,
                                    bHold                           := bHold,
                                    stParams                        := stCTRL_PID_PARAMS,
                                    fOut                            => ,
                                    bARWactive              => bARWactive,
                                    eErrorId                        => eErrorId,
                                    bError                          =>
                            );

                            (*deadband/clipper *)

(* call function block *)
stCTRL_DEADBAND_PARAMS.fThreshold   :=  fSetpointValue*0.0016 ;
(*fbCTRL_DEADBAND   (       fIn                                     := ,
                                    stParams                        := stCTRL_DEADBAND_PARAMS,
                                    bInIsUnderThreshold => ,
                                    eErrorId                        => ,
                                    bError                          =>
                            );*)

bError := fbCTRL_PID.bError OR fbCTRL_LIN_INTERPOLATION.bError;


FTRIG(CLK := bGo);

END_PROGRAM

PRG_Purge

PROGRAM PRG_Purge
VAR
    step: INT:=0;
    {attribute 'pytmc' := '
    pv: EM2K0:XGMD:sPURGE
    '}
    sMessage : STRING;

    {attribute 'pytmc' := '
    pv: EM2K0:XGMD:RESET
    '}
    bReset:BOOL := False;

    {attribute 'pytmc' := '
    pv: EM2K0:XGMD:PurgeError
    '}
    bError:BOOL := False;

    {attribute 'pytmc' :=' pv: EM2K0:XGMD:PURGE:SP1;
    field: HOPR 1000;
    field: LOPR 0;
    field: PREC 2;
    field: EGU "TORR";
    '}
    rPurge_SP1 :REAL :=0.01;

    {attribute 'pytmc' :=' pv: EM2K0:XGMD:PURGE:SP2;
    field: HOPR 1000;
    field: LOPR 0;
    field: PREC 2;
    field: EGU "TORR";
    '}
    rPurge_SP2 :REAL :=0.1;


    {attribute 'pytmc' :=' pv: EM2K0:XGMD:PURGE:REPEAT;
    '}
    NeedlePurgeRepeat       : INT:= 1;
    NeedleVlvPurgeTmr       : TON;  (* Declaration for the needle valve Purge timer *)
    tNeedlePurgeTime                : TIME:=T#5S;
    NeedlePurgeTime         : TIME:=T#5S;
    BurpET                          : TIME;
    NeedlePurgeRun          : BOOL;
    NeedlePurgeDone         : BOOL;

    VCN_Timer       :TON;


    rt_reset: R_TRIG;

    // Timers
    VVC_80_Timer : TON;
    VVC_81_Timer : TON;
    VVC_82_Timer : TON;
    VVC_80_Time                     : TIME:=T#30S;
    VVC_81_Time                     : TIME:=T#5S;
    VVC_82_Time                     : TIME:=T#5S;
    VCN_Time : TIME := T#5S;

    iVGP_POS: REAL:=0;


END_VAR
(*
PURGE CYCLE
The purge cycle consists of the following steps;
1. Close all gas valves 83-86 and Close Needle valve and switch off PID control
2. Wait till needle valve closes
3. Close VGP, to protect the Detector chamber in case a pressure spike on the roughing line stops the turbo.
4. PUMP DOWN MANIFOLD: Open VVC-80  then Open VVC82 for certain pressure on the baratron
5. Open VIC:81 and keep it open while the manifold pumps down to pressure set point for a certain time to avoid flukes then close VVC-80
 - THEN Fully open VGP:40
6. BURP NEEDLE VALVE: Once the manifold is pumped down, open the needle valve (burp) to evacuate gases that may be trapped in its mechanism
- this step is done gradually to avoid sending pressure spike into the detector
7. Close needle valve
8. Release VGP:40

*)


CASE step OF
            0: // READY STATE
            sMessage:= 'Purge Ready';
            bError := FALSE;
            IF (bStartPurge_sw) Then
                    step:=10;
                    bGo :=FALSE;
                    bPurgeActive := true;
                    bPurgeDone := false;
                    iVGP_POS := VGP_50.q_stVGP.rReqPosition;
                    sMessage:= 'Purge Start';
            END_IF

10: // start purge sequence by closing all gas valves and needle valve
    VVC_80.M_Set_OPN_SW(FALSE);
    VVC_81.M_Set_OPN_SW(FALSE);
    VVC_82.M_Set_OPN_SW(FALSE);
    VVC_83.M_Set_OPN_SW(FALSE);
    VVC_84.M_Set_OPN_SW(FALSE);
    VVC_85.M_Set_OPN_SW(FALSE);
    VVC_86.M_Set_OPN_SW(FALSE);
    VCN_50.M_ValveControl(E_VCN.CloseValve);
    IF   (NOT VVC_80.iq_stValve.q_xOPN_DO) AND (NOT VVC_81.iq_stValve.q_xOPN_DO)  AND (NOT VVC_82.iq_stValve.q_xOPN_DO)
                    AND (NOT VVC_83.iq_stValve.q_xOPN_DO) AND (NOT VVC_84.iq_stValve.q_xOPN_DO) AND (NOT VVC_85.iq_stValve.q_xOPN_DO) AND (NOT VVC_86.iq_stValve.q_xOPN_DO) THEN
            step:= 20;
            sMessage:= 'Prep: All valves are closed';
    END_IF

20: //Close Needle valve
    VCN_50.M_ValveControl( E_VCN.CloseValve);
    //sMessage:= 'Prep: Needle Valve is closed';
    // wait for a period of time to ensure that the Valve is fully closed
    IF (VCN_Timer.Q) THEN
            step:=30;
            sMessage:= 'Prep: Needle Valve is closed';
    END_IF


30: //Fully close VGP:40
    VGP_50.M_ValveControl(E_VCN.CloseValve);
    VGP_50.M_SetGoSw(TRUE);
    IF NOT(VGP_50.q_stVGP.eState = E_MoveState.READY)THEN // wait until the VGP Starts moving
            step:=31;
            sMessage:= 'Prep: VGP to fully closed';
    END_IF
    if (VGP_50.q_stVGP.pv_xError ) OR NOT (VGP_50.i_xExtIlkOK) OR NOT (VGP_50.q_stVGP.pv_xHomed) THEN
            step:=900+step;
    END_IF
31:
    IF (VGP_50.q_stVGP.eState = E_MoveState.READY ) THEN // wait until the VGP motion is done
            step:=40;
            sMessage:= 'Prep: VGP is closed';
    END_IF
    if (VGP_50.q_stVGP.pv_xError )then
            step:=900+step;
    END_IF

40: // open vavle 80 to pump down all the way to the needle valve
    //VVC_80.M_Set_OPN_SW(TRUE);
    //if (VVC_80.iq_stValve.q_xOPN_DO ) THEN
    step:=41;
    //END_IF

41: //PUMP DOWN MANIFOLD: Open VIC82 for a certain peroid of time or till certain pressure
    VVC_82.M_Set_OPN_SW(TRUE);
    sMessage:= 'Pumping down: VVC82 is open';
    if (VVC_82.iq_stValve.q_xOPN_DO) AND (VVC_82_Timer.Q) AND (GCM_80.PG.rPRESS <= rPurge_SP1) THEN
            step:=50;
    END_IF

50:// Open VIC:81 and keep it open while the manifold pumps down to pressure set point
    VVC_81.M_Set_OPN_SW(TRUE);
    sMessage:= 'Pumping down:  VVC81 and VVC82 are open';
    IF (VVC_81.iq_stValve.q_xOPN_DO ) AND (VVC_81_Timer.Q) AND (GCM_80.PG.rPRESS <= rPurge_SP2) THEN // or a certain pressure reading and check timeouts
            step:=51;
    END_IF

51: // open vavle 80 to pump down all the way to the needle valve
    VVC_80.M_Set_OPN_SW(TRUE);
    if (VVC_80.iq_stValve.q_xOPN_DO ) THEN
    step:=52;
    END_IF

52:// Open VIC:81 and keep it open while the manifold pumps down to pressure set point
    VVC_81.M_Set_OPN_SW(TRUE);
    sMessage:= 'Pumping down:  VVC80, VVC81 and VVC82 are open';
    IF (VVC_81.iq_stValve.q_xOPN_DO ) AND (VVC_80_Timer.Q) AND (GCM_80.PG.rPRESS <= rPurge_SP2) THEN // or a certain pressure reading and check timeouts
            step:=54;
    END_IF


54: //Close VIC:81 and VIC:82
    VVC_80.M_Set_OPN_SW(false);
    VVC_81.M_Set_OPN_SW(false);
    VVC_82.M_Set_OPN_SW(false);
    sMessage:= 'Pumping down complete: valves are closed';
    IF (NOT VVC_80.iq_stValve.q_xOPN_DO) AND(NOT VVC_81.iq_stValve.q_xOPN_DO) AND(NOT VVC_82.iq_stValve.q_xOPN_DO) THEN
            step:=55;
    END_IF

55: //Fully close VGP
    VGP_50.M_ValveControl(E_VCN.OpenValve);
    IF NOT(VGP_50.q_stVGP.eState = E_MoveState.READY ) THEN // wait until the VGP Starts moving
            step:=56;
            sMessage:= 'Prep: VGP to fully open';
    END_IF
    if (VGP_50.q_stVGP.pv_xError ) OR NOT (VGP_50.i_xExtIlkOK) OR NOT (VGP_50.q_stVGP.pv_xHomed) THEN
            step:=900+step;
    END_IF
56:
    IF (VGP_50.q_stVGP.eState = E_MoveState.READY ) THEN // wait until the VGP motion is done
            step:=60;
            sMessage:= 'Prep: VGP is Open';
    END_IF
    if (VGP_50.q_stVGP.pv_xError )then
            step:=900+step;
    END_IF

60: //BURP NEEDLE VALVE: Once the manifold is pumped down, open the needle valve (burp) to evacuate gases that may be trapped in its mechanism
    VCN_50.M_ValveControl(E_VCN.PressureControl);
    VCN_50.i_ReqPos := 15;
    sMessage:= 'VCN Burp: VCN to 15%';
    // wait for a period of time to ensure that the Valve is fully closed
    IF (NeedleVlvPurgeTmr.Q) THEN
            step:=61;
    END_IF

61:
    VCN_50.i_ReqPos := 19;
    sMessage:= 'VCN Burp: VCN to 19%';
    IF (VCN_Timer.Q) THEN
            step:=62;
    END_IF

62: //BURP NEEDLE VALVE: Once the manifold is pumped down, open the needle valve (burp) to evacuate gases that may be trapped in its mechanism
    VCN_50.i_ReqPos := 25;
    sMessage:= 'VCN Burp: VCN to 25%';
    // wait for a period of time to ensure that the Valve is fully closed
    IF (NeedleVlvPurgeTmr.Q) THEN
            step:=63;
    END_IF

63:
    VCN_50.i_ReqPos := 31;
    sMessage:= 'VCN Burp: VCN to 31%';
    IF (VCN_Timer.Q) THEN
            step:=64;
    END_IF

64:
    VCN_50.i_ReqPos := 39;
    sMessage:= 'VCN Burp: VCN to 39%';
    IF (NeedleVlvPurgeTmr.Q) THEN
            step:=65;
    END_IF

65:
    VCN_50.i_ReqPos := 49;
    sMessage:= 'VCN Burp: VCN to 49%';
    IF (VCN_Timer.Q) THEN
            step:=66;
    END_IF

66:
    VCN_50.i_ReqPos := 62;
    sMessage:= 'VCN Burp: VCN to 62%';
    IF (NeedleVlvPurgeTmr.Q) THEN
            step:=67;
    END_IF

67:
    VCN_50.i_ReqPos := 78;
    sMessage:= 'VCN Burp: VCN to 78%';
    IF (VCN_Timer.Q) THEN
            step:=68;
    END_IF

68:
    VCN_50.i_ReqPos := 100;
    sMessage:= 'VCN Burp: VCN to 100%';
    IF (NeedleVlvPurgeTmr.Q) THEN
            step:=70;
    END_IF

70: //Close Needle valve
    VCN_50.M_ValveControl(E_VCN.CloseValve);
    sMessage:= 'VCN Burp Complete: VCN to 0%';
    // wait for a period of time to ensure that the Valve is fully closed
    IF (VCN_Timer.Q) THEN
            step:=80;
    END_IF

80: // Repeat
    IF (NeedlePurgeRepeat > 0) THEN
            NeedlePurgeRepeat := NeedlePurgeRepeat-1;
            step:= 60;
    ELSE
            NeedlePurgeRepeat := 1;
            step:=90;
    END_IF


90: //Release VGP:40
    VGP_50.M_ValveControl(E_VCN.ManualControl);
    VGP_50.i_ReqPos:= iVGP_POS; //50% open
    VGP_50.M_SetGoSw(TRUE);
    sMessage:= 'Post: VGP to previous position';
    IF NOT(VGP_50.q_stVGP.eState = E_MoveState.READY ) THEN // wait until the VGP encoder reads Open //use motion ready
            step:=91;
    END_IF
    if (VGP_50.q_stVGP.pv_xError )then
            step:=900+step;
    END_IF

91:
    IF (VGP_50.q_stVGP.eState = E_MoveState.READY ) THEN // wait until the VGP encoder reads Open //use motion ready
            VGP_50.M_ValveControl(E_VCN.ManualControl);
            VGP_50.i_ReqPos:= 0;
            VGP_50.M_SetGoSw(FALSE);
            step:=100;
            sMessage:= 'Purge Complete';
    END_IF
    if (VGP_50.q_stVGP.pv_xError )then
            step:=900+step;
    END_IF

100: // DONE
    bStartPurge_sw := false;
    bPurgeActive := false;
    bPurgeDone := TRUE;
    VVC_80.M_Set_OPN_SW(false);
    VVC_81.M_Set_OPN_SW(false);
    VVC_82.M_Set_OPN_SW(false);
    VVC_83.M_Set_OPN_SW(false);
    VVC_84.M_Set_OPN_SW(false);
    VVC_85.M_Set_OPN_SW(false);
    VVC_86.M_Set_OPN_SW(false);
    VCN_50.M_ValveControl(E_VCN.CloseValve);
    VGP_50.M_ValveControl(E_VCN.ManualControl);
    // reset selected gas to none
    SelectedGas := E_GasType.none;
    step :=0;

900: //Error
    bStartPurge_sw := false;
    bPurgeActive := false;
    bPurgeDone := FALSE;
    bError := TRUE;
    VVC_80.M_Set_OPN_SW(false);
    VVC_81.M_Set_OPN_SW(false);
    VVC_82.M_Set_OPN_SW(false);
    VVC_83.M_Set_OPN_SW(false);
    VVC_84.M_Set_OPN_SW(false);
    VVC_85.M_Set_OPN_SW(false);
    VVC_86.M_Set_OPN_SW(false);
    VCN_50.M_ValveControl(E_VCN.CloseValve);
    VGP_50.M_ValveControl(E_VCN.ManualControl); // CLOSE or OPEN to pump down
    sMessage:= 'Purge Error: Interlock';
END_CASE


//shouldn't be here
(*
if (bPurgeActive) then
    VVC_83.i_xExtILK_OK := VVC_84.i_xExtILK_OK := VVC_85.i_xExtILK_OK := VVC_86.i_xExtILK_OK := false;
END_IF
*)

//Errors
if (step >900 ) Then
    //Error
    bStartPurge_sw := false;
    bPurgeActive := false;
    bPurgeDone := false;
    bError := TRUE;
    VVC_80.M_Set_OPN_SW(false);
    VVC_81.M_Set_OPN_SW(false);
    VVC_82.M_Set_OPN_SW(false);
    VVC_83.M_Set_OPN_SW(false);
    VVC_84.M_Set_OPN_SW(false);
    VVC_85.M_Set_OPN_SW(false);
    VVC_86.M_Set_OPN_SW(false);
    VCN_50.M_ValveControl(E_VCN.CloseValve);
    VGP_50.M_ValveControl(E_VCN.ManualControl);
    sMessage:= CONCAT('Purge Error: ',TO_STRING(step));
END_IF

rt_reset(CLK:= bReset);
IF rt_reset.Q THEN Step:=100; bReset:=False; bPurgeDone:=False; END_IF

//Timers
VVC_80_Timer(IN:=(step = 52), PT:=VVC_80_Time);
VVC_81_Timer(IN:= (step = 50) , PT:=VVC_81_Time);
VVC_82_Timer(IN:= (step = 41), PT:=VVC_82_Time);
VCN_Timer(IN:= (step = 20) OR (step = 61)  OR (step = 63)  OR (step = 65)  OR (step = 67) OR (step = 70), PT:=VCN_Time);
NeedleVlvPurgeTmr(IN:= (step = 60) OR (step = 62)  OR (step = 64)  OR (step = 66)  OR (step = 68), PT:=NeedlePurgeTime );

//
IF (bStartPurge_sw) THEN bGo :=FALSE; END_IF
/// If at any point the VGP interlocked or in an error state, we stop purge.

IF ((VGP_50.q_stVGP.pv_xError ) OR NOT (VGP_50.i_xExtIlkOK)) AND (bPurgeActive)  AND (step >=55) AND (step <=70) THEN
            step:=900;
END_IF
IF NOT (VCN_50.i_xExtIlkOK) AND (bPurgeActive) AND (step >=60) AND (step <=70) THEN
            step:=900;
END_IF

IF (NOT (fb_EM2K0_XGMD_PRT_50.stPump.eState = E_PumpState.pumpRUNNING)) AND (bPurgeActive) THEN
            step:=900;
END_IF

END_PROGRAM

PRG_VAC_INTF

PROGRAM PRG_VAC_INTF
VAR
END_VAR
ads_watch_dog(
    sNetId := '172.21.92.61.1.1', // AMS NET ID of the PLC reading from this PLC (SXR Vacuum PLC)
    nPort := 851, // ADS port of the PLC reading from this PLC
    sVarName := 'GVL_VAC_INTF.n_EM2K0_VAC_counter', // Full name of the UDINT provided to the 'iWatchdog' parameter in the interface functions on the PLC reading from this PLC
);

END_PROGRAM

PRG_VGP

PROGRAM PRG_VGP
VAR
    arrTable                                                                                        : ARRAY[1..14,1..2] OF FLOAT;
    arrTable_ENC                                                                            : ARRAY[1..14,1..2] OF FLOAT;

    bInit: BOOL:=true;

    VGP_REQ_POS: LREAL;
    VGP_OUT_POS:LREAL;
END_VAR
IF bInit
THEN


    (* init array with the interpolation points  *)
    (*      fIn                                      |              fOut            *)
    arrTable[1,1] := 0;                     arrTable[1,2] := 0;
    arrTable[2,1] := 5;                 arrTable[2,2] := 170;
    arrTable[3,1] := 10;            arrTable[3,2] := 280;
    arrTable[4,1] :=  20;       arrTable[4,2] := 445;
    arrTable[5,1] :=  30;       arrTable[5,2] := 575;
    arrTable[6,1] := 40;            arrTable[6,2] := 725;
    arrTable[7,1] := 50;            arrTable[7,2] := 860;
    arrTable[8,1] := 60;        arrTable[8,2] := 980;
    arrTable[9,1] := 70;        arrTable[9,2] := 1120;
    arrTable[10,1] := 80;           arrTable[10,2] := 1250;
    arrTable[11,1] := 90;           arrTable[11,2] := 1420;
    arrTable[12,1] := 95;           arrTable[12,2] := 1550;
    arrTable[13,1] := 98;           arrTable[13,2] := 1600;
    arrTable[14,1] := 100;          arrTable[14,2] := 1660;


    (* reset the init flag *)
    bInit                                                   := FALSE;
END_IF

VGP_50.i_xOpenIlkOK := (fb_EM2K0_XGMD_PTM_50.iq_stPtm.eState = pumpRUNNING) ;

VGP_50(
    i_xExtIlkOK:= (fb_EM2K0_XGMD_PTM_50.iq_stPtm.eState = pumpRUNNING),
    i_ReqPos:=  ,
    arrTable:= arrTable ,
    q_stVGP=> );

END_PROGRAM