DUTs

E_PositionState

TYPE E_PositionState :
(
RETRACTED    := 0,
INSERTED    := 1,
MOVING    := 2,
INVALID :=3
);
END_TYPE
Related:

ST_MPA

TYPE ST_MPA :
STRUCT
//    i_xInsertLS AT %I*: BOOL;
//    i_xRetractLS AT %I*: BOOL;
//    _xInsertSW : BOOL;
//    _xRetractSW : BOOL;
//    q_xInsertDO AT %Q*: BOOL;
//    q_xRetractDO AT %Q*: BOOL;
//    eState : DUT_PneumaticActuator_Position;

    //Readbacks
    {attribute 'pytmc' := '
    pv: IN
    io: i
    '}
    i_bInLS    :    BOOL;
    {attribute 'pytmc' := '
    pv: OUT
    io: i
    '}
    i_bOutLS    :    BOOL;

    //Controls
    {attribute 'pytmc' := '
    pv: INSERT_DO
    io: i
    '}
    q_bRetract    :    BOOL;
    {attribute 'pytmc' := '
    pv: RETRACT_DO
    io: i
    '}
    q_bInsert    :    BOOL;

    //Logic and supervisory
    {attribute 'pytmc' := '
    pv: ILKOK
    io: i
    '}
    bILK_OK: BOOL;
    {attribute 'pytmc' := '
    pv: INSERT_OK
    io: i
    '}
    bInsertOK    :    BOOL;
    {attribute 'pytmc' := '
    pv: RETRACT_OK
    io: i
    '}
    bRetractOK    :    BOOL;
    {attribute 'pytmc' := '
    pv: IN_CMD
    io: io
    '}

    bInsert_SW        :    BOOL;
    {attribute 'pytmc' := '
    pv: OUT_CMD
    io: io
    '}
    bRetract_SW    :    BOOL;
    {attribute 'pytmc' := '
    pv: ERROR
    io: io
    '}
    bErrorPresent : BOOL;
    {attribute 'pytmc' := '
    pv: POS_STATE
    type: mbbi
    field: ZRST RETRACTED
    field: ONST INSERTED
    field: TWST MOVING
    field: THST INVALID
    io: i
    '}

    eState    :    E_PositionState := INVALID;


END_STRUCT
END_TYPE
Related:

GVLs

Global_Version

{attribute 'TcGenerated'}
// This function has been automatically generated from the project information.
VAR_GLOBAL CONSTANT
    {attribute 'const_non_replaced'}
    {attribute 'linkalways'}
    stLibVersion_kfe_motion : ST_LibVersion := (iMajor := 4, iMinor := 0, iBuild := 1, iRevision := 0, sVersion := '4.0.1');
END_VAR

GVL

{attribute 'qualified_only'}
VAR_GLOBAL
    {attribute 'pytmc' := 'pv: PLC:KFE:MOTION:ARB:01'}
    fbArbiter: FB_Arbiter(1);
    {attribute 'pytmc' := 'pv: PLC:KFE:MOTION:ARB:02'}
    fbArbiter2: FB_Arbiter(2);
    {attribute 'pytmc' := 'pv: PLC:KFE:MOTION:FFO:01'}
    {attribute 'TcLinkTo' := '.q_xFastFaultOut:=TIIB[PMPS_FFO]^Channel 1^Output'}
    fbFastFaultOutput1: FB_HardwareFFOutput := (bAutoReset := TRUE, i_sNetID:='172.21.92.73.1.1');
    {attribute 'pytmc' := 'pv: PLC:KFE:MOTION:FFO:02'}
    {attribute 'TcLinkTo' := '.q_xFastFaultOut:=TIIB[PMPS_FFO]^Channel 2^Output'}
    fbFastFaultOutput2: FB_HardwareFFOutput := (bAutoReset := TRUE, i_sNetID:='172.21.92.73.1.1');

    {attribute 'pytmc' := 'pv: PLC:KFE:MOTION:PMPS:ReqTrans'}
    rReqTrans AT %I*                : ARRAY [1..PMPS_GVL.AUX_ATTENUATORS] OF ST_PMPS_Attenuator_IO;
    {attribute 'pytmc' := 'pv: PLC:KFE:MOTION:PMPS:CurTrans'}
    rCurTrans AT %Q*                : ARRAY [1..PMPS_GVL.AUX_ATTENUATORS] OF ST_PMPS_Attenuator_IO;

    ePF1K0State: E_WFS_States;
END_VAR

VAR_GLOBAL CONSTANT
    iFiltersPerSATTBlade : INT := 8;
END_VAR

Main

{attribute 'qualified_only'}
VAR_GLOBAL
(*
    Only includes motor definitions for the IOC
    These are hard-coded to be Main.M#,
    but are very convenient to store in a GVL,
    hence the confusing namespace here

    This should be refactored once the IOC
    supports arbitrary ads paths for motors
*)
    // IM1K0-XTES: 3 Axes
    {attribute 'pytmc' := 'pv: IM1K0:XTES:MMS'}
    {attribute 'TcLinkTo' := '.bLimitForwardEnable  := TIIB[IM1K0-EL7041]^STM Status^Status^Digital input 1;
                              .bBrakeRelease        := TIIB[IM1K0-EL2004]^Channel 1^Output;
                              .nRawEncoderINT       := TIIB[IM1K0-EL3054]^AI Standard Channel 1^Value'}
    M1: ST_MotionStage := (sName := 'IM1K0:XTES:MMS');
    {attribute 'pytmc' := 'pv: IM1K0:XTES:CLZ'}
    {attribute 'TcLinkTo' := '.bHome                := TIIB[IM1K0-EL1088]^Channel 2^Input;
                              .nRawEncoderUINT      := TIIB[IM1K0-EL5101-01]^ENC Status compact^Counter value'}
    M2: ST_MotionStage := (sName := 'IM1K0:XTES:CLZ');
    {attribute 'pytmc' := 'pv: IM1K0:XTES:CLF'}
    {attribute 'TcLinkTo' := '.bHome                := TIIB[IM1K0-EL1088]^Channel 4^Input;
                              .nRawEncoderUINT      := TIIB[IM1K0-EL5101-01]^ENC Status compact^Counter value'}
    M3: ST_MotionStage := (sName := 'IM1K0:XTES:CLF');

    // IM1K3-PPM: 1 Axis
    {attribute 'pytmc' := 'pv: IM1K3:PPM:MMS'}
    {attribute 'TcLinkTo' := '.bLimitForwardEnable  := TIIB[IM1K3-EL7041]^STM Status^Status^Digital input 1;
                              .bLimitBackwardEnable := TIIB[IM1K3-EL7041]^STM Status^Status^Digital input 2;
                              .bBrakeRelease        := TIIB[IM1K3-EL2004]^Channel 1^Output;
                              .nRawEncoderULINT     := TIIB[IM1K3-EL5042]^FB Inputs Channel 1^Position'}
    M4: ST_MotionStage := (sName := 'IM1K3:PPM:MMS');

    // IM2K0-XTES: 1 Axis, previously 3 but the zoom/focus have been removed
    {attribute 'pytmc' := 'pv: IM2K0:XTES:MMS'}
    {attribute 'TcLinkTo' := '.bBrakeRelease        := TIIB[IM2K0-EL2004]^Channel 1^Output;
                              .nRawEncoderULINT     := TIIB[IM2K0-EL5042]^FB Inputs Channel 1^Position'}
    M5: ST_MotionStage := (sName := 'IM2K0:XTES:MMS');
    {attribute 'pytmc' := 'pv: IM2K0:XTES:CLZ'}
    {attribute 'TcLinkTo' := '.bHome                := TIIB[IM2K0-EL1088]^Channel 2^Input;
                              .nRawEncoderUINT      := TIIB[IM2K0-EL7342]^ENC Status compact Channel 1^Counter value'}
    M6: ST_MotionStage := (sName := 'IM2K0:XTES:CLZ');
    {attribute 'pytmc' := 'pv: IM2K0:XTES:CLF'}
    {attribute 'TcLinkTo' := '.bHome                := TIIB[IM2K0-EL1088]^Channel 4^Input;
                              .nRawEncoderUINT      := TIIB[IM2K0-EL7342]^ENC Status compact Channel 2^Counter value'}
    M7: ST_MotionStage := (sName := 'IM2K0:XTES:CLF');

    // PF1K0-WFS: 2 Axes
    {attribute 'pytmc' := 'pv: PF1K0:WFS:MMS:Y'}
    {attribute 'TcLinkTo' := '.bLimitForwardEnable  := TIIB[PF1K0-EL7041-01]^STM Status^Status^Digital input 1;
                              .bLimitBackwardEnable := TIIB[PF1K0-EL7041-01]^STM Status^Status^Digital input 2;
                              .bBrakeRelease        := TIIB[PF1K0-EL2004]^Channel 1^Output;
                              .nRawEncoderULINT     := TIIB[PF1K0-EL5042]^FB Inputs Channel 2^Position'}
    M8: ST_MotionStage := (sName := 'PF1K0:WFS:MMS:Y');
    {attribute 'pytmc' := 'pv: PF1K0:WFS:MMS:Z'}
    {attribute 'TcLinkTo' := '.nRawEncoderULINT     := TIIB[PF1K0-EL5042]^FB Inputs Channel 1^Position'}
    M9: ST_MotionStage := (sName := 'PF1K0:WFS:MMS:Z');

   // RTDSK0: 8 Axes
    M10: ST_MotionStage;
    {attribute 'pytmc' := 'pv: RTDSK0:SCRP:MMS:Z'}
    {attribute 'TcLinkTo' := '.bLimitForwardEnable  := TIIB[RTDSK0-M2-EL7041]^STM Status^Status^Digital input 1;
                              .bLimitBackwardEnable := TIIB[RTDSK0-M2-EL7041]^STM Status^Status^Digital input 2'}
    M11: ST_MotionStage:= (sName := 'RTDSK0:SCRP:MMS:Z');
        {attribute 'pytmc' := 'pv: RTDSK0:SCRP:MMS:X'}
    {attribute 'TcLinkTo' := '.bLimitForwardEnable  := TIIB[RTDSK0-M3-EL7041]^STM Status^Status^Digital input 1;
                              .bLimitBackwardEnable := TIIB[RTDSK0-M3-EL7041]^STM Status^Status^Digital input 2'}
    M12: ST_MotionStage:= (sName := 'RTDSK0:SCRP:MMS:X');
        {attribute 'pytmc' := 'pv: RTDSK0:SCRP:MMS:Y'}
    {attribute 'TcLinkTo' := '.bLimitForwardEnable  := TIIB[RTDSK0-M4-EL7041]^STM Status^Status^Digital input 1;
                              .bLimitBackwardEnable := TIIB[RTDSK0-M4-EL7041]^STM Status^Status^Digital input 2'}
    M13: ST_MotionStage:= (sName := 'RTDSK0:SCRP:MMS:Y');
    M14: ST_MotionStage;
    M15: ST_MotionStage;
    M16: ST_MotionStage;
    M17: ST_MotionStage;

    // SL1K0-POWER: 4 Axes
    {attribute 'pytmc' := 'pv: SL1K0:POWER:MMS:SOUTH'}
    {attribute 'TcLinkTo' := '.bLimitForwardEnable  := TIIB[SL1K0-EL7041-E1]^STM Status^Status^Digital input 2;
                              .bLimitBackwardEnable := TIIB[SL1K0-EL7041-E1]^STM Status^Status^Digital input 1;
                              .nRawEncoderINT       := TIIB[SL1K0-EL3054-E12]^AI Standard Channel 1^Value'}

    M18: ST_MotionStage := (sName := 'SL1K0:POWER:MMS:SOUTH');
    {attribute 'pytmc' := 'pv: SL1K0:POWER:MMS:TOP'}
    {attribute 'TcLinkTo' := '.bLimitForwardEnable  := TIIB[SL1K0-EL7041-E2]^STM Status^Status^Digital input 2;
                              .bLimitBackwardEnable := TIIB[SL1K0-EL7041-E2]^STM Status^Status^Digital input 1;
                              .nRawEncoderINT       := TIIB[SL1K0-EL3054-E12]^AI Standard Channel 2^Value'}
    M19: ST_MotionStage := (sName := 'SL1K0:POWER:MMS:TOP');
    {attribute 'pytmc' := 'pv: SL1K0:POWER:MMS:NORTH'}
    {attribute 'TcLinkTo' := '.bLimitForwardEnable  := TIIB[SL1K0-EL7041-E4]^STM Status^Status^Digital input 2;
                              .bLimitBackwardEnable := TIIB[SL1K0-EL7041-E4]^STM Status^Status^Digital input 1;
                              .nRawEncoderINT       := TIIB[SL1K0-EL3054-E12]^AI Standard Channel 3^Value'}
    M20: ST_MotionStage := (sName := 'SL1K0:POWER:MMS:NORTH');
    {attribute 'pytmc' := 'pv: SL1K0:POWER:MMS:BOTTOM'}
    {attribute 'TcLinkTo' := '.bLimitForwardEnable  := TIIB[SL1K0-EL7041-E5]^STM Status^Status^Digital input 2;
                              .bLimitBackwardEnable := TIIB[SL1K0-EL7041-E5]^STM Status^Status^Digital input 1;
                              .nRawEncoderINT       := TIIB[SL1K0-EL3054-E12]^AI Standard Channel 4^Value'}
    M21: ST_MotionStage := (sName := 'SL1K0:POWER:MMS:BOTTOM');

    // SL2K0-POWER: 4 Axes
    {attribute 'pytmc' := 'pv: SL2K0:POWER:MMS:SOUTH'}
    {attribute 'TcLinkTo' := '.bLimitForwardEnable  := TIIB[SL2K0-EL7041-E1]^STM Status^Status^Digital input 2;
                              .bLimitBackwardEnable := TIIB[SL2K0-EL7041-E1]^STM Status^Status^Digital input 1;
                              .nRawEncoderUINT      := TIIB[SL2K0-EL5042-E2]^FB Inputs Channel 1^Position'}
    M22: ST_MotionStage := (sName := 'SL2K0:POWER:MMS:SOUTH');
    {attribute 'pytmc' := 'pv: SL2K0:POWER:MMS:TOP'}
    {attribute 'TcLinkTo' := '.bLimitForwardEnable  := TIIB[SL2K0-EL7041-E3]^STM Status^Status^Digital input 2;
                              .bLimitBackwardEnable := TIIB[SL2K0-EL7041-E3]^STM Status^Status^Digital input 1;
                              .nRawEncoderUINT      := TIIB[SL2K0-EL5042-E2]^FB Inputs Channel 2^Position'}
    M23: ST_MotionStage := (sName := 'SL2K0:POWER:MMS:TOP');
    {attribute 'pytmc' := 'pv: SL2K0:POWER:MMS:NORTH'}
    {attribute 'TcLinkTo' := '.bLimitForwardEnable  := TIIB[SL2K0-EL7041-E5]^STM Status^Status^Digital input 2;
                              .bLimitBackwardEnable := TIIB[SL2K0-EL7041-E5]^STM Status^Status^Digital input 1;
                              .nRawEncoderUINT      := TIIB[SL2K0-EL5042-E6]^FB Inputs Channel 1^Position'}
    M24: ST_MotionStage := (sName := 'SL2K0:POWER:MMS:NORTH');
    {attribute 'pytmc' := 'pv: SL2K0:POWER:MMS:BOTTOM'}
    {attribute 'TcLinkTo' := '.bLimitForwardEnable  := TIIB[SL2K0-EL7041-E7]^STM Status^Status^Digital input 2;
                              .bLimitBackwardEnable := TIIB[SL2K0-EL7041-E7]^STM Status^Status^Digital input 1;
                              .nRawEncoderUINT      := TIIB[SL2K0-EL5042-E6]^FB Inputs Channel 2^Position'}
    M25: ST_MotionStage := (sName := 'SL2K0:POWER:MMS:BOTTOM');

    // AT1K4-SOLID: 4 axes (Z=748)
    (* Important note

        AT1K4 axes were mistakenly wired opposite to other solid attenuators.
        The intended convention is:
            MMS:01 should be the most upstream blade,
            MMS:04 should be the most downstream blade.

        The fix applied here is that the NC axes and temperature sensors are *linked* in reverse.
        In summary:

        Traveler    EPICS   Stage           NC      Location
        Axis 4              MMS:01  fbStage1        26      Upstream
        Axis 3              MMS:02  fbStage2        27
        Axis 2              MMS:03  fbStage3        28
        Axis 1              MMS:04  fbStage4        29      Downstream

    *)
    {attribute 'pytmc' := 'pv: AT1K4:L2SI:MMS:01'}
    {attribute 'TcLinkTo' := '
        .bLimitForwardEnable  := TIIB[AT1K4-EL7047-04]^STM Status^Status^Digital input 1;
        .bLimitBackwardEnable := TIIB[AT1K4-EL7047-04]^STM Status^Status^Digital input 2;
        .nRawEncoderULINT     := TIIB[AT1K4-EL5042-02]^FB Inputs Channel 2^Position;
    '}
    M26: ST_MotionStage := (sName := 'AT1K4:L2SI:MMS:01');

    {attribute 'pytmc' := 'pv: AT1K4:L2SI:MMS:02'}
    {attribute 'TcLinkTo' := '
        .bLimitForwardEnable  := TIIB[AT1K4-EL7047-03]^STM Status^Status^Digital input 1;
        .bLimitBackwardEnable := TIIB[AT1K4-EL7047-03]^STM Status^Status^Digital input 2;
        .nRawEncoderULINT     := TIIB[AT1K4-EL5042-02]^FB Inputs Channel 1^Position;
    '}
    M27: ST_MotionStage := (sName := 'AT1K4:L2SI:MMS:02');

    {attribute 'pytmc' := 'pv: AT1K4:L2SI:MMS:03'}
    {attribute 'TcLinkTo' := '
        .bLimitForwardEnable  := TIIB[AT1K4-EL7047-02]^STM Status^Status^Digital input 1;
        .bLimitBackwardEnable := TIIB[AT1K4-EL7047-02]^STM Status^Status^Digital input 2;
        .nRawEncoderULINT     := TIIB[AT1K4-EL5042-01]^FB Inputs Channel 2^Position;
    '}
    M28: ST_MotionStage := (sName := 'AT1K4:L2SI:MMS:03');

    {attribute 'pytmc' := 'pv: AT1K4:L2SI:MMS:04'}
    {attribute 'TcLinkTo' := '
        .bLimitForwardEnable  := TIIB[AT1K4-EL7047-01]^STM Status^Status^Digital input 1;
        .bLimitBackwardEnable := TIIB[AT1K4-EL7047-01]^STM Status^Status^Digital input 2;
        .nRawEncoderULINT     := TIIB[AT1K4-EL5042-01]^FB Inputs Channel 1^Position;
    '}
    M29: ST_MotionStage := (sName := 'AT1K4:L2SI:MMS:04');

    // IM1K4-XTES: 3 Axes
    {attribute 'pytmc' := 'pv: IM1K4:XTES:MMS'}
    {attribute 'TcLinkTo' := '.bLimitForwardEnable  := TIIB[IM1K4-EL7041-E1]^STM Status^Status^Digital input 1;
                              .bBrakeRelease        := TIIB[IM1K4-EL2004-E2]^Channel 1^Output;
                              .nRawEncoderULINT     := TIIB[IM1K4-EL5042-E3]^FB Inputs Channel 1^Position'}
    M30: ST_MotionStage := (sName := 'IM1K4:XTES:MMS');
    {attribute 'pytmc' := 'pv: IM1K4:XTES:CLZ'}
    {attribute 'TcLinkTo' := '.bHome                := TIIB[IM1K4-EL1088-E5]^Channel 2^Input;
                              .nRawEncoderUINT     := TIIB[IM1K4-EL7342-E4]^ENC Status compact Channel 1^Counter value'}
    M31: ST_MotionStage := (sName := 'IM1K4:XTES:CLZ');
    {attribute 'pytmc' := 'pv: IM1K4:XTES:CLF'}
    {attribute 'TcLinkTo' := '.bHome := TIIB[IM1K4-EL1088-E5]^Channel 4^Input;
                              .nRawEncoderUINT     := TIIB[IM1K4-EL7342-E4]^ENC Status compact Channel 2^Counter value'}
    M32: ST_MotionStage := (sName := 'IM1K4:XTES:CLF');

    // ST1K4-TEST: 1 Axis
    {attribute 'pytmc' := 'pv: ST1K4:TEST:MMS:01'}
    {attribute 'TcLinkTo' := '.bLimitForwardEnable  := TIIB[ST1K4-EL7041-E4]^STM Status^Status^Digital input 1;
                              .bLimitBackwardEnable := TIIB[ST1K4-EL7041-E4]^STM Status^Status^Digital input 2;
                              .bBrakeRelease        := TIIB[ST1K4-EL2202-E3]^Channel 1^Output;
                              .nRawEncoderULINT      := TIIB[ST1K4-EL5042-E5A]^FB Inputs Channel 1^Position'}
    M33: ST_MotionStage := (sName := 'ST1K4:TEST:MMS:01');
END_VAR
Related:

POUs

FB_MPA

FUNCTION_BLOCK FB_MPA
VAR_INPUT
    (*EPS Interlock Bits*)
    ibInsertOK: BOOL;
    ibRetractOK: BOOL;
    ibPMPS_OK:BOOL;
    ibOverrideInterlock:BOOL; (*if true interlocks are ignored*)
    // Reset fault
    {attribute 'pytmc' := '
    pv: FF_Reset
    '}
    i_xReset: BOOL;
    sName: STRING;
END_VAR
VAR_OUTPUT
    {attribute 'pytmc' := '
    pv:
    '}
    q_stAct     :    ST_MPA;
    {attribute 'pytmc' := '
    pv: MPS_FAULT
    '}
    xMPS_OK:BOOL;
    {attribute 'pytmc' := '
    pv: MOT_DONE
    '}
    xDone:Bool; // Motion is Done
END_VAR
VAR_IN_OUT
    io_fbFFHWO    :    FB_HardwareFFOutput;
END_VAR
VAR
    // PMPS
    fbFF    :    FB_FastFault :=(
        i_xAutoReset := TRUE,
        i_Desc := 'Device is moving',
        i_TypeCode := 16#1010);

    (*Init*)
    xFirstPass    :    BOOL;
    fbFSInit        :    R_TRIG;

    (* Timeouts*)
    tTimeOutDuration: TIME:= T#5S;
    tInserttimeout: TON;
    tRetracttimeout:TON;

    (*IO*)
    i_xInsertedLS    AT%I*: BOOL;
    i_xRetractedLS    AT%I*: BOOL;
    q_xInsert_DO    AT%Q*: BOOL;
    q_xRetract_DO    AT%Q*: BOOL;

    (* Reset Triggers *)
    rtInsert: R_TRIG;
    rtRemove: R_TRIG;
END_VAR
(*Initialize*)
fbFSInit( CLK := TRUE, Q => xFirstPass);
(*IO Mapping*)
ACT_IO();

IF xFirstPass THEN
    q_stAct.eState := INVALID;
    q_stAct.bRetract_SW := FALSE;
    q_stAct.bInsert_SW := FALSE;
END_IF


(* Manage States*)
IF q_stAct.i_bInLS AND  q_stAct.i_bOutLS THEN
    q_stAct.eState:=INVALID;
ELSIF NOT q_stAct.i_bInLS AND q_stAct.i_bOutLS THEN
    q_stAct.eState:=RETRACTED;
ELSIF q_stAct.i_bInLS AND NOT q_stAct.i_bOutLS THEN
    q_stAct.eState:=INSERTED;
ELSIF NOT q_stAct.i_bInLS AND NOT q_stAct.i_bOutLS THEN
    q_stAct.eState:=MOVING;
ELSE
    q_stAct.eState:=INVALID;
END_IF

(*Set the Done signal*)
xDone := (q_stAct.bRetract_SW AND q_stAct.eState=RETRACTED) OR (q_stAct.eState=INSERTED AND q_stAct.bInsert_SW);


(*MPS FAULT*)
(**)
xMPS_OK := (q_stAct.bRetract_SW AND i_xRetractedLS) XOR (i_xInsertedLS AND q_stAct.bInsert_SW);
//xMPS_OK := i_xRetractedLS XOR i_xInsertedLS;
//xMPS_OK := (q_stAct.eState=RETRACTED) OR (q_stAct.eState=INSERTED);
//xMPS_OK := (q_stAct.eState=RETRACTED) ;

(*PMPS PERMISSION*)

(* Reset the other command bit when one goes high *)
rtInsert(CLK:=q_stAct.bInsert_SW);
IF rtInsert.Q THEN
    q_stAct.bRetract_SW := FALSE;
END_IF
rtRemove(CLK:=q_stAct.bRetract_SW);
IF rtRemove.Q THEN
    q_stAct.bInsert_SW := FALSE;
END_IF

(* Can't have bRetract_SW and  bInsert_SW both be true*)
If (q_stAct.bRetract_SW) and (q_stAct.bInsert_SW) THEN
    q_stAct.bRetract_SW := FALSE;
    q_stAct.bInsert_SW := FALSE;
END_IF

(* Make the state consistent if we can *)
IF NOT (q_stAct.bRetract_SW OR q_stAct.bInsert_SW) THEN
    IF q_stAct.eState = RETRACTED THEN
        q_stAct.bRetract_SW := TRUE;
    ELSIF q_stAct.eState = INSERTED THEN
        q_stAct.bInsert_SW := TRUE;
    END_IF
END_IF

q_stAct.bRetractOK := ibRetractOK;
q_stAct.bInsertOK := ibInsertOK;

(*Actuate the device*)
q_stAct.q_bRetract := q_stAct.bRetractOK AND q_stAct.bRetract_SW;
q_stAct.q_bInsert := q_stAct.bInsertOK AND q_stAct.bInsert_SW;

IF q_stAct.q_bInsert THEN
    q_stAct.q_bRetract := FALSE;
    q_stAct.bRetract_SW:= FALSE;
ELSIF q_stAct.q_bRetract THEN
    q_stAct.q_bInsert := FALSE;
    q_stAct.bInsert_SW:= FALSE;
END_IF;




(*Timers*)
tInserttimeout(IN:= q_stAct.q_bInsert, PT := tTimeOutDuration );
tRetracttimeout(IN:= q_stAct.q_bRetract, PT := tTimeOutDuration);

///Check moving postion timout
IF NOT q_stAct.i_bInLS AND tInserttimeout.Q THEN
    q_stAct.bErrorPresent := TRUE;
ELSIF NOT q_stAct.i_bOutLS AND tRetracttimeout.Q THEN
    q_stAct.bErrorPresent := TRUE;
END_IF

(*FAST FAULT*)
fbFF(i_DevName := sName,
    i_xOK := xMPS_OK,
    i_xReset := i_xReset,
    io_fbFFHWO := io_fbFFHWO);

(*Soft IO Mapping*)
ACT_IO();

END_FUNCTION_BLOCK

ACTION ACT_IO:
(*Inputs*)
q_stAct.i_bInLS :=  i_xInsertedLS;
q_stAct.i_bOutLS := i_xRetractedLS;

(*outputs*)
q_xInsert_DO:=q_stAct.q_bInsert;
q_xRetract_DO:=q_stAct.q_bRetract;
END_ACTION
Related:

FB_SLITS

FUNCTION_BLOCK FB_SLITS
VAR_IN_OUT
    stTopBlade: ST_MotionStage;
    stBottomBlade: ST_MotionStage;
    stNorthBlade: ST_MotionStage;
    stSouthBlade: ST_MotionStage;
    bExecuteMotion:BOOL ;
    io_fbFFHWO    :    FB_HardwareFFOutput;
    fbArbiter: FB_Arbiter();
END_VAR

VAR_INPUT

    {attribute 'pytmc' := '
    pv: PMPS_OK;
    io: i;
    field: ZNAM False
    field: ONAM True
    '}
    bMoveOk:BOOL;

        (*Offsets*)
    {attribute 'pytmc' := '
    pv: Offset_Top;
    io: io;
    '}
    rEncoderOffsetTop: REAL;
    {attribute 'pytmc' := '
    pv: ZeroOffset_Bottom;
    io: io;
    '}
    rEncoderOffsetBottom: REAL;
    {attribute 'pytmc' := '
    pv: ZeroOffset_North;
    io: io;
    '}
    rEncoderOffsetNorth: REAL;
    {attribute 'pytmc' := '
    pv: ZeroOffset_South;
    io: io;
    '}
    rEncoderOffsetSouth: REAL;
    i_DevName : STRING; //device name for FFO and PMPS diagnostics
END_VAR

VAR
    fbTopBlade: FB_MotionStage;
    fbBottomBlade: FB_MotionStage;
    fbNorthBlade: FB_MotionStage;
    fbSouthBlade: FB_MotionStage;
    fPosTopBlade: LREAL;
    fPosBottomBlade: LREAL;
    fPosNorthBlade: LREAL;
    fPosSouthBlade: LREAL;

    (*Motion Parameters*)
    fSmallDelta: LREAL := 0.01;
    fBigDelta: LREAL := 10;
    fMaxVelocity: LREAL := 0.2;
    fHighAccel: LREAL := 0.8;
    fLowAccel: LREAL := 0.1;

    stTop: DUT_PositionState;
    stBOTTOM: DUT_PositionState;
    stNorth: DUT_PositionState;
    stSouth: DUT_PositionState;

    {attribute 'pytmc' := 'pv: TOP'}
    fbTop: FB_StatePTPMove;
    {attribute 'pytmc' := 'pv: BOTTOM'}
    fbBottom: FB_StatePTPMove;
    {attribute 'pytmc' := 'pv: NORTH'}
    fbNorth: FB_StatePTPMove;
    {attribute 'pytmc' := 'pv: SOUTH'}
    fbSouth: FB_StatePTPMove;

    (*EPICS pvs*)
    {attribute 'pytmc' := '
    pv: XWID_REQ;
    io: io;
    '}
    rReqApertureSizeX : REAL;
    {attribute 'pytmc' := '
    pv: YWID_REQ;
    io: io;
    '}
    rReqApertureSizeY : REAL;
    {attribute 'pytmc' := '
    pv: XCEN_REQ;
    io: io;
    '}
    rReqCenterX: REAL;
    {attribute 'pytmc' := '
    pv: YCEN_REQ;
    io: io;
    '}
    rReqCenterY: REAL;

    {attribute 'pytmc' := '
    pv: ACTUAL_XWIDTH;
    io: io;
    '}
    rActApertureSizeX : REAL;

    {attribute 'pytmc' := '
    pv: ACTUAL_YWIDTH;
    io: io;
    '}
    rActApertureSizeY : REAL;
    {attribute 'pytmc' := '
    pv: ACTUAL_XCENTER;
    io: io;
    '}
    rActCenterX: REAL;
    {attribute 'pytmc' := '
    pv: ACTUAL_YCENTER;
    io: io;
    '}
    rActCenterY: REAL;

    {attribute 'pytmc' := '
    pv: XCEN_SETZERO;
    io: io;
    '}
    rSetCenterX: BOOL;
    {attribute 'pytmc' := '
    pv: YCEN_SETZERO;
    io: io;
    '}
    rSetCenterY: BOOL;


    {attribute 'pytmc' := '
    pv: OPEN;
    io: io;
    field: ZNAM False
    field: ONAM True
    '}
    bOpen: BOOL;

    {attribute 'pytmc' := '
    pv: CLOSE;
    io: io;
    field: ZNAM False
    field: ONAM True
    '}
    bClose: BOOL;

    {attribute 'pytmc' := '
    pv: BLOCK;
    io: io;
    field: ZNAM False
    field: ONAM True
    '}
    bBlock: BOOL;



        //Local variables
    bInit: BOOL :=true;
    rTrig_Block: R_TRIG;
    rTrig_Open: R_TRIG;
    rTrig_Close: R_TRIG;

    //old values
    rOldReqApertureSizeX : REAL;
    rOldReqApertureSizeY : REAL;
    rOldReqCenterX: REAL;
    rOldReqCenterY: REAL;

    bExecuteMotionX: BOOL;
    bExecuteMotionY: BOOL;


    fPosBlock: LREAL;
    fPosClose: LREAL;
    fPosOpen: LREAL;

    stSetPositionOptions:ST_SetPositionOptions;
    fbSetPosition_TOP: MC_SetPosition;
    fbSetPosition_Bottom: MC_SetPosition;
    fbSetPosition_North: MC_SetPosition;
    fbSetPosition_South: MC_SetPosition;

    // For logging
    fbLogger : FB_LogMessage := (eSubsystem:=E_SubSystem.MOTION);
    tErrorPresent : R_TRIG;
    tAction : R_TRIG;
    tOverrideActivated : R_TRIG;

    FFO    :    FB_FastFault :=(
        i_DevName := 'Slits',
        i_Desc := 'Fault occurs when gaps and/or centers are not within safe margins, or PMPS mode is switched OFF',
        i_TypeCode := 16#FAA);

    AptArrayStatus AT %Q* : ST_PMPS_Aperture_IO;
    AptArrayReq AT %I* : ST_PMPS_Aperture_IO;

    bTest: BOOL;

END_VAR


END_FUNCTION_BLOCK

ACTION ACT_BLOCK:
rTrig_Block (CLK:= bBlock);
rTrig_Open (CLK:= bOpen);
rTrig_Close (CLK:= bClose);

if (rTrig_Block.Q) THEN
    //BLOCK

    bBlock := false;
END_IF

if (rTrig_Open.Q) THEN


    bOpen := false;
END_IF

if (rTrig_Close.Q) THEN


    bClose := false;
END_IF
END_ACTION

ACTION ACT_CalculatePositions:
//check if requested center or gap has changed
//check that the requested values are within acceptable motion range
IF (rOldReqApertureSizeX <> rReqApertureSizeX) THEN
    IF (rReqApertureSizeX <= AptArrayReq.Width)  THEN
        rOldReqApertureSizeX := rReqApertureSizeX;
        bExecuteMotionX := TRUE;
        fbLogger(sMsg:='Requested new X gap.', eSevr:=TcEventSeverity.Verbose);
    ELSE
        fbLogger(sMsg:='Requested new X gap is larger than PMPS request.', eSevr:=TcEventSeverity.Verbose);
    END_IF
  //  ELSE
    //    rReqApertureSizeX := rActApertureSizeX;
END_IF

IF (rOldReqCenterX <> rReqCenterX) THEN
    rOldReqCenterX := rReqCenterX;
    bExecuteMotionX := TRUE;
    fbLogger(sMsg:='Requested new X center', eSevr:=TcEventSeverity.Verbose);
   // ELSE
      //  rReqCenterX := rActCenterX;
END_IF

IF (rOldReqApertureSizeY <> rReqApertureSizeY) THEN
    IF rReqApertureSizeY <= AptArrayReq.Height THEN
        rOldReqApertureSizeY := rReqApertureSizeY;
        bExecuteMotionY := TRUE;
        fbLogger(sMsg:='Requested new Y gap.', eSevr:=TcEventSeverity.Verbose);
    ELSE
        fbLogger(sMsg:='Requested new Y gap is larger than PMPS request.', eSevr:=TcEventSeverity.Verbose);
    END_IF
   // ELSE
       // rReqApertureSizeY := rActApertureSizeY;
END_IF

IF (rOldReqCenterY <> rReqCenterY) THEN
    rOldReqCenterY := rReqCenterY;
    bExecuteMotionY := TRUE;
    fbLogger(sMsg:='Requested new Y center.', eSevr:=TcEventSeverity.Verbose);
   // ELSE
      //  rReqCenterY := rActCenterY;
END_IF


//Calculate requested target positions from requested gap and center
fPosTopBlade := (rReqApertureSizeY/2) + (rReqCenterY + rEncoderOffsetTop) ;
fPosBottomBlade := (-1*rReqApertureSizeY/2) + (rReqCenterY+rEncoderOffsetBottom);

fPosNorthBlade := (rReqApertureSizeX/2) + (rReqCenterX + rEncoderOffsetNorth);
fPosSouthBlade := (-1*rReqApertureSizeX/2) + (rReqCenterX + rEncoderOffsetSouth);


//Calculate actual gap and center from actual stages positions
rActApertureSizeX := LREAL_TO_REAL((stNorthBlade.stAxisStatus.fActPosition - rEncoderOffsetNorth) - (stSouthBlade.stAxisStatus.fActPosition- rEncoderOffsetSouth));

rActApertureSizeY := LREAL_TO_REAL((stTopBlade.stAxisStatus.fActPosition - rEncoderOffsetTop) - (stBottomBlade.stAxisStatus.fActPosition - rEncoderOffsetBottom));

rActCenterX := LREAL_TO_REAL((((stNorthBlade.stAxisStatus.fActPosition - rEncoderOffsetNorth)  + (stSouthBlade.stAxisStatus.fActPosition - rEncoderOffsetSouth ))/2));

rActCenterY := LREAL_TO_REAL((((stTopBlade.stAxisStatus.fActPosition - rEncoderOffsetTop) + (stBottomBlade.stAxisStatus.fActPosition - rEncoderOffsetBottom))/2));



//Update PMPS Arbiter with the Actual Size and Center of the Aperture
END_ACTION

ACTION ACT_Home:

END_ACTION

ACTION ACT_Init:
//  init the motion stages parameters
IF ( bInit) THEN
    stTopBlade.bHardwareEnable := TRUE;
    stBottomBlade.bHardwareEnable := TRUE;
    stNorthBlade.bHardwareEnable := TRUE;
    stSouthBlade.bHardwareEnable := TRUE;
    stTopBlade.bPowerSelf :=TRUE;
    stBottomBlade.bPowerSelf :=TRUE;
    stNorthBlade.bPowerSelf :=TRUE;
    stSouthBlade.bPowerSelf :=TRUE;
    stTopBlade.nBrakeMode := ENUM_StageBrakeMode.NO_BRAKE;
    stBottomBlade.nBrakeMode := ENUM_StageBrakeMode.NO_BRAKE;
    stNorthBlade.nBrakeMode := ENUM_StageBrakeMode.NO_BRAKE;
    stSouthBlade.nBrakeMode := ENUM_StageBrakeMode.NO_BRAKE;
    FFO.i_DevName := i_DevName;
END_IF
END_ACTION

ACTION ACT_Motion:
// Instantiate Function block for all the blades
fbTopBlade(stMotionStage:=stTopBlade);
fbBottomBlade(stMotionStage:=stBottomBlade);
fbNorthBlade(stMotionStage:=stNorthBlade);
fbSouthBlade(stMotionStage:=stSouthBlade);

// PTP Motion for each blade
stTop.sName := 'Top';
stTop.fPosition := fPosTopBlade;
stTop.fDelta := fSmallDelta;
stTop.fVelocity := fMaxVelocity;
stTop.fAccel := fHighAccel;
stTop.fDecel := fHighAccel;

stBOTTOM.sName := 'Bottom';
stBOTTOM.fPosition := fPosBottomBlade;
stBOTTOM.fDelta := fSmallDelta;
stBOTTOM.fVelocity := fMaxVelocity;
stBOTTOM.fAccel := fHighAccel;
stBOTTOM.fDecel := fHighAccel;

stNorth.sName := 'North';
stNorth.fPosition := fPosNorthBlade;
stNorth.fDelta := fSmallDelta;
stNorth.fVelocity := fMaxVelocity;
stNorth.fAccel := fHighAccel;
stNorth.fDecel := fHighAccel;

stSouth.sName := 'South';
stSouth.fPosition := fPosSouthBlade;
stSouth.fDelta := fSmallDelta;
stSouth.fVelocity := fMaxVelocity;
stSouth.fAccel := fHighAccel;
stSouth.fDecel := fHighAccel;

IF (bExecuteMotionY) THEN
    fbTop.bExecute := fbBottom.bExecute := bExecuteMotionY;
    bExecuteMotionY:= FALSE;
END_IF

IF (bExecuteMotionX) THEN
    fbNorth.bExecute := fbSouth.bExecute := bExecuteMotionX;
    bExecuteMotionX:= FALSE;
END_IF


fbTop(
    stPositionState:=stTop,
    bMoveOk:=bMoveOk,
    stMotionStage:=stTopBlade);

fbBottom(
    stPositionState:=stBOTTOM,
    bMoveOk:=bMoveOk,
    stMotionStage:=stBottomBlade);

fbNorth(
    stPositionState:=stNorth,
    bMoveOk:=bMoveOk,
    stMotionStage:=stNorthBlade);

fbSouth(
    stPositionState:=stSouth,
    bMoveOk:=bMoveOk,
    stMotionStage:=stSouthBlade);
END_ACTION

ACTION ACT_Zero:
//ZERO BIAS

// Set Y center to zero

// Set X center to zero
(*
if (rSetCenterY)THEN
        rSetCenterY := false;
        // Set Current Position
        fbSetPosition_TOP.Position :=  stTopBlade.stAxisStatus.fActPosition - rActCenterY ;
        fbSetPosition_TOP.Execute := TRUE;
        fbSetPosition_Bottom.Position := stBottomBlade.stAxisStatus.fActPosition - rActCenterY;
        fbSetPosition_Bottom.Execute := TRUE;
END_IF

if (rSetCenterX)THEN
        rSetCenterX := false;
        // Set Current Position
        fbSetPosition_North.Position := stNorthBlade.stAxisStatus.fActPosition - rActCenterX ;
        fbSetPosition_North.Execute := TRUE;
        fbSetPosition_South.Position := stSouthBlade.stAxisStatus.fActPosition - rActCenterX ; ;
        fbSetPosition_South.Execute := TRUE;
END_IF


//Reset
if (fbSetPosition_TOP.Done ) THEN
    fbSetPosition_TOP.Execute := FALSE;
END_IF
if (fbSetPosition_Bottom.Done ) THEN
    fbSetPosition_Bottom.Execute := FALSE;
END_IF
if (fbSetPosition_North.Done ) THEN
    fbSetPosition_North.Execute := FALSE;
END_IF
if (fbSetPosition_South.Done ) THEN
    fbSetPosition_South.Execute := FALSE;
END_IF

// Set Encoder Position
//Clear position lag error
stSetPositionOptions.ClearPositionLag := TRUE;
fbSetPosition_TOP(
    Axis:=  stTopBlade.Axis ,
    Execute:= ,
    Position:= 0 ,
    Mode:= FALSE,
    Options:= stSetPositionOptions,
    Done=> ,
    Busy=> ,
    Error=> ,
    ErrorID=> );
fbSetPosition_Bottom(
    Axis:= stBottomBlade.Axis ,
    Execute:= ,
    Position:= 0 ,
    Mode:= FALSE,
    Options:= stSetPositionOptions,
    Done=> ,
    Busy=> ,
    Error=> ,
    ErrorID=> );
fbSetPosition_North(
    Axis:= stNorthBlade.Axis ,
    Execute:= ,
    Position:= 0 ,
    Mode:= FALSE,
    Options:= stSetPositionOptions,
    Done=> ,
    Busy=> ,
    Error=> ,
    ErrorID=> );
fbSetPosition_South(
    Axis:= stSouthBlade.Axis ,
    Execute:= ,
    Position:= 0 ,
    Mode:= FALSE,
    Options:= stSetPositionOptions,
    Done=> ,
    Busy=> ,
    Error=> ,
    ErrorID=> );

    *)
END_ACTION

FB_SLITS_POWER

FUNCTION_BLOCK FB_SLITS_POWER EXTENDS FB_SLITS
VAR_INPUT
END_VAR
VAR
    {attribute 'pytmc' := '
    pv: MODE ;
     field: ZNAM Local;
    field: ONAM PMPS;
     io: io;
    '}
    xPMPSMode       :BOOL :=TRUE;


     {attribute 'pytmc' := '
        pv: FSW
    '}
    fbFlowSwitch: FB_XTES_Flowswitch;


    //RTDs
    {attribute 'pytmc' := '
        pv: TOP:RTD:01
    '}
    RTD_TOP_1: FB_TempSensor;
    {attribute 'pytmc' := '
        pv: TOP:RTD:02
    '}
    RTD_TOP_2: FB_TempSensor;
    {attribute 'pytmc' := '
        pv: BOTTOM:RTD:01
    '}
    RTD_Bottom_1: FB_TempSensor;
    {attribute 'pytmc' := '
        pv: BOTTOM:RTD:02
    '}
    RTD_Bottom_2: FB_TempSensor;

    {attribute 'pytmc' := '
        pv: NORTH:RTD:01
    '}
    RTD_North_1: FB_TempSensor;
    {attribute 'pytmc' := '
        pv: NORTH:RTD:02
    '}
    RTD_North_2: FB_TempSensor;
    {attribute 'pytmc' := '
        pv: SOUTH:RTD:01
    '}
    RTD_South_1: FB_TempSensor;
    {attribute 'pytmc' := '
        pv: SOUTH:RTD:02
    '}
    RTD_South_2: FB_TempSensor;


END_VAR
ACT_init();

// Instantiate Function block for all the blades
ACT_Motion();
//SET and GET the requested and Actual values
ACT_CalculatePositions();
//ACT_BLOCK();
ACT_RTDs();

END_FUNCTION_BLOCK

ACTION ACT_RTDs:
////RTDs
RTD_TOP_1();
RTD_TOP_2();
RTD_Bottom_1();
RTD_Bottom_2();
RTD_North_1();
RTD_North_2();
RTD_South_1();
RTD_South_2();

//Flow Switch
fbFlowSwitch();
END_ACTION

METHOD M_UpdatePMPS : BOOL
VAR_INPUT
    index: int;
END_VAR
//Keep updating the status of the apertures PMPS
This^.AptArrayStatus.Height := This^.rActApertureSizeY;
This^.AptArrayStatus.Width := This^.rActApertureSizeX;
This^.AptArrayStatus.xOK := NOT (This^.stTopBlade.bError) AND NOT (This^.stBottomBlade.bError)
                                 AND NOT (This^.stNorthBlade.bError) AND NOT (This^.stNorthBlade.bError);

//Evaluate that the current center on the X and the y direction didn't exceed limits,
// Gap should be reduced when center is moved, gap < Maximum permessible gap - 2|Center deviation from nominal|
//Fast fault when it does.
IF(This^.rActApertureSizeX > (AptArrayReq.Width - (2*ABS(rActCenterX)))
//(rActCenterX > (PMPS_GVL.stCurrentBeamParameters.astApertures[index].Width/2))
    AND (PMPS_GVL.stCurrentBeamParameters.astApertures[index].Width >0 ))
    OR (This^.rActApertureSizeY > (AptArrayReq.Height - (2*ABS(rActCenterY)))
    //((rActCenterY > (PMPS_GVL.stCurrentBeamParameters.astApertures[index].Height/2))
        AND(PMPS_GVL.stCurrentBeamParameters.astApertures[index].Height>0 )) THEN
        FFO.i_xOK := FALSE;
    ELSE
        FFO.i_xOK := TRUE;
END_IF

//Evaluate that the requested gaps on the X and the y direction is not larger than the current gap
// narrow  the gap if the requested is larger
IF(xPMPSMode) THEN
    IF (This^.rActApertureSizeX > AptArrayReq.Width) THEN
        rReqApertureSizeX := AptArrayReq.Width - 0.01;
    END_IF
    IF (This^.rActApertureSizeY > AptArrayReq.Height) THEN
         rReqApertureSizeY := AptArrayReq.Height - 0.01;
    END_IF
    ELSE
     FFO.i_xOK := FALSE;
END_IF


(*FAST FAULT*)
FFO(i_xOK := ,
    i_xReset := ,
    i_xAutoReset :=TRUE,
    io_fbFFHWO := io_fbFFHWO);
END_METHOD
Related:

FB_XPIM_IM2K0

FUNCTION_BLOCK FB_XPIM_IM2K0
(*
    Function block for the IM2K0 imager. This used to be a standard XPIM, but
    IM2K0 has been modified to replace the lens, illuminator, and camera with the PPM versions.

    This function block therefore controls:
    - Y motion (XPIM style)
    - Y scintillator states (XPIM style)
    - camera power (PPM style)
    - camera illuminator (PPM style but with XPIM style on/off only)
    - flowswitch (XPIM style, not fully implemented)
*)
VAR_IN_OUT
    // Y motor (state select).
    stYStage: ST_MotionStage;
    // The fast fault output to fault to.
    fbFFHWO: FB_HardwareFFOutput;
    // The arbiter to request beam conditions from.
    fbArbiter: FB_Arbiter;
END_VAR
VAR_INPUT
    // Settings for the OUT state.
    stOut: DUT_PositionState;
    // Settings for the YAG state.
    stYag: DUT_PositionState;
    // Settings for the DIAMOND state.
    stDiamond: DUT_PositionState;
    // Settings for the RETICLE state.
    stReticle: DUT_PositionState;
    // Set this to a non-unknown value to request a new move.
    {attribute 'pytmc' := '
        pv: MMS:STATE:SET
        io: io
    '}
    eEnumSet: E_XPIM_States;
    // Set this to TRUE to enable input state moves, or FALSE to disable them.
    bEnableMotion: BOOL;
    // Set this to TRUE to enable beam parameter checks, or FALSE to disable them.
    bEnableBeamParams: BOOL;
    // Set this to TRUE to enable position limit checks, or FALSE to disable them.
    bEnablePositionLimits: BOOL;
    // The name of the device for use in the PMPS DB lookup and diagnostic screens.
    sDeviceName: STRING;
    // The name of the transition state in the PMPS database.
    sTransitionKey: STRING;
    // Set this to TRUE to re-read the loaded database immediately (useful for debug).
    bReadDBNow: BOOL;
END_VAR
VAR_OUTPUT
    // The current position state as an enum.
    {attribute 'pytmc' := '
        pv: MMS:STATE:GET
        io: i
    '}
    eEnumGet: E_XPIM_States;
    // The PMPS database lookup associated with the current position state.
    stDbStateParams: ST_DbStateParams;
END_VAR
VAR
    bInit: BOOL;

    fbYStage: FB_MotionStage;

    fbStateDefaults: FB_PositionState_Defaults;

    {attribute 'pytmc' := '
        pv: MMS
        astPositionState.array: 1..4
    '}
    fbStates: FB_PositionStatePMPS1D;
    astPositionState: ARRAY[1..GeneralConstants.MAX_STATES] OF ST_PositionState;
    fbArrCheckWrite: FB_CheckPositionStateWrite;

    {attribute 'pytmc' := '
        pv: CAM
    '}
    fbGige: FB_PPM_Gige;

    {attribute 'pytmc' := '
        pv: CIL
    '}
    fbLED: FB_XPIM_LED;

    {attribute 'pytmc' := '
        pv: SFW
    '}
    fbFlowSwitch: FB_XTES_Flowswitch;
END_VAR
VAR CONSTANT
    // State defaults if not provided
    fDelta: LREAL := 2;
    fAccel: LREAL := 200;
    fOutDecel: LREAL := 25;
END_VAR
IF NOT bInit THEN
    bInit := TRUE;

    stYStage.bHardwareEnable := TRUE;
    stYStage.bPowerSelf := FALSE;
    // No limit switch at the bottom
    stYStage.bLimitBackwardEnable := TRUE;

    // Partial backcompat, this used to set fVelocity too but this should be set per install
    fbStateDefaults(stPositionState:=stOut, sNameDefault:='OUT', fDeltaDefault:=fDelta, fAccelDefault:=fAccel, fDecelDefault:=fOutDecel);
    fbStateDefaults(stPositionState:=stYag, sNameDefault:='YAG', fDeltaDefault:=fDelta, fAccelDefault:=fAccel, fDecelDefault:=fAccel);
    fbStateDefaults(stPositionState:=stDiamond, sNameDefault:='DIAMOND', fDeltaDefault:=fDelta, fAccelDefault:=fAccel, fDecelDefault:=fAccel);
    fbStateDefaults(stPositionState:=stReticle, sNameDefault:='RETICLE', fDeltaDefault:=fDelta, fAccelDefault:=fAccel, fDecelDefault:=fAccel);
END_IF

fbYStage(stMotionStage:=stYStage);

// We need to update from PLC or from EPICS, but not both
fbArrCheckWrite(
    astPositionState:=astPositionState,
    bCheck:=TRUE,
    bSave:=FALSE,
);
IF NOT fbArrCheckWrite.bHadWrite THEN
    astPositionState[E_XPIM_States.OUT] := stOut;
    astPositionState[E_XPIM_States.YAG] := stYag;
    astPositionState[E_XPIM_States.DIAMOND] := stDiamond;
    astPositionState[E_XPIM_States.RETICLE] := stReticle;
END_IF

fbStates(
    stMotionStage:=stYStage,
    astPositionState:=astPositionState,
    eEnumSet:=eEnumSet,
    eEnumGet:=eEnumGet,
    fbFFHWO:=fbFFHWO,
    fbArbiter:=fbArbiter,
    bEnableMotion:=bEnableMotion,
    bEnableBeamParams:=bEnableBeamParams,
    bEnablePositionLimits:=bEnablePositionLimits,
    sDeviceName:=sDeviceName,
    sTransitionKey:=sTransitionKey,
    bReadDBNow:=bReadDBNow,
    stDbStateParams=>stDbStateParams,
);

fbArrCheckWrite(
    astPositionState:=astPositionState,
    bCheck:=FALSE,
    bSave:=TRUE,
);

stOut := astPositionState[E_XPIM_States.OUT];
stYag := astPositionState[E_XPIM_States.YAG];
stDiamond := astPositionState[E_XPIM_States.DIAMOND];
stReticle := astPositionState[E_XPIM_States.RETICLE];

fbGige();
fbLED(enumXPIM:=eEnumGet);
fbFlowSwitch();

END_FUNCTION_BLOCK

PRG_1_PlcTask

PROGRAM PRG_1_PlcTask
VAR
END_VAR
PRG_2_PMPS_PRE();

PRG_IM1K0_XTES();
PRG_IM1K3_PPM();
PRG_IM2K0_XTES();
PRG_PF1K0_WFS();
PRG_RTDSK0();
PRG_SL1K0_POWER();
PRG_SL2K0_POWER();

PRG_AT1K4_SOLID();
PRG_IM1K4_XTES();
PRG_ST1K4_TEST();

PRG_3_PMPS_POST();
PRG_4_LOG();

END_PROGRAM
Related:

PRG_2_PMPS_PRE

PROGRAM PRG_2_PMPS_PRE
VAR
END_VAR
MOTION_GVL.fbStandardPMPSDB(
    io_fbFFHWO:=GVL.fbFastFaultOutput1,
    bEnable:=TRUE,
    sPLCName:='plc-kfe-motion',
);

END_PROGRAM
Related:

PRG_3_PMPS_POST

PROGRAM PRG_3_PMPS_POST
VAR
    fbArbiterIO: FB_SubSysToArbiter_IO;
    fb_vetoArbiter: FB_VetoArbiter;
    bM1K1_Veto_IN: BOOL;

END_VAR
// create MR1K1 as veto for K4 lines
bM1K1_Veto_IN := NOT PMPS_GVL.stCurrentBeamParameters.aVetoDevices[PMPS.K_Stopper.MR1K1_OUT]
                AND PMPS_GVL.stCurrentBeamParameters.aVetoDevices[PMPS.K_Stopper.MR1K1_IN];




//create a preemptive request from Arbiter 2 in Arbiter 1
fb_vetoArbiter(bVeto:=bM1K1_Veto_IN,
                HigherAuthority := GVL.fbArbiter,
                LowerAuthority := GVL.fbArbiter2,
                FFO := GVL.fbFastFaultOutput2);



GVL.fbFastFaultOutput1.Execute();

GVL.fbFastFaultOutput2.Execute(i_xVeto:=bM1K1_Veto_IN);
fbArbiterIO(
    Arbiter:=GVL.fbArbiter,
    fbFFHWO:=GVL.fbFastFaultOutput1);

END_PROGRAM
Related:

PRG_4_LOG

PROGRAM PRG_4_LOG
VAR
    fbLogHandler: FB_LogHandler;
END_VAR
fbLogHandler();

END_PROGRAM

PRG_AT1K4_SOLID

PROGRAM PRG_AT1K4_SOLID
VAR
    (* TODO: use FALSE for simulation and production *)
    (* TODO: use TRUE when relying on visualization + actual hardware *)
    bDebug : BOOL := FALSE;

    nEnableMode : ENUM_StageEnableMode;

    {attribute 'pytmc' := 'pv: AT1K4:L2SI:MMS:01'}
    {attribute 'TcLinkTo' := '

        .fbRTD_1.iRaw := TIIB[AT1K4-EL3202-04]^RTD Inputs Channel 1^Value;
        .fbRTD_1.bError := TIIB[AT1K4-EL3202-04]^RTD Inputs Channel 1^Status^Error;
        .fbRTD_1.bUnderrange := TIIB[AT1K4-EL3202-04]^RTD Inputs Channel 1^Status^Underrange;
        .fbRTD_1.bOverrange := TIIB[AT1K4-EL3202-04]^RTD Inputs Channel 1^Status^Overrange;

        .fbRTD_2.iRaw := TIIB[AT1K4-EL3202-04]^RTD Inputs Channel 2^Value;
        .fbRTD_2.bError := TIIB[AT1K4-EL3202-04]^RTD Inputs Channel 2^Status^Error;
        .fbRTD_2.bUnderrange := TIIB[AT1K4-EL3202-04]^RTD Inputs Channel 2^Status^Underrange;
        .fbRTD_2.bOverrange := TIIB[AT1K4-EL3202-04]^RTD Inputs Channel 2^Status^Overrange;

    '}
    fbStage1: FB_SXR_SATT_Stage;

    {attribute 'pytmc' := 'pv: AT1K4:L2SI:MMS:02'}
    {attribute 'TcLinkTo' := '

        .fbRTD_1.iRaw := TIIB[AT1K4-EL3202-03]^RTD Inputs Channel 1^Value;
        .fbRTD_1.bError := TIIB[AT1K4-EL3202-03]^RTD Inputs Channel 1^Status^Error;
        .fbRTD_1.bUnderrange := TIIB[AT1K4-EL3202-03]^RTD Inputs Channel 1^Status^Underrange;
        .fbRTD_1.bOverrange := TIIB[AT1K4-EL3202-03]^RTD Inputs Channel 1^Status^Overrange;

        .fbRTD_2.iRaw := TIIB[AT1K4-EL3202-03]^RTD Inputs Channel 2^Value;
        .fbRTD_2.bError := TIIB[AT1K4-EL3202-03]^RTD Inputs Channel 2^Status^Error;
        .fbRTD_2.bUnderrange := TIIB[AT1K4-EL3202-03]^RTD Inputs Channel 2^Status^Underrange;
        .fbRTD_2.bOverrange := TIIB[AT1K4-EL3202-03]^RTD Inputs Channel 2^Status^Overrange;

    '}
    fbStage2: FB_SXR_SATT_Stage;

    {attribute 'pytmc' := 'pv: AT1K4:L2SI:MMS:03'}
    {attribute 'TcLinkTo' := '

        .fbRTD_1.iRaw := TIIB[AT1K4-EL3202-02]^RTD Inputs Channel 1^Value;
        .fbRTD_1.bError := TIIB[AT1K4-EL3202-02]^RTD Inputs Channel 1^Status^Error;
        .fbRTD_1.bUnderrange := TIIB[AT1K4-EL3202-02]^RTD Inputs Channel 1^Status^Underrange;
        .fbRTD_1.bOverrange := TIIB[AT1K4-EL3202-02]^RTD Inputs Channel 1^Status^Overrange;

        .fbRTD_2.iRaw := TIIB[AT1K4-EL3202-02]^RTD Inputs Channel 2^Value;
        .fbRTD_2.bError := TIIB[AT1K4-EL3202-02]^RTD Inputs Channel 2^Status^Error;
        .fbRTD_2.bUnderrange := TIIB[AT1K4-EL3202-02]^RTD Inputs Channel 2^Status^Underrange;
        .fbRTD_2.bOverrange := TIIB[AT1K4-EL3202-02]^RTD Inputs Channel 2^Status^Overrange;
    '}
    fbStage3: FB_SXR_SATT_Stage;

    {attribute 'pytmc' := 'pv: AT1K4:L2SI:MMS:04'}
    {attribute 'TcLinkTo' := '

        .fbRTD_1.iRaw := TIIB[AT1K4-EL3202-01]^RTD Inputs Channel 1^Value;
        .fbRTD_1.bError := TIIB[AT1K4-EL3202-01]^RTD Inputs Channel 1^Status^Error;
        .fbRTD_1.bUnderrange := TIIB[AT1K4-EL3202-01]^RTD Inputs Channel 1^Status^Underrange;
        .fbRTD_1.bOverrange := TIIB[AT1K4-EL3202-01]^RTD Inputs Channel 1^Status^Overrange;

        .fbRTD_2.iRaw := TIIB[AT1K4-EL3202-01]^RTD Inputs Channel 2^Value;
        .fbRTD_2.bError := TIIB[AT1K4-EL3202-01]^RTD Inputs Channel 2^Status^Error;
        .fbRTD_2.bUnderrange := TIIB[AT1K4-EL3202-01]^RTD Inputs Channel 2^Status^Underrange;
        .fbRTD_2.bOverrange := TIIB[AT1K4-EL3202-01]^RTD Inputs Channel 2^Status^Overrange;
    '}
    fbStage4: FB_SXR_SATT_Stage;

    fbStateSetup: FB_StateSetupHelper;
    stDefaultGood: ST_PositionState := (
        fDelta := 0.2,
        fVelocity := 10,
        bMoveOk := TRUE,
        bValid := TRUE
    );
    fbBadStateSetup: FB_StateSetupHelper;
    stDefaultBad: ST_PositionState := (
        fPosition := 500,
        fDelta := 0.2,
        fVelocity := 10,
        bMoveOk := FALSE,
        bValid := FALSE

    );
END_VAR
// M26, Axis 26
// M27, Axis 27
// M28, Axis 28
// M29, Axis 29

IF bDebug THEN
    // NEVER: checkouts with the TwinCAT NC GUI.
    nEnableMode := ENUM_StageEnableMode.NEVER;
ELSE
    // ALWAYS: want active position correction at all times
    nEnableMode := ENUM_StageEnableMode.ALWAYS;
END_IF

(*
    Important note

    Traveler        EPICS   Stage           NC      Location
    Axis 4          MMS:01  fbStage1        26      Downstream
    Axis 3          MMS:02  fbStage2        27
    Axis 2          MMS:03  fbStage3        28
    Axis 1          MMS:04  fbStage4        29      Upstream
*)

fbStateSetup(stPositionState:=stDefaultGood, bSetDefault:=TRUE);
fbBadStateSetup(stPositionState:=stDefaultBad, bSetDefault:=TRUE);

(* State setup - stage 1 *)
(* Downstream-most MMS:01 - TRAVELER AXIS 4 *)
fbStateSetup(stPositionState:=fbStage1.stOut, sName:='Out', fPosition:=22.70);
fbStateSetup(stPositionState:=fbStage1.stFilter1, sName:='(1) 25 um C', fPosition:=40.5);
fbStage1.arrFilters[1].fFilterThickness_um := 25;
fbStage1.arrFilters[1].sFilterMaterial     := 'C';
fbStateSetup(stPositionState:=fbStage1.stFilter2, sName:='(2) 50 um C', fPosition:=56.0);
fbStage1.arrFilters[2].fFilterThickness_um := 50;
fbStage1.arrFilters[2].sFilterMaterial     := 'C';
fbStateSetup(stPositionState:=fbStage1.stFilter3, sName:='(3) 100 um C', fPosition:=72.0);
fbStage1.arrFilters[3].fFilterThickness_um := 100;
fbStage1.arrFilters[3].sFilterMaterial     := 'C';
fbStateSetup(stPositionState:=fbStage1.stFilter4, sName:='(4) 320 um Si', fPosition:=87.5);
fbStage1.arrFilters[4].fFilterThickness_um := 320;
fbStage1.arrFilters[4].sFilterMaterial     := 'Si';
fbStateSetup(stPositionState:=fbStage1.stFilter5, sName:='(5) 160 um Si', fPosition:=102.5);
fbStage1.arrFilters[5].fFilterThickness_um := 160;
fbStage1.arrFilters[5].sFilterMaterial     := 'Si';
fbStateSetup(stPositionState:=fbStage1.stFilter6, sName:='(6) 80 um Si', fPosition:=117.5);
fbStage1.arrFilters[6].fFilterThickness_um := 80;
fbStage1.arrFilters[6].sFilterMaterial     := 'Si';
fbStateSetup(stPositionState:=fbStage1.stFilter7, sName:='(7) 40 um Si', fPosition:=135.5);
fbStage1.arrFilters[7].fFilterThickness_um := 40;
fbStage1.arrFilters[7].sFilterMaterial     := 'Si';
fbStateSetup(stPositionState:=fbStage1.stFilter8, sName:='(8) 20 um Si', fPosition:=150.5);
fbStage1.arrFilters[8].fFilterThickness_um := 20;
fbStage1.arrFilters[8].sFilterMaterial     := 'Si';

fbStage1(stAxis:=Main.M26, nEnableMode:=nEnableMode, fbFFHWO:=GVL.fbFastFaultOutput2, bEnable:=TRUE);

(* State setup - stage 2 *)
(* MMS:02 - 2nd downstream-most - TRAVELER AXIS 3 *)
fbStateSetup(stPositionState:=fbStage2.stOut, sName:='Out', fPosition:=24.00);
fbBadStateSetup(stPositionState:=fbStage2.stFilter1, sName:='Filter 1');
fbStage2.arrFilters[1].fFilterThickness_um := 0;
fbStage2.arrFilters[1].sFilterMaterial     := '';
fbBadStateSetup(stPositionState:=fbStage2.stFilter2, sName:='Filter 2');
fbStage2.arrFilters[2].fFilterThickness_um := 0;
fbStage2.arrFilters[2].sFilterMaterial     := '';
fbBadStateSetup(stPositionState:=fbStage2.stFilter3, sName:='Filter 3');
fbStage2.arrFilters[3].fFilterThickness_um := 0;
fbStage2.arrFilters[3].sFilterMaterial     := '';
fbBadStateSetup(stPositionState:=fbStage2.stFilter4, sName:='Filter 4');
fbStage2.arrFilters[4].fFilterThickness_um := 0;
fbStage2.arrFilters[4].sFilterMaterial     := '';
fbStateSetup(stPositionState:=fbStage2.stFilter5, sName:='(5) 50 um C', fPosition:=103.0);
fbStage2.arrFilters[5].fFilterThickness_um := 50;
fbStage2.arrFilters[5].sFilterMaterial     := 'C';
fbStateSetup(stPositionState:=fbStage2.stFilter6, sName:='(6) 25 um C', fPosition:=118.75);
fbStage2.arrFilters[6].fFilterThickness_um := 25;
fbStage2.arrFilters[6].sFilterMaterial     := 'C';
fbStateSetup(stPositionState:=fbStage2.stFilter7, sName:='(7) 12 um C', fPosition:=133.0);
fbStage2.arrFilters[7].fFilterThickness_um := 12;
fbStage2.arrFilters[7].sFilterMaterial     := 'C';
fbStateSetup(stPositionState:=fbStage2.stFilter8, sName:='(8) 10 um Si', fPosition:=147.0);
fbStage2.arrFilters[8].fFilterThickness_um := 10;
fbStage2.arrFilters[8].sFilterMaterial     := 'Si';

fbStage2(stAxis:=Main.M27, nEnableMode:=nEnableMode, fbFFHWO:=GVL.fbFastFaultOutput2, bEnable:=TRUE);

(* State setup - stage 3 *)
(* MMS:03 - 2nd upstream-most - TRAVELER AXIS 2 *)
fbStateSetup(stPositionState:=fbStage3.stOut, sName:='Out', fPosition:=23.24);
fbBadStateSetup(stPositionState:=fbStage3.stFilter1, sName:='Filter 1');
fbStage3.arrFilters[1].fFilterThickness_um := 0;
fbStage3.arrFilters[1].sFilterMaterial     := '';
fbBadStateSetup(stPositionState:=fbStage3.stFilter2, sName:='Filter 2');
fbStage3.arrFilters[2].fFilterThickness_um := 0;
fbStage3.arrFilters[2].sFilterMaterial     := '';
fbBadStateSetup(stPositionState:=fbStage3.stFilter3, sName:='Filter 3');
fbStage3.arrFilters[3].fFilterThickness_um := 0;
fbStage3.arrFilters[3].sFilterMaterial     := '';
fbBadStateSetup(stPositionState:=fbStage3.stFilter4, sName:='Filter 4');
fbStage3.arrFilters[4].fFilterThickness_um := 0;
fbStage3.arrFilters[4].sFilterMaterial     := '';
fbBadStateSetup(stPositionState:=fbStage3.stFilter5, sName:='Filter 5');
fbStage3.arrFilters[5].fFilterThickness_um := 0;
fbStage3.arrFilters[5].sFilterMaterial     := '';
fbStateSetup(stPositionState:=fbStage3.stFilter6, sName:='(6) 25 um C', fPosition:=119.5);
fbStage3.arrFilters[6].fFilterThickness_um := 25;
fbStage3.arrFilters[6].sFilterMaterial     := 'C';
fbStateSetup(stPositionState:=fbStage3.stFilter7, sName:='(7) 12 um C', fPosition:=135.0);
fbStage3.arrFilters[7].fFilterThickness_um := 12;
fbStage3.arrFilters[7].sFilterMaterial     := 'C';
fbStateSetup(stPositionState:=fbStage3.stFilter8, sName:='(8) 6 um C', fPosition:=147.5);
fbStage3.arrFilters[8].fFilterThickness_um := 6;
fbStage3.arrFilters[8].sFilterMaterial     := 'C';

fbStage3(stAxis:=Main.M28, nEnableMode:=nEnableMode, fbFFHWO:=GVL.fbFastFaultOutput2, bEnable:=TRUE);

(* State setup - stage 4 *)
(* MMS:04 - upstream-most - TRAVELER AXIS 1 *)
fbStateSetup(stPositionState:=fbStage4.stOut, sName:='Out', fPosition:=23.44);
fbBadStateSetup(stPositionState:=fbStage4.stFilter1, sName:='Filter 1');
fbStage4.arrFilters[1].fFilterThickness_um := 0;
fbStage4.arrFilters[1].sFilterMaterial     := '';
fbBadStateSetup(stPositionState:=fbStage4.stFilter2, sName:='Filter 2');
fbStage4.arrFilters[2].fFilterThickness_um := 0;
fbStage4.arrFilters[2].sFilterMaterial     := '';
fbBadStateSetup(stPositionState:=fbStage4.stFilter3, sName:='Filter 3');
fbStage4.arrFilters[3].fFilterThickness_um := 0;
fbStage4.arrFilters[3].sFilterMaterial     := '';
fbStateSetup(stPositionState:=fbStage4.stFilter4, sName:='(4) 12 um C', fPosition:=85.5);
fbStage4.arrFilters[4].fFilterThickness_um := 12;
fbStage4.arrFilters[4].sFilterMaterial     := 'C';
fbStateSetup(stPositionState:=fbStage4.stFilter5, sName:='(5) 6 um C', fPosition:=100.5);
fbStage4.arrFilters[5].fFilterThickness_um := 6;
fbStage4.arrFilters[5].sFilterMaterial     := 'C';
fbStateSetup(stPositionState:=fbStage4.stFilter6, sName:='(6) 3 um C', fPosition:=116.0);
fbStage4.arrFilters[6].fFilterThickness_um := 3;
fbStage4.arrFilters[6].sFilterMaterial     := 'C';
fbStateSetup(stPositionState:=fbStage4.stFilter7, sName:='(7) 3 um C', fPosition:=132.0);
fbStage4.arrFilters[7].fFilterThickness_um := 3;
fbStage4.arrFilters[7].sFilterMaterial     := 'C';
fbStateSetup(stPositionState:=fbStage4.stFilter8, sName:='(8) 0.2 um Al', fPosition:=147.0);
fbStage4.arrFilters[8].fFilterThickness_um := 0.2;
fbStage4.arrFilters[8].sFilterMaterial     := 'Al';

fbStage4(stAxis:=Main.M29, nEnableMode:=nEnableMode, fbFFHWO:=GVL.fbFastFaultOutput2, bEnable:=TRUE);

GVL.rCurTrans[PMPS.K_Attenuators.AT1K4].nTran := LREAL_TO_REAL(
    fbStage1.fTransmission *
    fbStage2.fTransmission *
    fbStage3.fTransmission *
    fbStage4.fTransmission
);

END_PROGRAM
Related:

PRG_IM1K0_XTES

PROGRAM PRG_IM1K0_XTES
VAR
    {attribute 'pytmc' := 'pv: IM1K0:XTES'}
    {attribute 'TcLinkTo' := '.bZoomEndFwd := TIIB[IM1K0-EL1088]^Channel 1^Input;
                              .bZoomEndBwd := TIIB[IM1K0-EL1088]^Channel 2^Input;
                              .bFocusEndFwd := TIIB[IM1K0-EL1088]^Channel 3^Input;
                              .bFocusEndBwd := TIIB[IM1K0-EL1088]^Channel 4^Input;
                              .fbOpal.bOpalPower := TIIB[IM1K0-EL2004]^Channel 2^Output;
                              .fbLED.bLedPower := TIIB[IM1K0-EL2004]^Channel 3^Output'}
    fbIM1K0: FB_XPIM;
    fbStateSetup: FB_StateSetupHelper;
    stDefault: ST_PositionState := (
        fVelocity := 1,
        bMoveOk := TRUE,
        bValid := TRUE
    );
    {attribute 'TcLinkTo' := '.Status := TIIB[IM1K0-EL6002]^COM TxPDO-Map Inputs Channel 1^Status;
                              .D[0] := TIIB[IM1K0-EL6002]^COM TxPDO-Map Inputs Channel 1^Data In 0;
                              .D[1] := TIIB[IM1K0-EL6002]^COM TxPDO-Map Inputs Channel 1^Data In 1;
                              .D[2] := TIIB[IM1K0-EL6002]^COM TxPDO-Map Inputs Channel 1^Data In 2;
                              .D[3] := TIIB[IM1K0-EL6002]^COM TxPDO-Map Inputs Channel 1^Data In 3;
                              .D[4] := TIIB[IM1K0-EL6002]^COM TxPDO-Map Inputs Channel 1^Data In 4;
                              .D[5] := TIIB[IM1K0-EL6002]^COM TxPDO-Map Inputs Channel 1^Data In 5;
                              .D[6] := TIIB[IM1K0-EL6002]^COM TxPDO-Map Inputs Channel 1^Data In 6;
                              .D[7] := TIIB[IM1K0-EL6002]^COM TxPDO-Map Inputs Channel 1^Data In 7;
                              .D[8] := TIIB[IM1K0-EL6002]^COM TxPDO-Map Inputs Channel 1^Data In 8;
                              .D[9] := TIIB[IM1K0-EL6002]^COM TxPDO-Map Inputs Channel 1^Data In 9;
                              .D[10] := TIIB[IM1K0-EL6002]^COM TxPDO-Map Inputs Channel 1^Data In 10;
                              .D[11] := TIIB[IM1K0-EL6002]^COM TxPDO-Map Inputs Channel 1^Data In 11;
                              .D[12] := TIIB[IM1K0-EL6002]^COM TxPDO-Map Inputs Channel 1^Data In 12;
                              .D[13] := TIIB[IM1K0-EL6002]^COM TxPDO-Map Inputs Channel 1^Data In 13;
                              .D[14] := TIIB[IM1K0-EL6002]^COM TxPDO-Map Inputs Channel 1^Data In 14;
                              .D[15] := TIIB[IM1K0-EL6002]^COM TxPDO-Map Inputs Channel 1^Data In 15;
                              .D[16] := TIIB[IM1K0-EL6002]^COM TxPDO-Map Inputs Channel 1^Data In 16;
                              .D[17] := TIIB[IM1K0-EL6002]^COM TxPDO-Map Inputs Channel 1^Data In 17;
                              .D[18] := TIIB[IM1K0-EL6002]^COM TxPDO-Map Inputs Channel 1^Data In 18;
                              .D[19] := TIIB[IM1K0-EL6002]^COM TxPDO-Map Inputs Channel 1^Data In 19;
                              .D[20] := TIIB[IM1K0-EL6002]^COM TxPDO-Map Inputs Channel 1^Data In 20;
                              .D[21] := TIIB[IM1K0-EL6002]^COM TxPDO-Map Inputs Channel 1^Data In 21'}
    stEL6In AT %I*: EL6InData22b;
    {attribute 'TcLinkTo' := '.Ctrl := TIIB[IM1K0-EL6002]^COM RxPDO-Map Outputs Channel 1^Ctrl;
                              .D[0] := TIIB[IM1K0-EL6002]^COM RxPDO-Map Outputs Channel 1^Data Out 0;
                              .D[1] := TIIB[IM1K0-EL6002]^COM RxPDO-Map Outputs Channel 1^Data Out 1;
                              .D[2] := TIIB[IM1K0-EL6002]^COM RxPDO-Map Outputs Channel 1^Data Out 2;
                              .D[3] := TIIB[IM1K0-EL6002]^COM RxPDO-Map Outputs Channel 1^Data Out 3;
                              .D[4] := TIIB[IM1K0-EL6002]^COM RxPDO-Map Outputs Channel 1^Data Out 4;
                              .D[5] := TIIB[IM1K0-EL6002]^COM RxPDO-Map Outputs Channel 1^Data Out 5;
                              .D[6] := TIIB[IM1K0-EL6002]^COM RxPDO-Map Outputs Channel 1^Data Out 6;
                              .D[7] := TIIB[IM1K0-EL6002]^COM RxPDO-Map Outputs Channel 1^Data Out 7;
                              .D[8] := TIIB[IM1K0-EL6002]^COM RxPDO-Map Outputs Channel 1^Data Out 8;
                              .D[9] := TIIB[IM1K0-EL6002]^COM RxPDO-Map Outputs Channel 1^Data Out 9;
                              .D[10] := TIIB[IM1K0-EL6002]^COM RxPDO-Map Outputs Channel 1^Data Out 10;
                              .D[11] := TIIB[IM1K0-EL6002]^COM RxPDO-Map Outputs Channel 1^Data Out 11;
                              .D[12] := TIIB[IM1K0-EL6002]^COM RxPDO-Map Outputs Channel 1^Data Out 12;
                              .D[13] := TIIB[IM1K0-EL6002]^COM RxPDO-Map Outputs Channel 1^Data Out 13;
                              .D[14] := TIIB[IM1K0-EL6002]^COM RxPDO-Map Outputs Channel 1^Data Out 14;
                              .D[15] := TIIB[IM1K0-EL6002]^COM RxPDO-Map Outputs Channel 1^Data Out 15;
                              .D[16] := TIIB[IM1K0-EL6002]^COM RxPDO-Map Outputs Channel 1^Data Out 16;
                              .D[17] := TIIB[IM1K0-EL6002]^COM RxPDO-Map Outputs Channel 1^Data Out 17;
                              .D[18] := TIIB[IM1K0-EL6002]^COM RxPDO-Map Outputs Channel 1^Data Out 18;
                              .D[19] := TIIB[IM1K0-EL6002]^COM RxPDO-Map Outputs Channel 1^Data Out 19;
                              .D[20] := TIIB[IM1K0-EL6002]^COM RxPDO-Map Outputs Channel 1^Data Out 20;
                              .D[21] := TIIB[IM1K0-EL6002]^COM RxPDO-Map Outputs Channel 1^Data Out 21'}
    stEL6Out AT %Q*: EL6OutData22b;
END_VAR
fbStateSetup(stPositionState:=stDefault, bSetDefault:=TRUE);

fbStateSetup(stPositionState:=fbIM1K0.stOut, fPosition:=0, sPmpsState:='IM1K0:XTES-OUT');
fbStateSetup(stPositionState:=fbIM1K0.stYag, fPosition:=-27.65, sPmpsState:='IM1K0:XTES-YAG');
fbStateSetup(stPositionState:=fbIM1K0.stDiamond, fPosition:=-57.65, sPmpsState:='IM1K0:XTES-DIAMOND');
fbStateSetup(stPositionState:=fbIM1K0.stReticle, fPosition:=-87.65, sPmpsState:='IM1K0:XTES-RETICLE');

fbIM1K0(
    fbFFHWO := GVL.fbFastFaultOutput1,
    fbArbiter := GVL.fbArbiter,
    stYStage := Main.M1,
    stZoomStage := Main.M2,
    stFocusStage := Main.M3,
    stEl6In := stEL6In,
    stEl6Out := stEl6Out,
    sDeviceName := 'IM1K0:XTES',
    sTransitionKey := 'IM1K0:XTES-TRANSITION',
    bEnableMotion := TRUE,
    bEnableBeamParams := TRUE,
    bEnablePositionLimits := TRUE,
);

END_PROGRAM
Related:

PRG_IM1K3_PPM

PROGRAM PRG_IM1K3_PPM
VAR
    {attribute 'pytmc' := 'pv: IM1K3:PPM'}
    {attribute 'TcLinkTo' := '.fbGige.iIlluminatorINT := TIIB[IM1K3-EL4004]^AO Outputs Channel 1^Analog output;
                              .fbGige.bGigePower := TIIB[IM1K3-EL2004]^Channel 2^Output;
                              .fbPowerMeter.iVoltageINT := TIIB[IM1K3-EL3062]^AI Standard Channel 1^Value;
                              .fbPowerMeter.fbThermoCouple.bError := TIIB[IM1K3-EL3314]^TC Inputs Channel 1^Status^Error;
                              .fbPowerMeter.fbThermoCouple.bUnderrange := TIIB[IM1K3-EL3314]^TC Inputs Channel 1^Status^Underrange;
                              .fbPowerMeter.fbThermoCouple.bOverrange := TIIB[IM1K3-EL3314]^TC Inputs Channel 1^Status^Overrange;
                              .fbPowerMeter.fbThermoCouple.iRaw := TIIB[IM1K3-EL3314]^TC Inputs Channel 1^Value;
                              .fbYagThermoCouple.bError := TIIB[IM1K3-EL3314]^TC Inputs Channel 2^Status^Error;
                              .fbYagThermoCouple.bUnderrange := TIIB[IM1K3-EL3314]^TC Inputs Channel 2^Status^Underrange;
                              .fbYagThermoCouple.bOverrange := TIIB[IM1K3-EL3314]^TC Inputs Channel 2^Status^Overrange;
                              .fbYagThermoCouple.iRaw := TIIB[IM1K3-EL3314]^TC Inputs Channel 2^Value'}
    fbIM1K3: FB_PPM;
    fbStateSetup: FB_StateSetupHelper;
    stDefault: ST_PositionState := (
        fVelocity := 15,
        bMoveOk := TRUE,
        bValid := TRUE
    );
END_VAR
fbStateSetup(stPositionState:=stDefault, bSetDefault:=TRUE);

fbStateSetup(stPositionState:=fbIM1K3.stOut, fPosition:=-9.1, sPmpsState:='IM1K3:PPM-OUT');
fbStateSetup(stPositionState:=fbIM1K3.stPower, fPosition:=-48.2, sPmpsState:='IM1K3:PPM-POWERMETER');
fbStateSetup(stPositionState:=fbIM1K3.stYag1, fPosition:=-72.2, sPmpsState:='IM1K3:PPM-YAG1');
fbStateSetup(stPositionState:=fbIM1K3.stYag2, fPosition:=-98.21, sPmpsState:='IM1K3:PPM-YAG2');

fbIM1K3(
    fbFFHWO := GVL.fbFastFaultOutput2,
    fbArbiter := GVL.fbArbiter2,
    stYStage := Main.M4,
    sDeviceName := 'IM1K3:PPM',
    sTransitionKey := 'IM1K3:PPM-TRANSITION',
    bEnableMotion := TRUE,
    bEnableBeamParams := TRUE,
    bEnablePositionLimits := TRUE,
);

END_PROGRAM
Related:

PRG_IM1K4_XTES

PROGRAM PRG_IM1K4_XTES
VAR
    {attribute 'pytmc' := 'pv: IM1K4:XTES'}
    {attribute 'TcLinkTo' := '.bZoomEndFwd := TIIB[IM1K4-EL1088-E5]^Channel 1^Input;
                              .bZoomEndBwd := TIIB[IM1K4-EL1088-E5]^Channel 2^Input;
                              .bFocusEndFwd := TIIB[IM1K4-EL1088-E5]^Channel 3^Input;
                              .bFocusEndBwd := TIIB[IM1K4-EL1088-E5]^Channel 4^Input;
                              .fbOpal.bOpalPower := TIIB[IM1K4-EL2004-E2]^Channel 2^Output;
                              .fbLED.bLedPower := TIIB[IM1K4-EL2004-E2]^Channel 3^Output'}
    fbIM1K4: FB_XPIM;
    fbStateSetup: FB_StateSetupHelper;
    stDefault: ST_PositionState := (
        fVelocity := 1,
        bMoveOk := TRUE,
        bValid := TRUE
    );
    {attribute 'TcLinkTo' := '.Status := TIIB[IM1K4-EL6002-E6]^COM TxPDO-Map Inputs Channel 1^Status;
                              .D[0] := TIIB[IM1K4-EL6002-E6]^COM TxPDO-Map Inputs Channel 1^Data In 0;
                              .D[1] := TIIB[IM1K4-EL6002-E6]^COM TxPDO-Map Inputs Channel 1^Data In 1;
                              .D[2] := TIIB[IM1K4-EL6002-E6]^COM TxPDO-Map Inputs Channel 1^Data In 2;
                              .D[3] := TIIB[IM1K4-EL6002-E6]^COM TxPDO-Map Inputs Channel 1^Data In 3;
                              .D[4] := TIIB[IM1K4-EL6002-E6]^COM TxPDO-Map Inputs Channel 1^Data In 4;
                              .D[5] := TIIB[IM1K4-EL6002-E6]^COM TxPDO-Map Inputs Channel 1^Data In 5;
                              .D[6] := TIIB[IM1K4-EL6002-E6]^COM TxPDO-Map Inputs Channel 1^Data In 6;
                              .D[7] := TIIB[IM1K4-EL6002-E6]^COM TxPDO-Map Inputs Channel 1^Data In 7;
                              .D[8] := TIIB[IM1K4-EL6002-E6]^COM TxPDO-Map Inputs Channel 1^Data In 8;
                              .D[9] := TIIB[IM1K4-EL6002-E6]^COM TxPDO-Map Inputs Channel 1^Data In 9;
                              .D[10] := TIIB[IM1K4-EL6002-E6]^COM TxPDO-Map Inputs Channel 1^Data In 10;
                              .D[11] := TIIB[IM1K4-EL6002-E6]^COM TxPDO-Map Inputs Channel 1^Data In 11;
                              .D[12] := TIIB[IM1K4-EL6002-E6]^COM TxPDO-Map Inputs Channel 1^Data In 12;
                              .D[13] := TIIB[IM1K4-EL6002-E6]^COM TxPDO-Map Inputs Channel 1^Data In 13;
                              .D[14] := TIIB[IM1K4-EL6002-E6]^COM TxPDO-Map Inputs Channel 1^Data In 14;
                              .D[15] := TIIB[IM1K4-EL6002-E6]^COM TxPDO-Map Inputs Channel 1^Data In 15;
                              .D[16] := TIIB[IM1K4-EL6002-E6]^COM TxPDO-Map Inputs Channel 1^Data In 16;
                              .D[17] := TIIB[IM1K4-EL6002-E6]^COM TxPDO-Map Inputs Channel 1^Data In 17;
                              .D[18] := TIIB[IM1K4-EL6002-E6]^COM TxPDO-Map Inputs Channel 1^Data In 18;
                              .D[19] := TIIB[IM1K4-EL6002-E6]^COM TxPDO-Map Inputs Channel 1^Data In 19;
                              .D[20] := TIIB[IM1K4-EL6002-E6]^COM TxPDO-Map Inputs Channel 1^Data In 20;
                              .D[21] := TIIB[IM1K4-EL6002-E6]^COM TxPDO-Map Inputs Channel 1^Data In 21'}
    stEL6In AT %I*: EL6InData22b;
    {attribute 'TcLinkTo' := '.Ctrl := TIIB[IM1K4-EL6002-E6]^COM RxPDO-Map Outputs Channel 1^Ctrl;
                              .D[0] := TIIB[IM1K4-EL6002-E6]^COM RxPDO-Map Outputs Channel 1^Data Out 0;
                              .D[1] := TIIB[IM1K4-EL6002-E6]^COM RxPDO-Map Outputs Channel 1^Data Out 1;
                              .D[2] := TIIB[IM1K4-EL6002-E6]^COM RxPDO-Map Outputs Channel 1^Data Out 2;
                              .D[3] := TIIB[IM1K4-EL6002-E6]^COM RxPDO-Map Outputs Channel 1^Data Out 3;
                              .D[4] := TIIB[IM1K4-EL6002-E6]^COM RxPDO-Map Outputs Channel 1^Data Out 4;
                              .D[5] := TIIB[IM1K4-EL6002-E6]^COM RxPDO-Map Outputs Channel 1^Data Out 5;
                              .D[6] := TIIB[IM1K4-EL6002-E6]^COM RxPDO-Map Outputs Channel 1^Data Out 6;
                              .D[7] := TIIB[IM1K4-EL6002-E6]^COM RxPDO-Map Outputs Channel 1^Data Out 7;
                              .D[8] := TIIB[IM1K4-EL6002-E6]^COM RxPDO-Map Outputs Channel 1^Data Out 8;
                              .D[9] := TIIB[IM1K4-EL6002-E6]^COM RxPDO-Map Outputs Channel 1^Data Out 9;
                              .D[10] := TIIB[IM1K4-EL6002-E6]^COM RxPDO-Map Outputs Channel 1^Data Out 10;
                              .D[11] := TIIB[IM1K4-EL6002-E6]^COM RxPDO-Map Outputs Channel 1^Data Out 11;
                              .D[12] := TIIB[IM1K4-EL6002-E6]^COM RxPDO-Map Outputs Channel 1^Data Out 12;
                              .D[13] := TIIB[IM1K4-EL6002-E6]^COM RxPDO-Map Outputs Channel 1^Data Out 13;
                              .D[14] := TIIB[IM1K4-EL6002-E6]^COM RxPDO-Map Outputs Channel 1^Data Out 14;
                              .D[15] := TIIB[IM1K4-EL6002-E6]^COM RxPDO-Map Outputs Channel 1^Data Out 15;
                              .D[16] := TIIB[IM1K4-EL6002-E6]^COM RxPDO-Map Outputs Channel 1^Data Out 16;
                              .D[17] := TIIB[IM1K4-EL6002-E6]^COM RxPDO-Map Outputs Channel 1^Data Out 17;
                              .D[18] := TIIB[IM1K4-EL6002-E6]^COM RxPDO-Map Outputs Channel 1^Data Out 18;
                              .D[19] := TIIB[IM1K4-EL6002-E6]^COM RxPDO-Map Outputs Channel 1^Data Out 19;
                              .D[20] := TIIB[IM1K4-EL6002-E6]^COM RxPDO-Map Outputs Channel 1^Data Out 20;
                              .D[21] := TIIB[IM1K4-EL6002-E6]^COM RxPDO-Map Outputs Channel 1^Data Out 21'}
    stEL6Out AT %Q*: EL6OutData22b;

    {attribute 'pytmc' := '
        pv: IM1K4:SCRP:LED:01:PWR
        io: io
        field: ZNAM OFF
        field: ONAM ON
    '}
    {attribute 'TcLinkTo' := 'TIIB[IM1K4-EL2004-E2]^Channel 4^Output'}
    bIM1K4_SCRP_LED_01 AT %Q*: BOOL;
END_VAR
fbStateSetup(stPositionState:=stDefault, bSetDefault:=TRUE);

fbStateSetup(stPositionState:=fbIM1K4.stOut, fPosition:=0, sPmpsState:='IM1K4:XTES-OUT');
fbStateSetup(stPositionState:=fbIM1K4.stYag, fPosition:=-88.87, sPmpsState:='IM1K4:XTES-YAG');
fbStateSetup(stPositionState:=fbIM1K4.stDiamond, fPosition:=-58.87, sPmpsState:='IM1K4:XTES-DIAMOND');
fbStateSetup(stPositionState:=fbIM1K4.stReticle, fPosition:=-28.87, sPmpsState:='IM1K4:XTES-RETICLE');

fbIM1K4(
    fbFFHWO := GVL.fbFastFaultOutput2,
    fbArbiter := GVL.fbArbiter2,
    stYStage := Main.M30,
    stZoomStage := Main.M31,
    stFocusStage := Main.M32,
    stEl6In := stEL6In,
    stEl6Out := stEl6Out,
    sDeviceName := 'IM1K4:XTES',
    sTransitionKey := 'IM1K4:XTES-TRANSITION',
    bEnableMotion := TRUE,
    bEnableBeamParams := TRUE,
    bEnablePositionLimits := TRUE,
);

END_PROGRAM
Related:

PRG_IM2K0_XTES

PROGRAM PRG_IM2K0_XTES
VAR
    {attribute 'pytmc' := 'pv: IM2K0:XTES'}
    {attribute 'TcLinkTo' := '.fbLED.bLedPower := TIIB[IM2K0-EL2004]^Channel 3^Output;
                              .fbGige.bGigePower := TIIB[IM2K0-EL2004]^Channel 4^Output'}
    fbIM2K0: FB_XPIM_IM2K0;
    fbStateSetup: FB_StateSetupHelper;
    stDefault: ST_PositionState := (
        fVelocity := 1,
        bMoveOk := TRUE,
        bValid := TRUE
    );

    {attribute 'TcLinkTo' := 'TIIB[IM2K0-EL7041]^STM Status^Status^Digital input 1'}
    bDefectiveLimitSwitch AT %I*: BOOL;
END_VAR
fbStateSetup(stPositionState:=stDefault, bSetDefault:=TRUE);

fbStateSetup(stPositionState:=fbIM2K0.stOut, fPosition:=0, sPmpsState:='IM2K0:XTES-OUT');
fbStateSetup(stPositionState:=fbIM2K0.stYag, fPosition:=-87.65);
fbStateSetup(stPositionState:=fbIM2K0.stDiamond, fPosition:=-57.65, sPmpsState:='IM2K0:XTES-DIAMOND');
fbStateSetup(stPositionState:=fbIM2K0.stReticle, fPosition:=-27.65, sPmpsState:='IM2K0:XTES-RETICLE');

CASE GVL.ePF1K0State OF
    E_WFS_STATES.TARGET1, E_WFS_STATES.TARGET2, E_WFS_STATES.TARGET3, E_WFS_STATES.TARGET4, E_WFS_STATES.TARGET5 :
        // Known state targets: allow less strict pmps
        fbIM2K0.stYag.stPMPS.sPmpsState := 'IM2K0:XTES-YAG_WFS_IN';
ELSE
    // Out, Unknown, or an unexpected state: full pmps
    fbIM2K0.stYag.stPMPS.sPmpsState := 'IM2K0:XTES-YAG';
END_CASE

fbIM2K0(
    fbFFHWO := GVL.fbFastFaultOutput1,
    fbArbiter := GVL.fbArbiter,
    stYStage := Main.M5,
    sDeviceName := 'IM2K0:XTES',
    sTransitionKey := 'IM2K0:XTES-TRANSITION',
    bEnableMotion := TRUE,
    bEnableBeamParams := TRUE,
    bEnablePositionLimits := TRUE,
);

Main.M5.bLimitForwardEnable := bDefectiveLimitSwitch OR (Main.M5.stAxisStatus.fActPosition < 0);

END_PROGRAM
Related:

PRG_PF1K0_WFS

PROGRAM PRG_PF1K0_WFS
VAR
    {attribute 'pytmc' := 'pv: PF1K0:WFS'}
    {attribute 'TcLinkTo' := '.fbThermoCouple1.bError := TIIB[PF1K0-EL3314]^TC Inputs Channel 1^Status^Error;
                              .fbThermoCouple1.bUnderrange := TIIB[PF1K0-EL3314]^TC Inputs Channel 1^Status^Underrange;
                              .fbThermoCouple1.bOverrange := TIIB[PF1K0-EL3314]^TC Inputs Channel 1^Status^Overrange;
                              .fbThermoCouple1.iRaw := TIIB[PF1K0-EL3314]^TC Inputs Channel 1^Value;
                              .fbThermoCouple2.bError := TIIB[PF1K0-EL3314]^TC Inputs Channel 2^Status^Error;
                              .fbThermoCouple2.bUnderrange := TIIB[PF1K0-EL3314]^TC Inputs Channel 2^Status^Underrange;
                              .fbThermoCouple2.bOverrange := TIIB[PF1K0-EL3314]^TC Inputs Channel 2^Status^Overrange;
                              .fbThermoCouple2.iRaw := TIIB[PF1K0-EL3314]^TC Inputs Channel 2^Value'}
    fbPF1K0: FB_WFS;
    fbStateSetup: FB_StateSetupHelper;
    stDefault: ST_PositionState := (
        fVelocity := 1,
        bMoveOk := TRUE,
        bValid := TRUE
    );
END_VAR
fbStateSetup(stPositionState:=stDefault, bSetDefault:=TRUE);

fbStateSetup(stPositionState:=fbPF1K0.stOut, fPosition:=-15, sPmpsState:='PF1K0:WFS-OUT');
fbStateSetup(stPositionState:=fbPF1K0.stTarget1, fPosition:=-96.623, sPmpsState:='PF1K0:WFS-TARGET1');
fbStateSetup(stPositionState:=fbPF1K0.stTarget2, fPosition:=-82.25, sPmpsState:='PF1K0:WFS-TARGET2');
fbStateSetup(stPositionState:=fbPF1K0.stTarget3, fPosition:=-67.874, sPmpsState:='PF1K0:WFS-TARGET3');
fbStateSetup(stPositionState:=fbPF1K0.stTarget4, fPosition:=-53.5, sPmpsState:='PF1K0:WFS-TARGET4');
fbStateSetup(stPositionState:=fbPF1K0.stTarget5, fPosition:=-39.124, sPmpsState:='PF1K0:WFS-TARGET5');

fbPF1K0(
    fbFFHWO := GVL.fbFastFaultOutput1,
    fbArbiter := GVL.fbArbiter,
    stYStage := Main.M8,
    stZStage := Main.M9,
    sDeviceName := 'PF1K0:WFS',
    sTransitionKey := 'PF1K0:WFS-TRANSITION',
    bEnableMotion := TRUE,
    bEnableBeamParams := TRUE,
    bEnablePositionLimits := TRUE,
    eEnumGet => GVL.ePF1K0State,
);

END_PROGRAM
Related:

PRG_RTDSK0

PROGRAM PRG_RTDSK0
VAR

   {attribute 'TcLinkTo' := '.i_xInsertedLS := TIIB[RTDSK0-MPA-EL1008]^Channel 1^Input;
                             .i_xRetractedLS := TIIB[RTDSK0-MPA-EL1008]^Channel 2^Input;
                             .q_xInsert_DO :=  TIIB[RTDSK0-MPA-EL2008]^Channel 1^Output;
                             .q_xRetract_DO :=  TIIB[RTDSK0-MPA-EL2008]^Channel 2^Output
    '}

     {attribute 'pytmc' :=' pv: RTDSK0:MPA:01 '}
    RTDSK0_MPA_01: FB_MPA := (sName := 'RTDSK0:MPA:01');

   {attribute 'TcLinkTo' := '.i_xInsertedLS := TIIB[RTDSK0-MPA-EL1008]^Channel 3^Input;
                             .i_xRetractedLS := TIIB[RTDSK0-MPA-EL1008]^Channel 4^Input;
                             .q_xInsert_DO :=  TIIB[RTDSK0-MPA-EL2008]^Channel 3^Output;
                             .q_xRetract_DO :=  TIIB[RTDSK0-MPA-EL2008]^Channel 4^Output
    '}


    {attribute 'pytmc' :=' pv: RTDSK0:MPA:02 '}
    RTDSK0_MPA_02: FB_MPA := (sName := 'RTDSK0:MPA:02');

       {attribute 'TcLinkTo' := '.i_xInsertedLS := TIIB[RTDSK0-MPA-EL1008]^Channel 5^Input;
                             .i_xRetractedLS := TIIB[RTDSK0-MPA-EL1008]^Channel 6^Input;
                             .q_xInsert_DO :=  TIIB[RTDSK0-MPA-EL2008]^Channel 5^Output;
                             .q_xRetract_DO :=  TIIB[RTDSK0-MPA-EL2008]^Channel 6^Output
    '}

    {attribute 'pytmc' :=' pv: RTDSK0:MPA:03 '}
    RTDSK0_MPA_03: FB_MPA := (sName := 'RTDSK0:MPA:03');

       {attribute 'TcLinkTo' := '.i_xInsertedLS := TIIB[RTDSK0-MPA-EL1008]^Channel 7^Input;
                             .i_xRetractedLS := TIIB[RTDSK0-MPA-EL1008]^Channel 8^Input;
                             .q_xInsert_DO :=  TIIB[RTDSK0-MPA-EL2008]^Channel 7^Output;
                             .q_xRetract_DO :=  TIIB[RTDSK0-MPA-EL2008]^Channel 8^Output
    '}
    {attribute 'pytmc' :=' pv: RTDSK0:MPA:04 '}
    RTDSK0_MPA_04: FB_MPA := (sName := 'RTDSK0:MPA:04');

    fbRTDSK0_SCRP_MMS_Z: FB_MotionStage;
    fbRTDSK0_SCRP_MMS_X: FB_MotionStage;
    fbRTDSK0_SCRP_MMS_Y: FB_MotionStage;

     {attribute 'pytmc' := 'pv: RTDSK0:SCRP:LED:01:PWR
      io: io
        field: ZNAM OFF
        field: ONAM ON
'}

     {attribute 'TcLinkTo' := 'TIIB[RTDSK0-EL2004]^Channel 3^Output'}
    bRTDSK0_SCRP_LED_01 AT %Q*: BOOL;

    FFO : FB_FastFault :=( i_Desc := 'fault occurs when Y motor is not activating upper limit switch', i_TypeCode := 16#FAF, i_DevName := 'RTDSK0:SCRP:MMS:Y');
    bInit: BOOL := TRUE;



END_VAR
//Pneumatic actuators - OTR filters

RTDSK0_MPA_01(
    ibInsertOK:= TRUE,
    ibRetractOK:= TRUE ,
    ibPMPS_OK:= TRUE ,
    ibOverrideInterlock:= ,
    q_stAct=> ,
    xMPS_OK=> ,
    xDone=> ,
    i_xReset := ,
    io_fbFFHWO := GVL.fbFastFaultOutput1,
);

RTDSK0_MPA_02(
    ibInsertOK:= TRUE,
    ibRetractOK:= TRUE ,
    ibPMPS_OK:= TRUE ,
    ibOverrideInterlock:= ,
    q_stAct=> ,
    xMPS_OK=> ,
    xDone=> ,
    i_xReset := ,
    io_fbFFHWO := GVL.fbFastFaultOutput1,
);

(*
Disable MPA_03 and MPA_04, no actuator installed

RTDSK0_MPA_03(
    ibInsertOK:= TRUE,
    ibRetractOK:= TRUE ,
    ibPMPS_OK:= TRUE ,
    ibOverrideInterlock:= ,
    q_stAct=> ,
    xMPS_OK=> ,
    xDone=> ,
    i_xReset := ,
    io_fbFFHWO := GVL.fbFastFaultOutput1,
);

RTDSK0_MPA_04(
    ibInsertOK:= TRUE,
    ibRetractOK:= TRUE ,
    ibPMPS_OK:= TRUE ,
    ibOverrideInterlock:= ,
    q_stAct=> ,
    xMPS_OK=> ,
    xDone=> ,
    i_xReset := ,
    io_fbFFHWO := GVL.fbFastFaultOutput1,
);
*)

//initialize RTDSK0 stages
IF bInit THEN
    Main.M11.bHardwareEnable := TRUE;
    Main.M11.bPowerSelf :=TRUE;
    Main.M11.nBrakeMode := ENUM_StageBrakeMode.NO_BRAKE;
    Main.M11.nEnableMode := ENUM_StageEnableMode.DURING_MOTION;
    Main.M11.fHomePosition := 0;

    Main.M12.bHardwareEnable := TRUE;
    Main.M12.bPowerSelf :=TRUE;
    Main.M12.nBrakeMode := ENUM_StageBrakeMode.NO_BRAKE;
    Main.M12.nEnableMode := ENUM_StageEnableMode.DURING_MOTION;
    Main.M12.fHomePosition := 0;

    Main.M13.bHardwareEnable := TRUE;
    Main.M13.bPowerSelf :=TRUE;
    Main.M13.nBrakeMode := ENUM_StageBrakeMode.NO_BRAKE;
    Main.M13.nEnableMode := ENUM_StageEnableMode.DURING_MOTION;
    Main.M13.fHomePosition := 0;

    Main.M11.nHomingMode := ENUM_EpicsHomeCmd.HIGH_LIMIT;
    Main.M12.nHomingMode := ENUM_EpicsHomeCmd.HIGH_LIMIT;
    Main.M13.nHomingMode := ENUM_EpicsHomeCmd.HIGH_LIMIT;

    bInit := FALSE;
END_IF

    fbRTDSK0_SCRP_MMS_Z (stMotionStage := Main.M11);
    fbRTDSK0_SCRP_MMS_X (stMotionStage := Main.M12);
    fbRTDSK0_SCRP_MMS_Y (stMotionStage := Main.M13);
    FFO(i_xOK := NOT(Main.M13.bLimitForwardEnable) AND Main.M13.bLimitBackwardEnable, io_fbFFHWO := GVL.fbFastFaultOutput1);

END_PROGRAM
Related:

PRG_SL1K0_POWER

PROGRAM PRG_SL1K0_POWER
VAR
    {attribute 'pytmc' := '
        pv: SL1K0:POWER
        io: io
    '}
    {attribute 'TcLinkTo' := '.RTD_South_1.iRaw := TIIB[SL1K0-EL3202-E6]^RTD Inputs Channel 1^Value;
                              .RTD_South_1.bError := TIIB[SL1K0-EL3202-E6]^RTD Inputs Channel 1^Status^Error;
                              .RTD_South_1.bUnderrange := TIIB[SL1K0-EL3202-E6]^RTD Inputs Channel 1^Status^Underrange;
                              .RTD_South_1.bOverrange := TIIB[SL1K0-EL3202-E6]^RTD Inputs Channel 1^Status^Overrange;
                              .RTD_South_2.iRaw := TIIB[SL1K0-EL3202-E6]^RTD Inputs Channel 2^Value;
                              .RTD_South_2.bError := TIIB[SL1K0-EL3202-E6]^RTD Inputs Channel 2^Status^Error;
                              .RTD_South_2.bUnderrange := TIIB[SL1K0-EL3202-E6]^RTD Inputs Channel 2^Status^Underrange;
                              .RTD_South_2.bOverrange := TIIB[SL1K0-EL3202-E6]^RTD Inputs Channel 2^Status^Overrange;
                              .RTD_TOP_1.iRaw := TIIB[SL1K0-EL3202-E7]^RTD Inputs Channel 1^Value;
                              .RTD_TOP_1.bError := TIIB[SL1K0-EL3202-E7]^RTD Inputs Channel 1^Status^Error;
                              .RTD_TOP_1.bUnderrange := TIIB[SL1K0-EL3202-E7]^RTD Inputs Channel 1^Status^Underrange;
                              .RTD_TOP_1.bOverrange := TIIB[SL1K0-EL3202-E7]^RTD Inputs Channel 1^Status^Overrange;
                              .RTD_TOP_2.iRaw := TIIB[SL1K0-EL3202-E7]^RTD Inputs Channel 2^Value;
                              .RTD_TOP_2.bError := TIIB[SL1K0-EL3202-E7]^RTD Inputs Channel 2^Status^Error;
                              .RTD_TOP_2.bUnderrange := TIIB[SL1K0-EL3202-E7]^RTD Inputs Channel 2^Status^Underrange;
                              .RTD_TOP_2.bOverrange := TIIB[SL1K0-EL3202-E7]^RTD Inputs Channel 2^Status^Overrange;
                              .RTD_North_1.iRaw := TIIB[SL1K0-EL3202-E8]^RTD Inputs Channel 1^Value;
                              .RTD_North_1.bError := TIIB[SL1K0-EL3202-E8]^RTD Inputs Channel 1^Status^Error;
                              .RTD_North_1.bUnderrange := TIIB[SL1K0-EL3202-E8]^RTD Inputs Channel 1^Status^Underrange;
                              .RTD_North_1.bOverrange := TIIB[SL1K0-EL3202-E8]^RTD Inputs Channel 1^Status^Overrange;
                              .RTD_North_2.iRaw := TIIB[SL1K0-EL3202-E8]^RTD Inputs Channel 2^Value;
                              .RTD_North_2.bError := TIIB[SL1K0-EL3202-E8]^RTD Inputs Channel 2^Status^Error;
                              .RTD_North_2.bUnderrange := TIIB[SL1K0-EL3202-E8]^RTD Inputs Channel 2^Status^Underrange;
                              .RTD_North_2.bOverrange := TIIB[SL1K0-EL3202-E8]^RTD Inputs Channel 2^Status^Overrange;
                              .RTD_Bottom_1.iRaw := TIIB[SL1K0-EL3202-E9]^RTD Inputs Channel 1^Value;
                              .RTD_Bottom_1.bError := TIIB[SL1K0-EL3202-E9]^RTD Inputs Channel 1^Status^Error;
                              .RTD_Bottom_1.bUnderrange := TIIB[SL1K0-EL3202-E9]^RTD Inputs Channel 1^Status^Underrange;
                              .RTD_Bottom_1.bOverrange := TIIB[SL1K0-EL3202-E9]^RTD Inputs Channel 1^Status^Overrange;
                              .RTD_Bottom_2.iRaw := TIIB[SL1K0-EL3202-E9]^RTD Inputs Channel 2^Value;
                              .RTD_Bottom_2.bError := TIIB[SL1K0-EL3202-E9]^RTD Inputs Channel 2^Status^Error;
                              .RTD_Bottom_2.bUnderrange := TIIB[SL1K0-EL3202-E9]^RTD Inputs Channel 2^Status^Underrange;
                              .RTD_Bottom_2.bOverrange := TIIB[SL1K0-EL3202-E9]^RTD Inputs Channel 2^Status^Overrange;
                              .AptArrayStatus := 'TIIB[PMPS_PRE]^IO Outputs^AptArrayStatus^AptArrayStatus[1];
                              .AptArrayReq := 'TIIB[PMPS_PRE]^IO Inputs^AptArrayReq^AptArrayReq[1]'}
    fbSL1K0: FB_SLITS_POWER;
//{attribute 'TcLinkTo' := 'TIIB[PMPS_PRE]^IO Outputs^AptArrayStatus'}
    {attribute 'pytmc' := '
    pv: SL1K0:POWER:GO;
    io: io;
    field: ZNAM False;
    field: ONAM True;
    '}
    bExecuteMotion:BOOL ;
    //GET PMPS Move Ok bit
    // Default True until it is properly linked to PMPS bit
    bMoveOk:BOOL :=TRUE;

    //for testing purposes only. comment-out/delete once done.
    mcPower : ARRAY [1..4] OF MC_POWER;
    bTest:BOOL:=FALSE;

    (*Offsets*)
    (* Absolute encoder value at the HLS + Absolure eoncoder value at the centered beam *)
    rEncoderOffsetTop: REAL := -11.2; (* 0+(-15)*)
    rEncoderOffsetBottom: REAL := -11.9; (* 0+(-15)*)
    rEncoderOffsetNorth: REAL := -11.4;//-4.6;(* 0+(-15)*)
    rEncoderOffsetSouth: REAL := -13;(* 0+(-15)*)
END_VAR
fbSL1K0.bMoveOk := bMoveOk;
Main.M18.bLimitBackwardEnable := True;



//for testing purposes only. comment-out/delete once done.
If bTest THEN
    mcPower[1](axis:=Main.M18.Axis, Enable:=TRUE, enable_positive:=Main.M18.bLimitForwardEnable, enable_negative:=Main.M18.bLimitBackwardEnable);
mcPower[2](axis:=Main.M19.Axis, Enable:=TRUE, enable_positive:=Main.M19.bLimitForwardEnable, enable_negative:=Main.M19.bLimitBackwardEnable);
mcPower[3](axis:=Main.M20.Axis, Enable:=TRUE, enable_positive:=Main.M20.bLimitForwardEnable, enable_negative:=Main.M20.bLimitBackwardEnable);
mcPower[4](axis:=Main.M21.Axis, Enable:=TRUE, enable_positive:=Main.M21.bLimitForwardEnable, enable_negative:=Main.M21.bLimitBackwardEnable);

else

//force that inner limit switch on south motor is not depressed. need to debug further in winter down.
//Main.M18.bLimitForwardEnable := TRUE;
fbSL1K0.rEncoderOffsetTop := rEncoderOffsetTop;
fbSL1K0.rEncoderOffsetBottom := rEncoderOffsetBottom;
fbSL1K0.rEncoderOffsetNorth := rEncoderOffsetNorth;
fbSL1K0.rEncoderOffsetSouth := rEncoderOffsetSouth;

fbSL1K0(stTopBlade:=  Main.M19,
        stBottomBlade:= Main.M21,
        stNorthBlade:=  Main.M20,
        stSouthBlade:=  Main.M18,
        bExecuteMotion:=bExecuteMotion,
        io_fbFFHWO := GVL.fbFastFaultOutput1,
        fbArbiter := GVL.fbArbiter);

fbSL1K0.M_UpdatePMPS(1);

END_IF

END_PROGRAM
Related:

PRG_SL2K0_POWER

PROGRAM PRG_SL2K0_POWER
VAR
    {attribute 'pytmc' := '
        pv: SL2K0:POWER
        io: io
    '}
    {attribute 'TcLinkTo' := '.RTD_South_1.iRaw := TIIB[SL2K0-EL3202-E8]^RTD Inputs Channel 1^Value;
                              .RTD_South_1.bError := TIIB[SL2K0-EL3202-E8]^RTD Inputs Channel 1^Status^Error;
                              .RTD_South_1.bUnderrange := TIIB[SL2K0-EL3202-E8]^RTD Inputs Channel 1^Status^Underrange;
                              .RTD_South_1.bOverrange := TIIB[SL2K0-EL3202-E8]^RTD Inputs Channel 1^Status^Overrange;
                              .RTD_South_2.iRaw := TIIB[SL2K0-EL3202-E8]^RTD Inputs Channel 2^Value;
                              .RTD_South_2.bError := TIIB[SL2K0-EL3202-E8]^RTD Inputs Channel 2^Status^Error;
                              .RTD_South_2.bUnderrange := TIIB[SL2K0-EL3202-E8]^RTD Inputs Channel 2^Status^Underrange;
                              .RTD_South_2.bOverrange := TIIB[SL2K0-EL3202-E8]^RTD Inputs Channel 2^Status^Overrange;
                              .RTD_TOP_1.iRaw := TIIB[SL2K0-EL3202-E9]^RTD Inputs Channel 1^Value;
                              .RTD_TOP_1.bError := TIIB[SL2K0-EL3202-E9]^RTD Inputs Channel 1^Status^Error;
                              .RTD_TOP_1.bUnderrange := TIIB[SL2K0-EL3202-E9]^RTD Inputs Channel 1^Status^Underrange;
                              .RTD_TOP_1.bOverrange := TIIB[SL2K0-EL3202-E9]^RTD Inputs Channel 1^Status^Overrange;
                              .RTD_TOP_2.iRaw := TIIB[SL2K0-EL3202-E9]^RTD Inputs Channel 2^Value;
                              .RTD_TOP_2.bError := TIIB[SL2K0-EL3202-E9]^RTD Inputs Channel 2^Status^Error;
                              .RTD_TOP_2.bUnderrange := TIIB[SL2K0-EL3202-E9]^RTD Inputs Channel 2^Status^Underrange;
                              .RTD_TOP_2.bOverrange := TIIB[SL2K0-EL3202-E9]^RTD Inputs Channel 2^Status^Overrange;
                              .RTD_North_1.iRaw := TIIB[SL2K0-EL3202-E10]^RTD Inputs Channel 1^Value;
                              .RTD_North_1.bError := TIIB[SL2K0-EL3202-E10]^RTD Inputs Channel 1^Status^Error;
                              .RTD_North_1.bUnderrange := TIIB[SL2K0-EL3202-E10]^RTD Inputs Channel 1^Status^Underrange;
                              .RTD_North_1.bOverrange := TIIB[SL2K0-EL3202-E10]^RTD Inputs Channel 1^Status^Overrange;
                              .RTD_North_2.iRaw := TIIB[SL2K0-EL3202-E10]^RTD Inputs Channel 2^Value;
                              .RTD_North_2.bError := TIIB[SL2K0-EL3202-E10]^RTD Inputs Channel 2^Status^Error;
                              .RTD_North_2.bUnderrange := TIIB[SL2K0-EL3202-E10]^RTD Inputs Channel 2^Status^Underrange;
                              .RTD_North_2.bOverrange := TIIB[SL2K0-EL3202-E10]^RTD Inputs Channel 2^Status^Overrange;
                              .RTD_Bottom_1.iRaw := TIIB[SL2K0-EL3202-E10]^RTD Inputs Channel 1^Value;
                              .RTD_Bottom_1.bError := TIIB[SL2K0-EL3202-E10]^RTD Inputs Channel 1^Status^Error;
                              .RTD_Bottom_1.bUnderrange := TIIB[SL2K0-EL3202-E11]^RTD Inputs Channel 1^Status^Underrange;
                              .RTD_Bottom_1.bOverrange := TIIB[SL2K0-EL3202-E11]^RTD Inputs Channel 1^Status^Overrange;
                              .RTD_Bottom_2.iRaw := TIIB[SL2K0-EL3202-E11]^RTD Inputs Channel 2^Value;
                              .RTD_Bottom_2.bError := TIIB[SL2K0-EL3202-E11]^RTD Inputs Channel 2^Status^Error;
                              .RTD_Bottom_2.bUnderrange := TIIB[SL2K0-EL3202-E11]^RTD Inputs Channel 2^Status^Underrange;
                              .RTD_Bottom_2.bOverrange := TIIB[SL2K0-EL3202-E11]^RTD Inputs Channel 2^Status^Overrange;
                              .AptArrayStatus := 'TIIB[PMPS_PRE]^IO Outputs^AptArrayStatus^AptArrayStatus[2];
                              .AptArrayReq := 'TIIB[PMPS_PRE]^IO Inputs^AptArrayReq^AptArrayReq[2]'}
    fbSL2K0: FB_SLITS_POWER;
//GET PMP Move Ok bit
// Default True until it is properly linked to PMPS bit
    bMoveOk:BOOL :=TRUE;
    {attribute 'pytmc' := '
    pv: SL2K0:POWER:GO;
    io: io;
    field: ZNAM False;
    field: ONAM True;
    '}
    bExecuteMotion:BOOL ;
    //for testing purposes only. comment-out/delete once done.
    mcPower : ARRAY [1..4] OF MC_POWER;
        (*Offsets*)
    (* Absolute encoder value at the HLS + Absolure eoncoder value at the centered beam *)
    rEncoderOffsetTop: REAL := 15.1;
    rEncoderOffsetBottom: REAL := -12.2;
    rEncoderOffsetNorth: REAL := 15.4;
    rEncoderOffsetSouth: REAL := -13.4;
END_VAR
fbSL2K0.bMoveOk := bMoveOk;

fbSL2K0.rEncoderOffsetTop := rEncoderOffsetTop;
fbSL2K0.rEncoderOffsetBottom := rEncoderOffsetBottom;
fbSL2K0.rEncoderOffsetNorth := rEncoderOffsetNorth;
fbSL2K0.rEncoderOffsetSouth := rEncoderOffsetSouth;

fbSL2K0(stTopBlade:=  Main.M23,
        stBottomBlade:= Main.M25,
        stNorthBlade:=  Main.M24,
        stSouthBlade:=  Main.M22,
        bExecuteMotion:=bExecuteMotion,
        io_fbFFHWO := GVL.fbFastFaultOutput1,
        fbArbiter := GVL.fbArbiter);

fbSL2K0.M_UpdatePMPS(2);


//for testing purposes only. comment-out/delete once done.
(*mcPower[1](axis:=Main.M22.Axis, Enable:=TRUE, enable_positive:=Main.M22.bLimitForwardEnable, enable_negative:=Main.M22.bLimitBackwardEnable);
mcPower[2](axis:=Main.M23.Axis, Enable:=TRUE, enable_positive:=Main.M23.bLimitForwardEnable, enable_negative:=Main.M23.bLimitBackwardEnable);
mcPower[3](axis:=Main.M24.Axis, Enable:=TRUE, enable_positive:=Main.M24.bLimitForwardEnable, enable_negative:=Main.M24.bLimitBackwardEnable);
mcPower[4](axis:=Main.M25.Axis, Enable:=TRUE, enable_positive:=Main.M25.bLimitForwardEnable, enable_negative:=Main.M25.bLimitBackwardEnable);*)

END_PROGRAM
Related:

PRG_ST1K4_TEST

PROGRAM PRG_ST1K4_TEST
VAR
    fbMotion: FB_MotionStage;

    {attribute 'pytmc' := '
        pv: ST1K4:TEST:MMS
        astPositionState.array: 1..2
    '}
    fbStates: FB_PositionState1D;

    fbStateSetup: FB_StateSetupHelper;
    stDefault: ST_PositionState := (
        fDelta := 1,
        fVelocity := 5,
        bMoveOk := TRUE,
        bValid := TRUE
    );
    astPositionState: ARRAY[1..GeneralConstants.MAX_STATES] OF ST_PositionState;

    {attribute 'pytmc' := '
        pv: ST1K4:TEST:MMS:STATE:GET
        io: i
    '}
    eEnumGet: E_EpicsInOut;
    {attribute 'pytmc' := '
        pv: ST1K4:TEST:MMS:STATE:SET
        io: io
    '}
    eEnumSet: E_EpicsInOut;

    bST3K4_in: BOOL;

    {attribute 'pytmc' := '
        pv: ST1K4:TEST:MMS:STATE:ST3K4_AUTO
        io: io
    '}
    bST3K4_auto: BOOL := TRUE;
END_VAR
// M33, Axis 33
Main.M33.nEnableMode := ENUM_StageEnableMode.DURING_MOTION;
Main.M33.bHardwareEnable:= TRUE;
Main.M33.bPowerSelf := TRUE;
Main.M33.nBrakeMode := ENUM_StageBrakeMode.IF_ENABLED;
fbMotion(stMotionStage:=Main.M33);

// States
fbStateSetup(stPositionState:=stDefault, bSetDefault:=TRUE);

fbStateSetup(stPositionState:=astPositionState[E_EpicsInOut.IN], sName:='IN', fPosition:=2);
fbStateSetup(stPositionState:=astPositionState[E_EpicsInOut.OUT], sName:='OUT', fPosition:=40);

fbStates(
    stMotionStage:=Main.M33,
    astPositionState:=astPositionState,
    eEnumSet:=eEnumSet,
    eEnumGet:=eEnumGet,
    bEnable:=TRUE,
);

bST3K4_in := PMPS_GVL.stCurrentBeamParameters.aVetoDevices[PMPS.K_Stopper.ST3K4];

IF bST3K4_auto THEN
    IF bST3K4_in AND eEnumGet <> E_EpicsInOut.IN THEN
        eEnumSet := ENUM_EpicsInOut.IN;
    ELSIF NOT bST3K4_in AND eEnumGet <> E_EpicsInOut.OUT THEN
        eEnumSet := ENUM_EpicsInOut.OUT;
    END_IF
END_IF

END_PROGRAM
Related: