DUTs

DUT_MotionStage_Extras

TYPE DUT_MotionStage_Extras :
STRUCT
    fVisuStep: LREAL;
    bVisuLowLim: BOOL;
    bVisuHighLim: BOOL;
END_STRUCT
END_TYPE
Related:

ENUM_SXR_SATT_Position

{attribute 'qualified_only'}
TYPE ENUM_SXR_SATT_Position :
(
    UNKNOWN := 0, // UNKNOWN must be in slot 0 or the FB breaks
    OUT := 1, // OUT at slot 1 is a convention
    FILTER1 := 2,
    FILTER2 := 3,
    FILTER3 := 4,
    FILTER4 := 5
);
END_TYPE

GVLs

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
*)
(*
    Four identical systems:
    Instr.          Area            ID#                     Z (m)
    TMO                     FEE                     AT1K4-SOLID     748
    NEH 2.2         H2.2            AT1K2-SOLID     784
    NEH 2.2         H2.2            AT2K2-SOLID     788.8
    TXI                     H1.1            AT1K3-SOLID     ~763

*)
    {attribute 'pytmc' := 'pv: AT1K4:L2SI:MMS:01'}
    {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;
    '}
    M1: DUT_MotionStage := (sName := 'AT1K4:L2SI:MMS:01');

    {attribute 'pytmc' := 'pv: AT1K4:L2SI:MMS:02'}
    {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;
    '}
    M2: DUT_MotionStage := (sName := 'AT1K4:L2SI:MMS:02');

    {attribute 'pytmc' := 'pv: AT1K4:L2SI:MMS:03'}
    {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;
    '}
    M3: DUT_MotionStage := (sName := 'AT1K4:L2SI:MMS:03');

    {attribute 'pytmc' := 'pv: AT1K4:L2SI:MMS:04'}
    {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;
    '}
    M4: DUT_MotionStage := (sName := 'AT1K4:L2SI:MMS:04');

END_VAR

POUs

FB_SXR_SATT_PositionState

FUNCTION_BLOCK FB_SXR_SATT_PositionState EXTENDS FB_PositionStateBase
VAR_INPUT
     // The enum position to move to
     {attribute 'pytmc' := '
         pv: SET
         io: io
     '}
     enumSet: ENUM_SXR_SATT_Position;

    // NOTE: Do not pragma these, let it happen in the manager.
     // Information about the OUT position
     stOut          : DUT_PositionState;
     stFilter1      : DUT_PositionState;
     stFilter2      : DUT_PositionState;
     stFilter3      : DUT_PositionState;
     stFilter4      : DUT_PositionState;

END_VAR
VAR_OUTPUT
    // The enum state readback
    {attribute 'pytmc' := '
        pv: GET
        io: i
    '}
    enumGet: ENUM_SXR_SATT_Position;
END_VAR
VAR
    bInitialized: BOOL := FALSE;
END_VAR
IF NOT bInitialized THEN
    bInitialized := TRUE;

    arrStates[1] := stOut;
    arrStates[2] := stFilter1;
    arrStates[3] := stFilter2;
    arrStates[4] := stFilter3;
    arrStates[5] := stFilter4;

END_IF
setState := enumSet;
Exec();
enumGet := getState;
enumSet := setState;

END_FUNCTION_BLOCK
Related:

FB_SXR_SATT_Stage

FUNCTION_BLOCK FB_SXR_SATT_Stage
VAR_IN_OUT
    stAxis : DUT_MotionStage;
END_VAR
VAR_INPUT
    nEnableMode : ENUM_StageEnableMode;

    stOut           : DUT_PositionState;
    stFilter1       : DUT_PositionState;
    stFilter2       : DUT_PositionState;
    stFilter3       : DUT_PositionState;
    stFilter4       : DUT_PositionState;
END_VAR
VAR_OUTPUT
    stExtra : DUT_MotionStage_Extras;
    fTemp1 : LREAL;
    fTemp2 : LREAL;
END_VAR
VAR
    // TODO: debug
    // fbMotion: FB_MotionStage;
    fbMotion: FB_MotionStageSim;

    {attribute 'pytmc' := '
         pv: STATE
    '}
    fbState         : FB_SXR_SATT_PositionState;

    bInitialized: BOOL := FALSE;

    (* EL3202-0020: 0.01 °C per digit *)
    {attribute 'pytmc' := 'pv: RTD:1'}
    fbRTD_1: FB_TempSensor := ( fResolution:=0.01 );
    {attribute 'pytmc' := 'pv: RTD:2'}
    fbRTD_2: FB_TempSensor := ( fResolution:=0.01 );

END_VAR
IF NOT bInitialized THEN
    bInitialized := TRUE;

    (* Defaults for DUT_MotionStage *)
    stAxis.bHardwareEnable      := TRUE;
    stAxis.bLimitBackwardEnable := TRUE;
    stAxis.bLimitForwardEnable  := TRUE;
    stAxis.bPowerSelf           := TRUE;
    stAxis.nBrakeMode           := ENUM_StageBrakeMode.NO_BRAKE;
    stAxis.nHomingMode          := ENUM_EpicsHomeCmd.NONE;

    (* Defaults for visualization *)
    stExtra.fVisuStep                       := 0.1;

END_IF

fbRTD_1();
fTemp1 := fbRTD_1.fTemp;

fbRTD_2();
fTemp2 := fbRTD_2.fTemp;

stAxis.nEnableMode := nEnableMode;
fbMotion(stMotionStage:=stAxis);
fbState(
    bEnable:=TRUE,
    bReset:=FALSE,
    stMotionStage:=stAxis,
    stOut:=stOut,
    stFilter1:=stFilter1,
    stFilter2:=stFilter2,
    stFilter3:=stFilter3,
    stFilter4:=stFilter4
);

stExtra.bVisuHighLim := NOT stAxis.bAllForwardEnable;
stExtra.bVisuLowLim := NOT stAxis.bAllBackwardEnable;

END_FUNCTION_BLOCK
Related:

PRG_1_PlcTask

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

PRG_2_AT1K4();

END_PROGRAM
Related:

PRG_2_AT1K4

PROGRAM PRG_2_AT1K4
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-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;

    '}
    fbStage1: FB_SXR_SATT_Stage;

    {attribute 'pytmc' := 'pv: AT1K4:L2SI:MMS:02'}
    {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;

    '}
    fbStage2: FB_SXR_SATT_Stage;

    {attribute 'pytmc' := 'pv: AT1K4:L2SI:MMS:03'}
    {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;
    '}
    fbStage3: FB_SXR_SATT_Stage;

    {attribute 'pytmc' := 'pv: AT1K4:L2SI:MMS:04'}
    {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;
    '}
    fbStage4: FB_SXR_SATT_Stage;

END_VAR
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

(* State setup - stage 1 *)
fbStage1.stOut.sName         := 'Out';
fbStage1.stOut.fPosition     := 50;
fbStage1.stOut.fDelta        := 100;
fbStage1.stOut.fVelocity     := 10;
fbStage1.stOut.bValid        := TRUE;
fbStage1.stOut.bMoveOk       := TRUE;

fbStage1.stFilter1.sName     := 'Filter 1';
fbStage1.stFilter1.fPosition := 500;
fbStage1.stFilter1.fDelta    := 0;
fbStage1.stFilter1.fVelocity := 10;
fbStage1.stFilter1.bValid    := FALSE;
fbStage1.stFilter1.bMoveOk   := FALSE;

fbStage1.stFilter2.sName     := 'Filter 2';
fbStage1.stFilter2.fPosition := 500;
fbStage1.stFilter2.fDelta    := 0;
fbStage1.stFilter2.fVelocity := 10;
fbStage1.stFilter2.bValid    := FALSE;
fbStage1.stFilter2.bMoveOk   := FALSE;

fbStage1.stFilter3.sName     := 'Filter 3';
fbStage1.stFilter3.fPosition := 500;
fbStage1.stFilter3.fDelta    := 0;
fbStage1.stFilter3.fVelocity := 10;
fbStage1.stFilter3.bValid    := FALSE;
fbStage1.stFilter3.bMoveOk   := FALSE;

fbStage1.stFilter4.sName     := 'Filter 4';
fbStage1.stFilter4.fPosition := 500;
fbStage1.stFilter4.fDelta    := 0;
fbStage1.stFilter4.fVelocity := 10;
fbStage1.stFilter4.bValid    := FALSE;
fbStage1.stFilter4.bMoveOk   := FALSE;

fbStage1(stAxis:=Main.M1, nEnableMode:=nEnableMode);

(* State setup - stage 2 *)
fbStage2.stOut.sName         := 'Out';
fbStage2.stOut.fPosition     := 50;
fbStage2.stOut.fDelta        := 100;
fbStage2.stOut.fVelocity     := 10;
fbStage2.stOut.bValid        := TRUE;
fbStage2.stOut.bMoveOk       := TRUE;

fbStage2.stFilter1.sName     := 'Filter 1';
fbStage2.stFilter1.fPosition := 500;
fbStage2.stFilter1.fDelta    := 0;
fbStage2.stFilter1.fVelocity := 10;
fbStage2.stFilter1.bValid    := FALSE;
fbStage2.stFilter1.bMoveOk   := FALSE;

fbStage2.stFilter2.sName     := 'Filter 2';
fbStage2.stFilter2.fPosition := 500;
fbStage2.stFilter2.fDelta    := 0;
fbStage2.stFilter2.fVelocity := 10;
fbStage2.stFilter2.bValid    := FALSE;
fbStage2.stFilter2.bMoveOk   := FALSE;

fbStage2.stFilter3.sName     := 'Filter 3';
fbStage2.stFilter3.fPosition := 500;
fbStage2.stFilter3.fDelta    := 0;
fbStage2.stFilter3.fVelocity := 10;
fbStage2.stFilter3.bValid    := FALSE;
fbStage2.stFilter3.bMoveOk   := FALSE;

fbStage2.stFilter4.sName     := 'Filter 4';
fbStage2.stFilter4.fPosition := 500;
fbStage2.stFilter4.fDelta    := 0;
fbStage2.stFilter4.fVelocity := 10;
fbStage2.stFilter4.bValid    := FALSE;
fbStage2.stFilter4.bMoveOk   := FALSE;

fbStage2(stAxis:=Main.M2, nEnableMode:=nEnableMode);

(* State setup - stage 3 *)
fbStage3.stOut.sName         := 'Out';
fbStage3.stOut.fPosition     := 50;
fbStage3.stOut.fDelta        := 100;
fbStage3.stOut.fVelocity     := 10;
fbStage3.stOut.bValid        := TRUE;
fbStage3.stOut.bMoveOk       := TRUE;

fbStage3.stFilter1.sName     := 'Filter 1';
fbStage3.stFilter1.fPosition := 500;
fbStage3.stFilter1.fDelta    := 0;
fbStage3.stFilter1.fVelocity := 10;
fbStage3.stFilter1.bValid    := FALSE;
fbStage3.stFilter1.bMoveOk   := FALSE;

fbStage3.stFilter2.sName     := 'Filter 2';
fbStage3.stFilter2.fPosition := 500;
fbStage3.stFilter2.fDelta    := 0;
fbStage3.stFilter2.fVelocity := 10;
fbStage3.stFilter2.bValid    := FALSE;
fbStage3.stFilter2.bMoveOk   := FALSE;

fbStage3.stFilter3.sName     := 'Filter 3';
fbStage3.stFilter3.fPosition := 500;
fbStage3.stFilter3.fDelta    := 0;
fbStage3.stFilter3.fVelocity := 10;
fbStage3.stFilter3.bValid    := FALSE;
fbStage3.stFilter3.bMoveOk   := FALSE;

fbStage3.stFilter4.sName     := 'Filter 4';
fbStage3.stFilter4.fPosition := 500;
fbStage3.stFilter4.fDelta    := 0;
fbStage3.stFilter4.fVelocity := 10;
fbStage3.stFilter4.bValid    := FALSE;
fbStage3.stFilter4.bMoveOk   := FALSE;

fbStage3(stAxis:=Main.M3, nEnableMode:=nEnableMode);

(* State setup - stage 4 *)
fbStage4.stOut.sName         := 'Out';
fbStage4.stOut.fPosition     := 50;
fbStage4.stOut.fDelta        := 100;
fbStage4.stOut.fVelocity     := 10;
fbStage4.stOut.bValid        := TRUE;
fbStage4.stOut.bMoveOk       := TRUE;

fbStage4.stFilter1.sName     := 'Filter 1';
fbStage4.stFilter1.fPosition := 500;
fbStage4.stFilter1.fDelta    := 0;
fbStage4.stFilter1.fVelocity := 10;
fbStage4.stFilter1.bValid    := FALSE;
fbStage4.stFilter1.bMoveOk   := FALSE;

fbStage4.stFilter2.sName     := 'Filter 2';
fbStage4.stFilter2.fPosition := 500;
fbStage4.stFilter2.fDelta    := 0;
fbStage4.stFilter2.fVelocity := 10;
fbStage4.stFilter2.bValid    := FALSE;
fbStage4.stFilter2.bMoveOk   := FALSE;

fbStage4.stFilter3.sName     := 'Filter 3';
fbStage4.stFilter3.fPosition := 500;
fbStage4.stFilter3.fDelta    := 0;
fbStage4.stFilter3.fVelocity := 10;
fbStage4.stFilter3.bValid    := FALSE;
fbStage4.stFilter3.bMoveOk   := FALSE;

fbStage4.stFilter4.sName     := 'Filter 4';
fbStage4.stFilter4.fPosition := 500;
fbStage4.stFilter4.fDelta    := 0;
fbStage4.stFilter4.fVelocity := 10;
fbStage4.stFilter4.bValid    := FALSE;
fbStage4.stFilter4.bMoveOk   := FALSE;

fbStage4(stAxis:=Main.M4, nEnableMode:=nEnableMode);

END_PROGRAM
Related: