DUTs
E_DeviceState
{attribute 'qualified_only'}
TYPE E_DeviceState :
(
INVALID := 0,
INIT := EC_DEVICE_STATE_INIT,
PREOP := EC_DEVICE_STATE_PREOP,
BOOTSTRAP := EC_DEVICE_STATE_BOOTSTRAP,
SAFEOP := EC_DEVICE_STATE_SAFEOP,
OP := EC_DEVICE_STATE_OP
) WORD := INVALID;
END_TYPE
- Related:
E_LeakLocation
{attribute 'qualified_only'}
{attribute 'strict'}
TYPE E_LeakLocation :
(
NO_LEAK := 0,
LOC1 := 1,
LOC2 := 2,
LOC3 := 4,
LOC4 := 8,
LOC5 := 16,
LOC6 := 32
) BYTE;
END_TYPE
ST_DeviceDiagnostic
// PLC Terminal device diagnostics
TYPE ST_DeviceDiagnostic :
STRUCT
{attribute 'pytmc' := '
pv: TYPE
io: i
'}
sType : STRING[15];
{attribute 'pytmc' := '
pv: ADDRESS
io: i
'}
nAddr : WORD;
{attribute 'pytmc' := '
pv: NAME
io: i
'}
sName : STRING[31];
{attribute 'pytmc' := '
pv: DEVICE_STATE
io: i
field: ZRVL 0
field: ONVL 1
field: TWVL 2
field: THVL 3
field: FRVL 4
field: SXVL 8
field: ZRST INVALID
field: ONST INIT
field: TWST PREOP
field: THST BOOTSTRAP
field: FRST SAFEOP
field: SXST OP
field: ZRSV MAJOR
field: ONSV MAJOR
field: TWSV MAJOR
field: THSV MAJOR
field: FRSV MAJOR
field: FVSV MINOR
field: SXSV NO_ALARM
field: UNSV MAJOR
'}
nDeviceState : ENUM;
{attribute 'pytmc' := '
pv: DEVICE_STATE_FLAGS
io: i
'}
nDeviceStateFlags : BYTE;
{attribute 'pytmc' := '
pv: LINK_STATE_FLAGS
io: i
'}
nLinkStateFlags : BYTE;
END_STRUCT
END_TYPE
ST_ErrorStates
// Error states that can occur in the program
TYPE ST_ErrorStates :
STRUCT
// Leak Alarms
bLeakOpticalTableAmphosOn : BOOL; // Leak on the optical table with Amphos on
bLeakOpticalTableNoLaser : BOOL; // Leak on the optical table with no laser on
bLeakOpcpaCarbideOn : BOOL; // Leak inside the OPCPA with Carbide on
bLeakUnderTable : BOOL; // Leak under the table
bLeakInsideRacks : BOOL; // Leak inside the racks
// Temperature loop alarms
bChillerLoop01 : BOOL; // Temperature too high in loop 01
bChillerLoop02 : BOOL; // Temperature too high in loop 02
bChillerLoop03 : BOOL; // Temperature too high in loop 03
bChillerLoop04 : BOOL; // Temperature too high in loop 04
// Beam Errors
bAmphosBeam : BOOL; // Amphos beam error
bOpcpaBeam : BOOL; // OPCPA beam error
(*
// Temperature monitors
bTempMon01 : BOOL; // Temperature too high at location 01
bTempMon02 : BOOL; // Temperature too high at location 02
bTempMon03 : BOOL; // Temperature too high at location 03
bTempMon04 : BOOL; // Temperature too high at location 04
bTempMon05 : BOOL; // Temperature too high at location 05
bTempMon06 : BOOL; // Temperature too high at location 06
bTempMon07 : BOOL; // Temperature too high at location 07
bTempMon08 : BOOL; // Temperature too high at location 08
*)
// Dump chiller
bDumpChiller : BOOL; // Dump chiller error
bBaseplateChiller : BOOL; // Baseplate chiller error
(*
// Amphos MRC
bAmphosMRC01 : BOOL; // Amphos MRC 01 Error
bAmphosMRC02 : BOOL; // Amphos MRC 01 Error
bAmphosMRC03 : BOOL; // Amphos MRC 01 Error
*)
// Hardware Failure
bHardwareFailure : BOOL; // A component of the EPS has failed
END_STRUCT
END_TYPE
ST_LaserSetpoints
// Setpoints for the lasers
TYPE ST_LaserSetpoints :
STRUCT
{attribute 'pytmc' := '
pv: MIN_VOLTAGE
io: io
field: EGU Volts
'}
nMinVoltage : LREAL; // Minimum voltage the laser will be allowed to operate at
{attribute 'pytmc' := '
pv: MIN_NOMINAL_VOLTAGE
io: io
field: EGU Volts
'}
nMinNominalVoltage : LREAL; // Minimum voltage for the laser to be operating nominally
END_STRUCT
END_TYPE
ST_LeakBoundaries
// Boundaries indicating leak monitor locations
TYPE ST_LeakBoundaries :
STRUCT
{attribute 'pytmc' := '
pv: L_MIN01
io: io
'}
nLMin1 : UINT;
{attribute 'pytmc' := '
pv: L_MAX01
io: io
'}
nLMax1 : UINT;
{attribute 'pytmc' := '
pv: L_MIN02
io: io
'}
nLMin2 : UINT;
{attribute 'pytmc' := '
pv: L_MAX02
io: io
'}
nLMax2 : UINT;
{attribute 'pytmc' := '
pv: L_MIN03
io: io
'}
nLMin3 : UINT;
{attribute 'pytmc' := '
pv: L_MAX03
io: io
'}
nLMax3 : UINT;
{attribute 'pytmc' := '
pv: L_MIN04
io: io
'}
nLMin4 : UINT;
{attribute 'pytmc' := '
pv: L_MAX04
io: io
'}
nLMax4 : UINT;
{attribute 'pytmc' := '
pv: L_MIN05
io: io
'}
nLMin5 : UINT;
{attribute 'pytmc' := '
pv: L_MAX05
io: io
'}
nLMax5 : UINT;
{attribute 'pytmc' := '
pv: L_MIN06
io: io
'}
nLMin6 : UINT;
{attribute 'pytmc' := '
pv: L_MAX06
io: io
'}
nLMax6 : UINT;
END_STRUCT
END_TYPE
ST_TemperatureMonitorSetpoints
// Setpoints for the temperature monitors
TYPE ST_TemperatureMonitorSetpoints :
STRUCT
{attribute 'pytmc' := '
pv: MAX_TEMP
io: io
field: EGU C
'}
fMaxTemperature : LREAL; // Maximum temperature in Celsius allowed before triggering error
END_STRUCT
END_TYPE
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_EPS : ST_LibVersion := (iMajor := 0, iMinor := 0, iBuild := 0, iRevision := 0, sVersion := '0.0.0');
END_VAR
GVL_EL3174
{attribute 'qualified_only'}
VAR_GLOBAL CONSTANT
(* Analog scaling *)
fRawUpperLimit : LREAL := 16#7736; // Highest raw signal that can be read
fRawLowerLimit : LREAL := 16#0000; // Lowest raw signal that can be read
fScaleUpperLimit : LREAL := 10; // Upper limit in volts
fScaleLowerLimit : LREAL := 0; // Lower limit in volts
END_VAR
GVL_IO
// PLC IO from terminal modules
{attribute 'qualified_only'}
VAR_GLOBAL
(* CX2020 *)
(* Slot1 EL3174 *)
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E01_EL3174]^AI Standard Channel 1^Value'}
nOpcpaVoltageRaw AT %I* : INT; // Ch1
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E01_EL3174]^AI Standard Channel 2^Value'}
nAmphosVoltageRaw AT %I* : INT; // Ch2
(* Slot2 EL3174 *)
(* Slot3 EL9189 *)
(* Slot4 EL9184 *)
(*
(* Slot5 EL3174 *)
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E05_EL3174]^AI Standard Channel 1^Value'}
nTempMonRaw01 AT %I* : INT; // Ch1
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E05_EL3174]^AI Standard Channel 2^Value'}
nTempMonRaw02 AT %I* : INT; // Ch2
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E05_EL3174]^AI Standard Channel 3^Value'}
nTempMonRaw03 AT %I* : INT; // Ch3
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E05_EL3174]^AI Standard Channel 4^Value'}
nTempMonRaw04 AT %I* : INT; // Ch4
(* Slot6 EL3174 *)
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E06_EL3174]^AI Standard Channel 1^Value'}
nTempMonRaw05 AT %I* : INT; // Ch1
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E06_EL3174]^AI Standard Channel 2^Value'}
nTempMonRaw06 AT %I* : INT; // Ch2
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E06_EL3174]^AI Standard Channel 3^Value'}
nTempMonRaw07 AT %I* : INT; // Ch3
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E06_EL3174]^AI Standard Channel 4^Value'}
nTempMonRaw08 AT %I* : INT; // Ch4
*)
(* Slot7 EL1259 Inputs *)
{attribute 'pytmc' := '
pv: @(PREFIX):LPS:AMPHOS:POWER_STATE
io: i
field: ZNAM "OFF"
field: ONAM "ON"
'}
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E07_EL1259]^MTI Inputs 10x Channel 1^Status^Input state'}
bAmphosOn AT %I* : BOOL; // Ch1
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E07_EL1259]^MTI Inputs 10x Channel 2^Status^Input state'}
bLeakDetected AT %I* : BOOL; // Ch2
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E07_EL1259]^MTI Inputs 10x Channel 3^Status^Input state'}
bLoopTempSW01 AT %I* : BOOL; // Ch3 Loop 01 NC Temp switch
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E07_EL1259]^MTI Inputs 10x Channel 4^Status^Input state'}
bLoopTempSW02 AT %I* : BOOL; // Ch4 Loop 02 NC Temp switch
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E07_EL1259]^MTI Inputs 10x Channel 5^Status^Input state'}
bLoopTempSW03 AT %I* : BOOL; // Ch5 Loop 03 NC Temp switch
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E07_EL1259]^MTI Inputs 10x Channel 6^Status^Input state'}
bLoopTempSW04 AT %I* : BOOL; // Ch6 Loop 04 NC Temp switch
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E07_EL1259]^MTI Inputs 10x Channel 7^Status^Input state'}
bBaseplateChillerFlow AT %I* : BOOL; // Ch7 Baseplate chiller NC flow sensor
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E07_EL1259]^MTI Inputs 10x Channel 8^Status^Input state'}
bDumpChillerFlow AT %I* : BOOL; // Ch2 Dump chiller NC flow sensor
(* Slot7 EL1259 Outputs *)
(*
{attribute 'pytmc' := '
pv: @(PREFIX):LPS:AMPHOS_ATTENUATOR:ENABLE
io: i
field: OSV NO_ALARM
field: ZSV MAJOR
field: ZNAM DISABLED
field: ONAM ENABLED
'}
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E06]^Channel 1^Output'}
bAmphosAttenuatorEnable AT %Q* : BOOL; // Ch1
bAmphosAttenuatorEnableManualOperation AT %Q* : BOOL := TRUE;
*)
{attribute 'pytmc' := '
pv: @(PREFIX):LPS:AMPHOS_SHUTTER:ENABLE
io: i
field: OSV NO_ALARM
field: ZSV MAJOR
field: ZNAM DISABLED
field: ONAM ENABLED
'}
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E07_EL1259]^MTO Outputs 10x Channel 1^Ctrl^Manual output state'}
bAmphosShutterEnable AT %Q* : BOOL; // Ch1
bAmphosShutterEnableManualOperation AT %Q* : BOOL := TRUE;
(* Slot8 EL9184 *)
(* Slot9 EL1259 *)
(* Slot10 EL9184 *)
(* Slot11 ES2624 *)
{attribute 'pytmc' := '
pv: @(PREFIX):LPS:DUMP_CHILLER_RELAY:ENABLE
io: i
field: OSV NO_ALARM
field: ZSV MAJOR
field: ZNAM DISABLED
field: ONAM ENABLED
'}
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E11_EL2624]^Channel 1^Output'}
bDumpChillerRelay AT %Q* : BOOL; // Ch1 Dump chiller NC relay
{attribute 'pytmc' := '
pv: @(PREFIX):LPS:BASEPLATE_CHILLER_RELAY:ENABLE
io: i
field: OSV NO_ALARM
field: ZSV MAJOR
field: ZNAM DISABLED
field: ONAM ENABLED
'}
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E11_EL2624]^Channel 2^Output'}
bBaseplateChillerRelay AT %Q* : BOOL; // Ch2 Baseplate chiller NC relay
{attribute 'pytmc' := '
pv: @(PREFIX):LPS:AMPHOS_RELAY:ENABLE
io: i
field: OSV NO_ALARM
field: ZSV MAJOR
field: ZNAM DISABLED
field: ONAM ENABLED
'}
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E11_EL2624]^Channel 3^Output'}
bAmphosRelay AT %Q* : BOOL; // Ch3 Amphos Interlock relay
{attribute 'pytmc' := '
pv: @(PREFIX):LPS:CARBIDE_SHUTTER:ENABLE
io: i
field: OSV NO_ALARM
field: ZSV MAJOR
field: ZNAM DISABLED
field: ONAM ENABLED
'}
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E11_EL2624]^Channel 4^Output'}
bCarbideShutterEnable AT %Q* : BOOL; // Ch4 HASS
bCarbideShutterEnableManualOperation AT %Q* : BOOL := TRUE;
(* Slot12 EL6022 *)
(* Slot13 EL9505 *)
(* Slot14 EL1124 *)
{attribute 'pytmc' := '
pv: @(PREFIX):LPS:OPCPA:POWER_STATE
io: i
field: ZNAM "OFF"
field: ONAM "ON"
'}
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E14_EL1124]^Channel 1^Input'}
bCarbideOn AT %I* : BOOL; // Ch1
(*
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E14_EL1124]^Channel 2^Input'}
bAmphosMRC01 AT %I* : BOOL; // Ch2 NC Amphos MRC switch
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E14_EL1124]^Channel 3^Input'}
bAmphosMRC02 AT %I* : BOOL; // Ch3 NC Amphos MRC switch
{attribute 'TcLinkTo' := 'TIIB[LPS_PLC_E14_EL1124]^Channel 4^Input'}
bAmphosMRC03 AT %I* : BOOL; // Ch4 NC Amphos MRC switch
*)
END_VAR
GVL_Laser
// Setpoints for lasers
{attribute 'qualified_only'}
VAR_GLOBAL PERSISTENT
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:AMPHOS'}
stAmphosSP : ST_LaserSetpoints; // Amphos setpoints
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:OPCPA'}
stOpcpaSP : ST_LaserSetpoints; // OPCPA setpoints
END_VAR
- Related:
GVL_PLC
// PLC global variables
{attribute 'qualified_only'}
VAR_GLOBAL
AMSNetId AT %I* : AMSNETID;
END_VAR
GVL_TemperatureMonitor
// Temperature monitor setpoints
{attribute 'qualified_only'}
VAR_GLOBAL PERSISTENT
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:TEMPMON01'}
stTempMonSP01 : ST_TemperatureMonitorSetpoints;
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:TEMPMON02'}
stTempMonSP02 : ST_TemperatureMonitorSetpoints;
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:TEMPMON03'}
stTempMonSP03 : ST_TemperatureMonitorSetpoints;
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:TEMPMON04'}
stTempMonSP04 : ST_TemperatureMonitorSetpoints;
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:TEMPMON05'}
stTempMonSP05 : ST_TemperatureMonitorSetpoints;
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:TEMPMON06'}
stTempMonSP06 : ST_TemperatureMonitorSetpoints;
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:TEMPMON07'}
stTempMonSP07 : ST_TemperatureMonitorSetpoints;
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:TEMPMON08'}
stTempMonSP08 : ST_TemperatureMonitorSetpoints;
END_VAR
- Related:
GVL_TraceTek
// Global variables for the TraceTek leak detector
{attribute 'qualified_only'}
VAR_GLOBAL CONSTANT
(* Modbus address *)
nModbusSlaveAddress : BYTE := 199; // Modbus slave address of the TraceTek device
END_VAR
VAR_GLOBAL PERSISTENT
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:LEAK'}
stLeakMonitorBoundaries : ST_LeakBoundaries; // Boundaries of possible leak locations
END_VAR
- Related:
POUs
F_AmphosAttenuatorEnable
// Interlock logic for the Amphos attenuator
FUNCTION F_AmphosAttenuatorEnable : BOOL
VAR_INPUT
bAmphosOn : BOOL; // Whether the Amphos is turned on
END_VAR
VAR_IN_OUT CONSTANT
stErrors : ST_ErrorStates; // Currently detected errors
END_VAR
VAR
END_VAR
IF stErrors.bHardwareFailure // Close attenuator if there is a hardware failure
OR NOT bAmphosOn // Close attenuator if Amphos is not on
OR stErrors.bLeakOpticalTableAmphosOn OR stErrors.bLeakOpcpaCarbideOn (* OR stErrors.bLeakUnderTable *) // Close attenuator if there is a leak on the optical table with amphos on, there is a leak in the OPCPA with the carbide on, or there is a leak under the table
(* OR stErrors.bAmphosMRC01 // Close attenuator if there is an AmphosMRC01 error *)
THEN
F_AmphosAttenuatorEnable := FALSE;
ELSE
F_AmphosAttenuatorEnable := TRUE;
END_IF
END_FUNCTION
- Related:
F_AmphosEnable
// Interlock logic for the Amphos relay
FUNCTION F_AmphosEnable : BOOL
VAR_INPUT
fAmphosVoltage : LREAL; // The Amphos voltage
bEnabled : BOOL; // Whether the amphos enable signal is currently on
bMasterOverride : BOOL; //Master manual override control input
END_VAR
VAR_IN_OUT CONSTANT
stAmphosSetpoints : ST_LaserSetpoints; // The Amphos setpoints
stErrors : ST_ErrorStates; // Currently detected errors
END_VAR
IF (stErrors.bHardwareFailure // Disable Amphos if there is a hardware failure
OR stErrors.bAmphosBeam // Disable Amphos if there is a beam error
OR stErrors.bAmphosBeam AND NOT bEnabled) // Once amphos is disabled, keep it disabled until beam error is reset
AND NOT bMasterOverride //if master override is TRUE, ignore all errors
THEN
F_AmphosEnable := FALSE;
ELSE
F_AmphosEnable := TRUE;
END_IF
END_FUNCTION
- Related:
F_AmphosShutterEnable
// Interlock logic for the Amphos shutter
FUNCTION F_AmphosShutterEnable : BOOL
VAR_INPUT
bAmphosOn : BOOL; // Whether the amphos is on
fOpcpaVoltage : LREAL; // The voltage of the OPCPA
bLoopTempOverride01 : BOOL; // Whether the chiller loop error is overriden
bLoopTempOverride02 : BOOL; // Whether the chiller loop error is overriden
bLoopTempOverride03 : BOOL; // Whether the chiller loop error is overriden
bLoopTempOverride04 : BOOL; // Whether the chiller loop error is overriden
bMasterOverride : BOOL; //Master manual override control input
bAmpShutterClosed : BOOL; //Master Amphos shutter control. TRUE = Closed
END_VAR
VAR_IN_OUT CONSTANT
stErrors : ST_ErrorStates; // Currently detected errors
stOpcpaSetpoints : ST_LaserSetpoints; // OPCPA setpoints
END_VAR
VAR
END_VAR
IF (stErrors.bHardwareFailure // Close shutter if there is a hardware failure
OR stErrors.bLeakOpticalTableAmphosOn OR stErrors.bLeakOpcpaCarbideOn (* OR stErrors.bLeakUnderTable *) // Close shutter if there is a leak on the optical table with the amphos on, a leak under the table, or a leak inside the OPCPA with Carbide on
OR bAmphosOn AND (
(NOT bLoopTempOverride01 AND stErrors.bChillerLoop01) OR
(NOT bLoopTempOverride02 AND stErrors.bChillerLoop02) OR
(NOT bLoopTempOverride03 AND stErrors.bChillerLoop03) OR
(NOT bLoopTempOverride04 AND stErrors.bChillerLoop04)) // Close shutter if the amphos is on and the temperature is too high in any loop. Ignore if operator override is enabled
OR (stErrors.bOpcpaBeam) // Close shutter if in OPCPA beam error state and OPCPA voltage too low
(*OR stErrors.bTempMon01 OR stErrors.bTempMon02 OR stErrors.bTempMon03 OR stErrors.bTempMon04 OR stErrors.bTempMon05 OR
stErrors.bTempMon06 OR stErrors.bTempMon07 OR stErrors.bTempMon08 // Close shutter if temperature too high at any monitor location *)
OR stErrors.bDumpChiller) // Close shutter if there is a Dump Chiller error
(* OR stErrors.bAmphosMRC02 OR stErrors.bAmphosMRC03 // Close shutter if there are errors on the additional MRCs *)
AND NOT bMasterOverride //if master override is TRUE, ignore all errors
THEN
F_AmphosShutterEnable := FALSE;
ELSIF bMasterOverride AND bAmpShutterClosed THEN
F_AmphosShutterEnable := FALSE;
ELSIF bMasterOverride AND NOT bAmpShutterClosed THEN
F_AmphosShutterEnable := TRUE;
ELSE
F_AmphosShutterEnable := TRUE;
END_IF
END_FUNCTION
- Related:
F_BaseplateChillerEnable
// Interlock logic for the Baseplate Chiller
FUNCTION F_BaseplateChillerEnable : BOOL
VAR_INPUT
bMasterOverride : BOOL; //Master manual override control input
END_VAR
VAR_IN_OUT CONSTANT
stErrors : ST_ErrorStates; // Currently detected errors
END_VAR
VAR
END_VAR
IF (stErrors.bHardwareFailure // Disable baseplate chiller if there is a hardware failure
(* OR stErrors.bLeakUnderTable *) OR stErrors.bLeakOpcpaCarbideOn) // Disable baseplate chiller if there is a leak under the table
AND NOT bMasterOverride //if master override is TRUE, ignore all errors
THEN
F_BaseplateChillerEnable := FALSE;
ELSE
F_BaseplateChillerEnable := TRUE;
END_IF
END_FUNCTION
- Related:
F_CarbideShutterEnable
// Interlock logic for the Carbide Shutter
FUNCTION F_CarbideShutterEnable : BOOL
VAR_INPUT
bMasterOverride : BOOL; //Master manual override control input
END_VAR
VAR_IN_OUT CONSTANT
stErrors : ST_ErrorStates; // Currently detected errors
END_VAR
VAR
END_VAR
IF (stErrors.bHardwareFailure // Close carbide shutter if there is a hardware failure
OR stErrors.bLeakOpcpaCarbideOn (* OR stErrors.bLeakUnderTable *) ) // Close carbide shutter if leak in OPCPA with carbide on or if there is a leak under the table
AND NOT bMasterOverride //if master override is TRUE, ignore all errors
THEN
F_CarbideShutterEnable := FALSE;
ELSE
F_CarbideShutterEnable := TRUE;
END_IF
END_FUNCTION
- Related:
F_DumpChillerEnable
// Interlock logic for the Dump Chiller
FUNCTION F_DumpChillerEnable : BOOL
VAR_INPUT
bMasterOverride : BOOL; //Master manual override control input
END_VAR
VAR_IN_OUT CONSTANT
stErrors : ST_ErrorStates; // Currently detected errors
END_VAR
VAR
END_VAR
IF (stErrors.bHardwareFailure // Disable dump chiller if there's a hardware failure
OR stErrors.bLeakOpticalTableAmphosOn OR stErrors.bLeakOpticalTableNoLaser (* OR stErrors.bLeakUnderTable *) ) // Disable dump chiller for these leak conditions
AND NOT bMasterOverride //if master override is TRUE, ignore all errors
THEN
F_DumpChillerEnable := FALSE;
ELSE
F_DumpChillerEnable := TRUE;
END_IF
END_FUNCTION
- Related:
FB_AmphosMRC
// Monitors the Amphos MRC input signal for errors
FUNCTION_BLOCK FB_AmphosMRC
VAR_INPUT
bAmphosOn : BOOL; // Whether the Amphos is turned on
bMRC : BOOL; // Error signal. Signal should normally be high
END_VAR
VAR_OUTPUT
{attribute 'pytmc' := '
pv: ERROR
io: i
field: OSV MAJOR
field: ZSV NO_ALARM
field: ZNAM OK
field: ONAM ERROR
'}
bError : BOOL; // Whether an error was detected. Error should go back to normal on its own
END_VAR
VAR
END_VAR
(* Set error flag if amphos is on and the MRC has an error *)
bError := bAmphosOn AND NOT bMRC;
END_FUNCTION_BLOCK
FB_BaseplateChiller
// Monitors the baseplate chiller from the flow sensor
FUNCTION_BLOCK FB_BaseplateChiller
VAR_INPUT
bAmphosOn : BOOL; // Whether the amphos is turned on
bBaseplateChillerFlow : BOOL; // Signal from the flow sensor. Normally high.
bMasterLatchReset : BOOL; //Master latched error reset
END_VAR
VAR_OUTPUT
{attribute 'pytmc' := '
pv: ERROR
io: i
field: OSV MAJOR
field: ZSV NO_ALARM
field: ZNAM OK
field: ONAM ERROR
'}
bError : BOOL; // Whether an error was detected. Should latch until reset
END_VAR
VAR
END_VAR
(* Latch error if the baseplate chiller flow detects an error *)
IF bAmphosOn AND NOT bBaseplateChillerFlow THEN
bError := TRUE;
END_IF
IF bMasterLatchReset THEN
bError := FALSE;
END_IF
END_FUNCTION_BLOCK
// Reset latched errors
METHOD Reset
VAR_INPUT
END_VAR
bError := FALSE;
END_METHOD
FB_ChillerLoop
// Monitors the chiller loop from the flow sensor
FUNCTION_BLOCK FB_ChillerLoop
VAR_INPUT
bLoopTempSW : BOOL; // NC Temperature switch. Indicates when temperature is too high
END_VAR
VAR_OUTPUT
{attribute 'pytmc' := '
pv: ERROR
io: i
field: OSV MAJOR
field: ZSV NO_ALARM
field: ZNAM OK
field: ONAM ERROR
'}
bError : BOOL := FALSE; // Whether an error was detected. Goes back to normal on its own
{attribute 'pytmc' := '
pv: OVERRIDE
io: io
field: ZNAM "OFF"
field: ONAM "ON"
'}
bOperatorOverride : BOOL := FALSE; // If TRUE, allows the EPS to keep running despite the chiller loop error
END_VAR
(* Set error flag if loop temperature monitor detects an error *)
bError := NOT bLoopTempSW;
(* Reset the operator override if the system returns to normal tempreature range *)
IF bLoopTempSW THEN
bOperatorOverride := FALSE;
END_IF
END_FUNCTION_BLOCK
FB_DumpChiller
// Monitors the dump chiller from the flow sensor
FUNCTION_BLOCK FB_DumpChiller
VAR_INPUT
bAmphosOn : BOOL; // Whether the amphos is turned on
bDumpChillerFlow : BOOL; // Signal from the flow sensor. Normally high.
bMasterLatchReset : BOOL; //Master latched error reset
END_VAR
VAR_OUTPUT
{attribute 'pytmc' := '
pv: ERROR
io: i
field: OSV MAJOR
field: ZSV NO_ALARM
field: ZNAM OK
field: ONAM ERROR
'}
bError : BOOL; // Whether an error was detected. Latches until reset
END_VAR
VAR
END_VAR
(* Latch error if the dump chiller flow detects an error and the amphos is on *)
IF bAmphosOn AND NOT bDumpChillerFlow THEN
bError := TRUE;
END_IF
IF bMasterLatchReset THEN
bError := FALSE;
END_IF
END_FUNCTION_BLOCK
// Reset latched errors
METHOD Reset
VAR_INPUT
END_VAR
bError := FALSE;
END_METHOD
FB_EcatDiag
(*
Ecat bus diagnostic tool
2015-11-4 Alex Wallace
This function block checks the states of all slaves on the ecat bus network,
it could be modified to export the states of the slaves on an individual basis,
but for now it sets the output boolean true if all slaves are OP and false otherwise.
To start the block provide a falling edge on the first pass boolean input.
2018-05-05 Margaret Ghaly
Function block has been modified to retrieve the Device State of the Ethercat Master.
It also exports the states and information of each individual configured Slave.
And saves them in the array q_aEcConfSlaveInfo.
2019-08-28 Nathan Telles
Customized for EPS project using PyTMC. Export all states to a structure which is
linked to EPICS records. Remove unecessary diagnostics.
*)
{attribute 'call_after_init'}
FUNCTION_BLOCK FB_EcatDiag
VAR_INPUT
{attribute 'naming' := 'omit'}
AMSNetId : AMSNETID; //Link to the AMSNETID name in the ethercat master info.
//i_xFirstPass: BOOL; //Hook to system first pass boolean for proper intialization (must be true for the first cycle of the PLC)
END_VAR
VAR_OUTPUT
{attribute 'pytmc' := '
pv: ERROR
io: i
field: OSV MAJOR
field: ZSV NO_ALARM
field: ZNAM OK
field: ONAM ERROR
'}
bError : BOOL;
{attribute 'pytmc' := '
pv: SLAVES_OK
io: i
field: OSV NO_ALARM
field: ZSV MAJOR
field: ZNAM ERROR
field: ONAM OK
'}
bAllSlaveStatesGood: BOOL; // Set to True if all Slaves are in OP State
{attribute 'pytmc' := '
pv: MASTER_OK
io: i
field: OSV NO_ALARM
field: ZSV MAJOR
field: ZNAM ERROR
field: ONAM OK
'}
bMasterStateGood : BOOL;
END_VAR
VAR
{attribute 'pytmc' := '
pv: MASTER_DEV_STATE
io: i
'}
nMasterDevState: WORD; // The Device State of the Master
{attribute 'pytmc' := '
pv: MASTER_STATE
io: i
'}
nMasterState: WORD; // The State of the Master
{attribute 'pytmc' := '
pv: AMS_ID
io: i
'}
sNetId: STRING(23); //NetId string
astTermStates: ARRAY[1..MAX_SLAVES] OF ST_EcSlaveState; //ECAT Slave States Buffer
astEcConfSlaveInfo: ARRAY[1..MAX_SLAVES] OF ST_EcSlaveConfigData; //ECAT Slave Configs Buffer
fbGetAllSlaveStates: FB_EcGetAllSlaveStates; //Acquires the ECAT Slave States puts them into astTermStates
fbGetMasterDevState: FB_EcGetMasterDevState; //Acquires ECAT Master State
fbGetMasterState: FB_EcGetMasterState; //Acquires ECAT Master State
fbGetConfSlaves: FB_EcGetConfSlaves; //Acquires the ECAT slave configuration of the bus (how many, what kind, etc)
{attribute 'naming' := 'omit'}
ftReset: F_TRIG; //Reset trigger sensor
{attribute 'naming' := 'omit'}
ftMasterDevReset: F_TRIG; //Retrigger sensor for GetMasterDevState
{attribute 'naming' := 'omit'}
ftMasterReset: F_TRIG; //Retrigger sensor for GetMasterState
{attribute 'pytmc' := 'pv: SLAVE01'}
stSlave01 : ST_DeviceDiagnostic;
{attribute 'pytmc' := 'pv: SLAVE02'}
stSlave02 : ST_DeviceDiagnostic;
{attribute 'pytmc' := 'pv: SLAVE03'}
stSlave03 : ST_DeviceDiagnostic;
{attribute 'pytmc' := 'pv: SLAVE04'}
stSlave04 : ST_DeviceDiagnostic;
{attribute 'pytmc' := 'pv: SLAVE05'}
stSlave05 : ST_DeviceDiagnostic;
{attribute 'pytmc' := 'pv: SLAVE06'}
stSlave06 : ST_DeviceDiagnostic;
{attribute 'pytmc' := 'pv: SLAVE07'}
stSlave07 : ST_DeviceDiagnostic;
{attribute 'pytmc' := 'pv: SLAVE08'}
stSlave08 : ST_DeviceDiagnostic;
{attribute 'pytmc' := 'pv: SLAVE09'}
stSlave09 : ST_DeviceDiagnostic;
{attribute 'pytmc' := 'pv: SLAVE10'}
stSlave10 : ST_DeviceDiagnostic;
aSlaves : ARRAY [1..MAX_SLAVES] OF POINTER TO ST_DeviceDiagnostic := [ADR(stSlave01),ADR(stSlave02),
ADR(stSlave03),ADR(stSlave04),ADR(stSlave05),ADR(stSlave06),ADR(stSlave07),ADR(stSlave08),
ADR(stSlave09), ADR(stSlave10)];
nIterator: UINT;
bInit : BOOL := TRUE;
{attribute 'pytmc' := '
pv: SLAVES_COUNT
io: i
'}
nSlaves : UINT;
END_VAR
VAR CONSTANT
MAX_SLAVES : UINT := 10;
END_VAR
sNetId := F_CreateAmsNetId(AMSNetId);
//Query the state of all terminals, collect in astTermStates
ftReset(CLK:=fbGetAllSlaveStates.bBusy OR bInit);
fbGetAllSlaveStates.bExecute := ftReset.Q;
fbGetAllSlaveStates(sNetId:=sNetId, pStateBuf := ADR(astTermStates), cbBufLen:=SIZEOF(astTermStates));
//Keep checking...
//Cycle through each entry in the array and check if we have anyone not in OP and that the link state is good.
// If so, then set our global IO bad boolean.
IF fbGetAllSlaveStates.nSlaves > 0 THEN
bAllSlaveStatesGood := TRUE;
FOR nIterator := 1 TO MAX_SLAVES DO
IF nIterator > fbGetAllSlaveStates.nSlaves // Slave is missing
OR NOT( (astTermStates[nIterator].deviceState = EC_DEVICE_STATE_OP) AND (astTermStates[nIterator].linkState = EC_LINK_STATE_OK))
THEN
bAllSlaveStatesGood := FALSE;
END_IF
IF nIterator <= fbGetAllSlaveStates.nSlaves THEN
aSlaves[nIterator]^.nDeviceState := astTermStates[nIterator].deviceState AND EC_DEVICE_STATE_MASK;
aSlaves[nIterator]^.nDeviceStateFlags := SHR(astTermStates[nIterator].deviceState, 4);
aSlaves[nIterator]^.nLinkStateFlags :=astTermStates[nIterator].linkState;
ELSE
// Missing slaves should be set to invalid
aSlaves[nIterator]^.nDeviceState := E_DeviceState.INVALID;
END_IF
END_FOR
END_IF
// Read the EtherCAT state of the master. If the call is successful,
//the State output variable of type WORD contains the requested status information.
ftMasterDevReset(CLK:=fbGetMasterDevState.bBusy OR bInit);
fbGetMasterDevState(sNetId:= sNetId, bExecute:=ftMasterDevReset.Q, nDevState => nMasterDevState);
ftMasterReset(CLK:=fbGetMasterState.bBusy OR bInit);
fbGetMasterState(sNetId:= sNetId, bExecute:=ftMasterDevReset.Q, state => nMasterState);
bMasterStateGood:= (fbGetMasterState.state = BYTE_TO_UINT(EC_DEVICE_STATE_OP) AND fbGetMasterDevState.nDevState = 0);
//This function is used to read a list of all configured slaves from the EtherCat master object Directory
//needs to run only once
fbGetConfSlaves(bExecute := bInit, sNetId :=sNetId, pArrEcConfSlaveInfo := ADR(astEcConfSlaveInfo),cbBufLen := SIZEOF(astEcConfSlaveInfo));
nSlaves:=fbGetConfSlaves.nSlaves;
IF NOT (fbGetConfSlaves.bBusy) THEN
FOR nIterator := 1 TO MIN(MAX_SLAVES, fbGetConfSlaves.nSlaves) DO
IF nIterator > fbGetConfSlaves.nSlaves THEN // Missing terminal
aSlaves[nIterator]^.nAddr := 0;
aSlaves[nIterator]^.sName := '';
aSlaves[nIterator]^.sType := '';
ELSE
aSlaves[nIterator]^.nAddr :=astEcConfSlaveInfo[nIterator].nAddr;
aSlaves[nIterator]^.sName :=astEcConfSlaveInfo[nIterator].sName;
aSlaves[nIterator]^.sType :=astEcConfSlaveInfo[nIterator].sType;
END_IF
END_FOR
fbGetConfSlaves.bExecute := FALSE;
END_IF
bInit := FALSE;
bError := fbGetMasterDevState.bError OR fbGetMasterState.bError OR fbGetAllSlaveStates.bError OR
fbGetConfSlaves.bError OR NOT bAllSlaveStatesGood OR NOT bMasterStateGood;
END_FUNCTION_BLOCK
- Related:
FB_ErrorTriggers
// Detects rising-edge errors
FUNCTION_BLOCK FB_ErrorTriggers
VAR_INPUT
nLeakLocations : BYTE;
END_VAR
VAR_IN_OUT CONSTANT
stErrors : ST_ErrorStates; // Errors that have been detected
END_VAR
VAR_OUTPUT
stNewErrors : St_ErrorStates; // Rising-edge errors
END_VAR
VAR
// R_TRIG function blocks for detecting new errors
fbLeakTrig : R_TRIG;
fbLeakOpticalTableAmphosOnTrig : R_TRIG;
fbLeakOpticalTableNoLaserTrig : R_TRIG;
fbLeakOpcpaCarbideOnTrig : R_TRIG;
fbLeakUnderTableTrig : R_TRIG;
fbLeakInsideRacksTrig : R_TRIG;
fbAmphosBeamTrig : R_TRIG;
fbOpcpaBeamTrig : R_TRIG;
fbDumpChillerTrig : R_TRIG;
fbBaseplateChillerTrig : R_TRIG;
END_VAR
fbLeakTrig(
CLK := nLeakLocations <> E_LeakLocation.NO_LEAK,
);
fbLeakOpticalTableAmphosOnTrig(
CLK := stErrors.bLeakOpticalTableAmphosOn,
Q => stNewErrors.bLeakOpticalTableAmphosOn
);
fbLeakOpticalTableNoLaserTrig(
CLK := stErrors.bLeakOpticalTableNoLaser,
Q => stNewErrors.bLeakOpticalTableNoLaser
);
fbLeakOpcpaCarbideOnTrig(
CLK := stErrors.bLeakOpcpaCarbideOn,
Q => stNewErrors.bLeakOpcpaCarbideOn
);
fbLeakUnderTableTrig(
CLK := stErrors.bLeakUnderTable,
Q => stNewErrors.bLeakUnderTable
);
fbLeakInsideRacksTrig(
CLK := stErrors.bLeakInsideRacks,
Q => stNewErrors.bLeakInsideRacks
);
fbAmphosBeamTrig(
CLK := stErrors.bAmphosBeam,
Q => stNewErrors.bAmphosBeam
);
fbOpcpaBeamTrig(
CLK := stErrors.bOpcpaBeam,
Q => stNewErrors.bOpcpaBeam
);
fbDumpChillerTrig(
CLK := stErrors.bDumpChiller,
Q => stNewErrors.bDumpChiller
);
fbBaseplateChillerTrig(
CLK := stErrors.bBaseplateChiller,
Q => stNewErrors.bBaseplateChiller
);
END_FUNCTION_BLOCK
// Returns whether a rising-edge leak error has occured
METHOD NewLeakError : BOOL
VAR_INPUT
END_VAR
NewLeakError := fbLeakTrig.Q OR fbLeakOpticalTableAmphosOnTrig.Q OR fbLeakOpticalTableNoLaserTrig.Q OR fbLeakOpcpaCarbideOnTrig.Q OR fbLeakUnderTableTrig.Q OR fbLeakInsideRacksTrig.Q;
END_METHOD
// Reset latched amphos errors
METHOD ResetAmphosTrigger
VAR_INPUT
END_VAR
fbAmphosBeamTrig(
CLK := FALSE,
Q => stNewErrors.bAmphosBeam
);
END_METHOD
METHOD ResetBaseplateChillerTrigger
VAR_INPUT
END_VAR
fbBaseplateChillerTrig(
CLK := FALSE,
Q => stNewErrors.bBaseplateChiller
);
END_METHOD
METHOD ResetDumpChillerTrigger
VAR_INPUT
END_VAR
fbDumpChillerTrig(
CLK := FALSE,
Q => stNewErrors.bDumpChiller
);
END_METHOD
// Reset latched leak errors
METHOD ResetLeakTriggers
VAR_INPUT
END_VAR
fbLeakOpticalTableAmphosOnTrig(
CLK := FALSE,
Q => stNewErrors.bLeakOpticalTableAmphosOn
);
fbLeakOpticalTableNoLaserTrig(
CLK := FALSE,
Q => stNewErrors.bLeakOpticalTableNoLaser
);
fbLeakOpcpaCarbideOnTrig(
CLK := FALSE,
Q => stNewErrors.bLeakOpcpaCarbideOn
);
fbLeakUnderTableTrig(
CLK := FALSE,
Q => stNewErrors.bLeakUnderTable
);
fbLeakInsideRacksTrig(
CLK := FALSE,
Q => stNewErrors.bLeakInsideRacks
);
END_METHOD
// Reset latched OPCPA errors
METHOD ResetOpcpaTrigger
VAR_INPUT
END_VAR
fbOpcpaBeamTrig(
CLK := FALSE,
Q => stNewErrors.bOpcpaBeam
);
END_METHOD
- Related:
FB_Laser
// Monitors the lasers for under voltage events
FUNCTION_BLOCK FB_Laser
VAR_INPUT
nVoltageRaw : INT; // The raw signal collected from the ADC
bAmphosOn : BOOL; // Whether the amphos is turned on
bMasterLatchReset : BOOL; //Master latched error reset
END_VAR
VAR_IN_OUT CONSTANT
stSetpoints : ST_LaserSetpoints; // Setpoints for the laser
END_VAR
VAR_OUTPUT
{attribute 'pytmc' := '
pv: VOLTAGE
io: i
field: HOPR 10.0
field: LOPR 0.0
field: LSV MINOR
field: LLSV MAJOR
field: EGU Volts
'}
fVoltage : LREAL; // Voltage calculated from the raw ADC input
{attribute 'pytmc' := '
pv: SCALED_PWR
io: i
field: EGU Watts
'}
fPower : LREAL; // Value to be scaled from fVoltage to give meter reading in terms of watts
{attribute 'pytmc' := '
pv: ERROR
io: i
field: OSV MAJOR
field: ZSV NO_ALARM
field: ZNAM OK
field: ONAM ERROR
'}
bError : BOOL; // Whether an error was detected. Latches until reset
bBelowNominal : BOOL; //fVoltage is below the nominal setpoint
END_VAR
(* Scale the analog signal to voltage *)
fVoltage := F_Scale(
fRawData := nVoltageRaw,
fRawDataLowerOffLimit := GVL_EL3174.fRawLowerLimit,
fRawDataUpperOffLimit := GVL_EL3174.fRawUpperLimit,
fScaleDataLowerOffLimit := GVL_EL3174.fScaleLowerLimit,
fScaleDataUpperOffLimit := GVL_EL3174.fScaleUpperLimit);
fPower := fVoltage; //Value is scaled by user set ASLO and AOFF fields (for display only)
IF bAmphosOn AND (fVoltage < stSetpoints.nMinNominalVoltage) THEN
bBelowNominal := TRUE;
END_IF
(* Set error if amphos is below nominal voltage *)
IF bAmphosOn AND (fVoltage < stSetpoints.nMinVoltage) THEN
bError := TRUE;
END_IF
IF bMasterLatchReset THEN
bBelowNominal := FALSE;
bError := FALSE;
END_IF
END_FUNCTION_BLOCK
// Reset latched errors
METHOD Reset
VAR_INPUT
END_VAR
bError := FALSE;
END_METHOD
- Related:
FB_LeakMonitor
// Detect leaks and leak locations
FUNCTION_BLOCK FB_LeakMonitor
VAR_INPUT
bLeakDetected : BOOL; // Whether a leak was detected
bAmphosOn : BOOL; // Whether the Amphos is on
bCarbideOn : BOOL; // Whether the Carbide is on
nLocationResistance: UINT; // Used for calculating the location of the leak
bMasterLatchReset : BOOL; //Master latched error reset
END_VAR
VAR_IN_OUT CONSTANT
stBound : ST_LeakBoundaries; // Setpoints for calculating leak locations from location resistance
END_VAR
VAR_OUTPUT
{attribute 'pytmc' := '
pv: LOW_RES
io: i
'}
bLowResistance : BOOL := FALSE;
{attribute 'pytmc' := '
pv: LEAKS
io: i
'}
nLeakLocations : BYTE := E_LeakLocation.NO_LEAK; // Locations of leaks
{attribute 'pytmc' := '
pv: LOTAO_ERROR
io: i
field: OSV MAJOR
field: ZSV NO_ALARM
field: ZNAM OK
field: ONAM ERROR
'}
bLeakOpticalTableAmphosOn : BOOL := FALSE; // Leak on the optical table with Amphos on
{attribute 'pytmc' := '
pv: LOTNL_ERROR
io: i
field: OSV MAJOR
field: ZSV NO_ALARM
field: ZNAM OK
field: ONAM ERROR
'}
bLeakOpticalTableNoLaser : BOOL := FALSE; // Leak on the optical table with no laser on
{attribute 'pytmc' := '
pv: LOCO_ERROR
io: i
field: OSV MAJOR
field: ZSV NO_ALARM
field: ZNAM OK
field: ONAM ERROR
'}
bLeakOpcpaCarbideOn : BOOL := FALSE; // Leak inside the OPCPA with Carbide on
{attribute 'pytmc' := '
pv: LUT_ERROR
io: i
field: OSV MAJOR
field: ZSV NO_ALARM
field: ZNAM OK
field: ONAM ERROR
'}
bLeakUnderTable : BOOL := FALSE; // Leak under the table
{attribute 'pytmc' := '
pv: LIR_ERROR
io: i
field: OSV MAJOR
field: ZSV NO_ALARM
field: ZNAM OK
field: ONAM ERROR
'}
bLeakInsideRacks : BOOL := FALSE; // Leak inside the racks
END_VAR
IF (nLocationResistance < 200) THEN
bLowResistance := TRUE;
ELSE
bLowResistance := FALSE;
END_IF
IF (bLeakDetected OR bLowResistance) THEN
(* Find leak location for PV. Stays until reset *)
IF stBound.nLMin1 <= nLocationResistance AND nLocationResistance < stBound.nLMax1 THEN
nLeakLocations := nLeakLocations OR E_LeakLocation.LOC1;
END_IF
IF stBound.nLMin2 <= nLocationResistance AND nLocationResistance < stBound.nLMax2 THEN
nLeakLocations := nLeakLocations OR E_LeakLocation.LOC2;
END_IF
IF stBound.nLMin3 <= nLocationResistance AND nLocationResistance < stBound.nLMax3 THEN
nLeakLocations := nLeakLocations OR E_LeakLocation.LOC3;
END_IF
IF stBound.nLMin4 <= nLocationResistance AND nLocationResistance < stBound.nLMax4 THEN
nLeakLocations := nLeakLocations OR E_LeakLocation.LOC4;
END_IF
IF stBound.nLMin5 <= nLocationResistance AND nLocationResistance < stBound.nLMax5 THEN
nLeakLocations := nLeakLocations OR E_LeakLocation.LOC5;
END_IF
IF stBound.nLMin6 <= nLocationResistance AND nLocationResistance < stBound.nLMax6 THEN
nLeakLocations := nLeakLocations OR E_LeakLocation.LOC6;
END_IF
//CURRENT SETUP : LOC1 = OPCPA, LOC2 = rest of optical table (values decrease toward higher LOC#)
(* Latch Optical table leak errors *)
IF (stBound.nLMin2 <= nLocationResistance AND nLocationResistance < stBound.nLMax1) THEN
IF bAmphosOn THEN
bLeakOpticalTableAmphosOn := TRUE;
ELSIF NOT bCarbideOn THEN
bLeakOpticalTableNoLaser := TRUE;
END_IF
END_IF
(* Latch carbide leak errors *)
IF (bCarbideOn AND stBound.nLMin1 <= nLocationResistance AND nLocationResistance < stBound.nLMax1) THEN
bLeakOpcpaCarbideOn := TRUE;
END_IF
(* Latch leak under table errors *)
IF (stBound.nLMin5 <= nLocationResistance AND nLocationResistance < stBound.nLMax5) THEN
bLeakUnderTable := TRUE;
END_IF
(* Latch leak inside rack errors *)
IF (stBound.nLMin6 <= nLocationResistance AND nLocationResistance < stBound.nLMax6) THEN
bLeakInsideRacks := TRUE;
END_IF
END_IF
IF bMasterLatchReset THEN
nLeakLocations := E_LeakLocation.NO_LEAK;
bLeakOpticalTableAmphosOn := FALSE;
bLeakOpcpaCarbideOn := FALSE;
bLeakOpticalTableNoLaser := FALSE;
bLeakUnderTable := FALSE;
bLeakInsideRacks := FALSE;
END_IF
END_FUNCTION_BLOCK
// Reset latched errors
METHOD Reset
VAR_INPUT
END_VAR
nLeakLocations := E_LeakLocation.NO_LEAK;
bLeakOpticalTableAmphosOn := FALSE;
bLeakOpticalTableNoLaser := FALSE;
bLeakOpcpaCarbideOn := FALSE;
bLeakUnderTable := FALSE;
bLeakInsideRacks := FALSE;
END_METHOD
- Related:
FB_TemperatureMonitor
// Monitors temperature sensors
FUNCTION_BLOCK FB_TemperatureMonitor
VAR_INPUT
nTempMonRaw : INT; // Raw signal from the ADC
bAmphosOn : BOOL; // Whether the Amphos is on
END_VAR
VAR_IN_OUT
stSetpoints : ST_TemperatureMonitorSetpoints; // Temperature sensor setpoints
END_VAR
VAR_OUTPUT
{attribute 'pytmc' := '
pv: TEMP
io: i
field: EGU C
field: LOPR 0.0
field: HOPR 1000
field: LSV MINOR
'}
fTemperature : LREAL; // Temperature reading in celsius
{attribute 'pytmc' := '
pv: ERROR
io: i
field: OSV MAJOR
field: ZSV NO_ALARM
field: ZNAM OK
field: ONAM ERROR
'}
bError : BOOL; // Whether a temperature event happened. Goes back to normal by itself
END_VAR
VAR_TEMP
fMonitorVoltage : LREAL; // Voltage calculated from the raw ADC input
END_VAR
(* Scale the analog signal to voltage *)
fMonitorVoltage := F_Scale(
fRawData := nTempMonRaw,
fRawDataLowerOffLimit := GVL_EL3174.fRawLowerLimit,
fRawDataUpperOffLimit := GVL_EL3174.fRawUpperLimit,
fScaleDataLowerOffLimit := GVL_EL3174.fScaleLowerLimit,
fScaleDataUpperOffLimit := GVL_EL3174.fScaleUpperLimit);
fTemperature := fMonitorVoltage * 100;
(* Set error flag if temperature above max allowed and the amphos is on *)
bError := fTemperature > stSetpoints.fMaxTemperature AND bAmphosOn;
END_FUNCTION_BLOCK
- Related:
FB_TraceTekModbus
// Communicates with the TraceTek TTSIM-1A hardware over Modbus to get more information about a leak
FUNCTION_BLOCK FB_TraceTekModbus
VAR_INPUT
nModbusSlaveAddress : BYTE; // Modbus address of slave to be read from
bLeakDetected : BOOL; // Whether a leak has been detected
bResetError : BOOL; // Reset signal for error
END_VAR
VAR_OUTPUT
{attribute 'pytmc' := '
pv: LOC_RES
io: i
field: OSV MAJOR
field: ZSV NO_ALARM
field: ZNAM OK
field: ONAM ERROR
'}
nLocationResistance: UINT; // Resistance measured in the detection wire
{attribute 'pytmc' := '
pv: ERROR
io: i
field: OSV MAJOR
field: ZSV NO_ALARM
field: ZNAM OK
field: ONAM ERROR
'}
bError : BOOL := FALSE; // Flag for Modbus communication errors
nErrorId : MODBUS_ERRORS := MODBUS_ERRORS.MODBUSERROR_NO_ERROR; // Description of Modbus error
END_VAR
VAR
aModbusBuffer : WORD := 16#FFFF; // "Infinite" until real value is read from device
fbModbusMaster : ModbusRtuMaster_KL6x22B := (
Quantity := 1,
MBAddr := 1,
cbLength := SIZEOF(aModbusBuffer),
pMemoryAddr := ADR(aModbusBuffer),
Timeout := T#5S
);
fbPoll : TON := (PT := T#0S); // Poll rate for reading modbus. Start at 0 so that modbus is read on first call
END_VAR
VAR_STAT
tPollRate : TIME := T#500MS;
END_VAR
// Advance poll rate timer
fbPoll(IN := TRUE);
// Update modbus status
fbModbusMaster.Execute := FALSE;
fbModbusMaster.ReadInputRegs();
IF bResetError THEN // Reset modbus error
bError := FALSE;
nErrorId := MODBUS_ERRORS.MODBUSERROR_NO_ERROR;
ELSIF fbModbusMaster.Error OR NOT fbModbusMaster.BUSY THEN
// Allow fb error state to go back to normal by checking modbus error state after reading has finished
bError := fbModbusMaster.Error;
nErrorId := fbModbusMaster.ErrorId;
END_IF
(* If the modbus interface isn't busy and there is a leak, try reading
the leak location from the TraceTek. Even if there is no leak, maintain
the modbus connection by checking every few seconds using the fbPoll rate *)
IF NOT fbModbusMaster.BUSY AND (bLeakDetected OR fbPoll.Q) THEN
fbPoll(IN := FALSE, PT := tPollRate);
fbModbusMaster.UnitID := nModbusSlaveAddress;
fbModbusMaster.Execute := TRUE;
fbModbusMaster.ReadInputRegs();
END_IF
// Copy the location resitance from the buffer to the FB output
nLocationResistance := WORD_TO_UINT(aModbusBuffer);
END_FUNCTION_BLOCK
MAIN
PROGRAM MAIN
VAR
stErrors : ST_ErrorStates; // Triggered error states
fbErrorTriggers : FB_ErrorTriggers; // Brand new errors this cycle
// Leak Monitor
{attribute 'pytmc' := 'pv: @(PREFIX):TTSIM:DEV01'}
fbTraceTekModbus : FB_TraceTekModbus; // Modbus connection to TraceTek
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:LEAK:RESET'}
bLeakMonitorReset : BOOL; // Leak monitor reset flag
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:LEAK'}
fbLeakMonitor : FB_LeakMonitor; // Leak detection
// Chiller Loop temperature monitors
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:TEMP01'}
fbChillerLoop01 : FB_ChillerLoop; // Chiller loop 01
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:TEMP02'}
fbChillerLoop02 : FB_ChillerLoop; // Chiller loop 02
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:TEMP03'}
fbChillerLoop03 : FB_ChillerLoop; // Chiller loop 03
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:TEMP04'}
fbChillerLoop04 : FB_ChillerLoop; // Chiller loop 04
// Laser monitors
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:AMPHOS'}
fbAmphos : FB_Laser; // Amphos laser
{attribute 'pytmc' := '
pv: @(PREFIX):LPS:AMPHOS:RESET
io: o
'}
bAmphosReset : BOOL; // Amphos laser error unlatch flag
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:OPCPA'}
fbOpcpa : FB_Laser; // OPCPA laser
{attribute 'pytmc' := '
pv: @(PREFIX):LPS:OPCPA:RESET
io: o
'}
bOpcpaReset : BOOL; // OPCPA laser error unlatch flag
(*
// Temperature monitors
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:TEMPMON01'}
fbTempMon01 : FB_TemperatureMonitor; // System temperature monitor 01
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:TEMPMON02'}
fbTempMon02 : FB_TemperatureMonitor; // System temperature monitor 02
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:TEMPMON03'}
fbTempMon03 : FB_TemperatureMonitor; // System temperature monitor 03
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:TEMPMON04'}
fbTempMon04 : FB_TemperatureMonitor; // System temperature monitor 04
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:TEMPMON05'}
fbTempMon05 : FB_TemperatureMonitor; // System temperature monitor 05
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:TEMPMON06'}
fbTempMon06 : FB_TemperatureMonitor; // System temperature monitor 06
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:TEMPMON07'}
fbTempMon07 : FB_TemperatureMonitor; // System temperature monitor 07
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:TEMPMON08'}
fbTempMon08 : FB_TemperatureMonitor; // System temperature monitor 08
*)
// Chillers
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:DUMP_CHILLER'}
fbDumpChiller : FB_DumpChiller; // Flow sensor monitor for the dump chiller
{attribute 'pytmc' := '
pv: @(PREFIX):LPS:DUMP_CHILLER:RESET
io: o
'}
bDumpChillerReset : BOOL; // Dump chiller error unlatch flag
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:BASEPLATE_CHILLER'}
fbBaseplateChiller : FB_BaseplateChiller; // Flow sensor monitor for the baseplate chiller
{attribute 'pytmc' := '
pv: @(PREFIX):LPS:BASEPLATE_CHILLER:RESET
io: o
'}
bBaseplateChillerReset : BOOL; // Baseplate chiller error unlatch flag
(*
// Amphos MRCs
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:AMPHOS_MRC01'}
fbAmphosMRC01 : FB_AmphosMRC; // MRC monitor 01
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:AMPHOS_MRC02'}
fbAmphosMRC02 : FB_AmphosMRC; // MRC monitor 02
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:AMPHOS_MRC03'}
fbAmphosMRC03 : FB_AmphosMRC; // MRC monitor 03
*)
{attribute 'pytmc' := '
pv: @(PREFIX):LPS:MASTER_OVERRIDE
io: o
'}
bMasterOverride : BOOL := TRUE; // Master override control for safety system.
{attribute 'pytmc' := '
pv: @(PREFIX):LPS:MASTER_AMP_SHUTTER
io: o
'}
bAmpShutterClosed : BOOL; // Master Amphos Shutter control
{attribute 'pytmc' := '
pv: @(PREFIX):LPS:MASTER_LATCH_RESET
io: o
'}
bMasterLatchReset : BOOL; //Master release of latched error conditions
bLatchStart : BOOL := FALSE; //Latch at start of loop.
{attribute 'pytmc' := 'pv: @(PREFIX):LPS:PLC'}
fbDiag : FB_EcatDiag; // Ethercat diagnostics
END_VAR
(* Ensure master latch is TRUE for at least one full cycle of the PLC logic *)
IF bMasterLatchReset AND NOT bLatchStart THEN
bLatchStart := TRUE;
END_IF
(*******************************************************************
Update diagnostics. Check for hardware failures
*******************************************************************)
(* Check PLC hardware for failures *)
fbDiag(AMSNetId := GVL_PLC.AMSNetId);
stErrors.bHardwareFailure := (fbDiag.bError OR fbTraceTekModbus.bError) AND NOT bMasterOverride;
(*******************************************************************
Feed each device function block inputs from the PLC IO. Collect error states detected
by the function blocks into stErrors. These collected errors are then used later for
making decisions in the interlock logic.
*******************************************************************)
(* Detects leaks using the location resitance from the TraceTek *)
fbLeakMonitor(
nLocationResistance := fbTraceTekModbus.nLocationResistance,
bAmphosOn := GVL_IO.bAmphosOn,
bCarbideOn := GVL_IO.bCarbideOn,
bLeakDetected := GVL_IO.bLeakDetected,
stBound := GVL_TraceTek.stLeakMonitorBoundaries,
bLeakOpticalTableAmphosOn => stErrors.bLeakOpticalTableAmphosOn,
bLeakOpticaltableNoLaser => stErrors.bLeakOpticalTableNoLaser,
bLeakOpcpaCarbideOn => stErrors.bLeakOpcpaCarbideOn,
bLeakUnderTable => stErrors.bLeakUnderTable,
bLeakInsideRacks => stErrors.bLeakInsideRacks,
bMasterLatchReset := bMasterLatchReset
);
(* Monitors for error events on chiller loop 1 *)
fbChillerLoop01(
bLoopTempSW := GVL_IO.bLoopTempSW01,
bError => stErrors.bChillerLoop01
);
(* Monitors for error events on chiller loop 2 *)
fbChillerLoop02(
bLoopTempSW := GVL_IO.bLoopTempSW02,
bError => stErrors.bChillerLoop02
);
(* Monitors for error events on chiller loop 3 *)
fbChillerLoop03(
bLoopTempSW := GVL_IO.bLoopTempSW03,
bError => stErrors.bChillerLoop03
);
(* Monitors for error events on chiller loop 4 *)
fbChillerLoop04(
bLoopTempSW := GVL_IO.bLoopTempSW04,
bError => stErrors.bChillerLoop04
);
(* Monitors the Amphos laser *)
fbAmphos(
nVoltageRaw := GVL_IO.nAmphosVoltageRaw,
bAmphosOn := GVL_IO.bAmphosOn,
stSetpoints := GVL_Laser.stAmphosSP,
bError => stErrors.bAmphosBeam,
bMasterLatchReset := bMasterLatchReset
);
(* Monitors the OPCPA laser *)
fbOpcpa(
nVoltageRaw := GVL_IO.nOpcpaVoltageRaw,
bAmphosOn := GVL_IO.bAmphosOn,
stSetpoints := GVL_Laser.stOpcpaSP,
bError => stErrors.bOpcpaBeam,
bMasterLatchReset := bMasterLatchReset
);
(*
(* Monitors system temperature from sensor 1 *)
fbTempMon01(
nTempMonRaw := GVL_IO.nTempMonRaw01,
bAmphosOn := GVL_IO.bAmphosOn,
stSetpoints := GVL_TemperatureMonitor.stTempMonSP01,
bError => stErrors.bTempMon01
);
(* Monitors system temperature from sensor 2 *)
fbTempMon02(
nTempMonRaw := GVL_IO.nTempMonRaw02,
bAmphosOn := GVL_IO.bAmphosOn,
stSetpoints := GVL_TemperatureMonitor.stTempMonSP02,
bError => stErrors.bTempMon02
);
(* Monitors system temperature from sensor 3 *)
fbTempMon03(
nTempMonRaw := GVL_IO.nTempMonRaw03,
bAmphosOn := GVL_IO.bAmphosOn,
stSetpoints := GVL_TemperatureMonitor.stTempMonSP03,
bError => stErrors.bTempMon03
);
(* Monitors system temperature from sensor 4 *)
fbTempMon04(
nTempMonRaw := GVL_IO.nTempMonRaw04,
bAmphosOn := GVL_IO.bAmphosOn,
stSetpoints := GVL_TemperatureMonitor.stTempMonSP04,
bError => stErrors.bTempMon04
);
(* Monitors system temperature from sensor 5 *)
fbTempMon05(
nTempMonRaw := GVL_IO.nTempMonRaw05,
bAmphosOn := GVL_IO.bAmphosOn,
stSetpoints := GVL_TemperatureMonitor.stTempMonSP05,
bError => stErrors.bTempMon05
);
(* Monitors system temperature from sensor 6 *)
fbTempMon06(
nTempMonRaw := GVL_IO.nTempMonRaw06,
bAmphosOn := GVL_IO.bAmphosOn,
stSetpoints := GVL_TemperatureMonitor.stTempMonSP06,
bError => stErrors.bTempMon06
);
(* Monitors system temperature from sensor 7 *)
fbTempMon07(
nTempMonRaw := GVL_IO.nTempMonRaw07,
bAmphosOn := GVL_IO.bAmphosOn,
stSetpoints := GVL_TemperatureMonitor.stTempMonSP07,
bError => stErrors.bTempMon07
);
(* Monitors system temperature from sensor 8 *)
fbTempMon08(
nTempMonRaw := GVL_IO.nTempMonRaw08,
bAmphosOn := GVL_IO.bAmphosOn,
stSetpoints := GVL_TemperatureMonitor.stTempMonSP08,
bError => stErrors.bTempMon08
);
*)
(* Flow sensor monitor for the dump chiller *)
fbDumpChiller(
bAmphosOn := GVL_IO.bAmphosOn,
bDumpChillerFlow := GVL_IO.bDumpChillerFlow,
bError => stErrors.bDumpChiller,
bMasterLatchReset := bMasterLatchReset
);
(* Flow sensor monitor for the baseplate chiller *)
fbBaseplateChiller(
bAmphosOn := GVL_IO.bAmphosOn,
bBaseplateChillerFlow := GVL_IO.bBaseplateChillerFlow,
bError => stErrors.bBaseplateChiller,
bMasterLatchReset := bMasterLatchReset
);
(*
(* Detects problems with MRC 1 *)
fbAmphosMRC01(
bAmphosOn := GVL_IO.bAmphosOn,
bMRC := GVL_IO.bAmphosMRC01,
bError => stErrors.bAmphosMRC01
);
(* Detects problems with MRC 2 *)
fbAmphosMRC02(
bAmphosOn := GVL_IO.bAmphosOn,
bMRC := GVL_IO.bAmphosMRC02,
bError => stErrors.bAmphosMRC02
);
(* Detects problems with MRC 3 *)
fbAmphosMRC03(
bAmphosOn := GVL_IO.bAmphosOn,
bMRC := GVL_IO.bAmphosMRC03,
bError => stErrors.bAmphosMRC03
);
*)
(*******************************************************************
Now that each of the input signals have been checked and errors stored,
run the interlock logic.
*******************************************************************)
(* Enable Amphos attenuator if interlock logic passes *)
(*
GVL_IO.bAmphosAttenuatorEnable := F_AmphosAttenuatorEnable(
bAmphosOn := GVL_IO.bAmphosOn,
stErrors := stErrors
);
Deprecated Logic -- Not Currently Used*)
(* Enable Amphos shutter if interlock logic passes *)
GVL_IO.bAmphosShutterEnable := F_AmphosShutterEnable(
bAmphosOn := GVL_IO.bAmphosOn,
fOpcpaVoltage := fbOpcpa.fVoltage,
bLoopTempOverride01 := fbChillerLoop01.bOperatorOverride,
bLoopTempOverride02 := fbChillerLoop02.bOperatorOverride,
bLoopTempOverride03 := fbChillerLoop03.bOperatorOverride,
bLoopTempOverride04 := fbChillerLoop04.bOperatorOverride,
stOpcpaSetpoints := GVL_Laser.stOpcpaSP,
stErrors := stErrors,
bMasterOverride := bMasterOverride,
bAmpShutterClosed := bAmpShutterClosed
);
(* Enable Carbide shutter if interlock logic passes *)
GVL_IO.bCarbideShutterEnable := F_CarbideShutterEnable(
stErrors := stErrors,
bMasterOverride := bMasterOverride
);
(* Enable Dump chiller if interlock logic passes *)
GVL_IO.bDumpChillerRelay := F_DumpChillerEnable(
stErrors := stErrors,
bMasterOverride := bMasterOverride
);
(* Enable Baseplate chiller if interlock logic passes *)
GVL_IO.bBaseplateChillerRelay := F_BaseplateChillerEnable(
stErrors := stErrors,
bMasterOverride := bMasterOverride
);
(* Enable Amphos if interlock logic passes *)
GVL_IO.bAmphosRelay := F_AmphosEnable(
fAmphosVoltage := fbAmphos.fVoltage,
bEnabled := GVL_IO.bAmphosRelay,
stAmphosSetpoints := GVL_Laser.stAmphosSP,
stErrors := stErrors,
bMasterOverride := bMasterOverride
);
(*******************************************************************
Safety related tasks have now been finished. Now try slower tasks such as
communicating with external hardware.
*******************************************************************)
(* Read from TraceTek hardware to get leak details. Errors are
handled later when diagnostics are run *)
fbTraceTekModbus(
nModbusSlaveAddress := GVL_TraceTek.nModbusSlaveAddress,
bLeakDetected := GVL_IO.bLeakDetected
);
(*******************************************************************
As per the specification, the reset PV is not checked until after the EPS has taken action.
Check the reset flags to see if they have been set and the errors can be unlatched.
*******************************************************************)
(* Check for rising-edge errors *)
fbErrorTriggers(stErrors := stErrors, nLeakLocations := fbLeakMonitor.nLeakLocations);
(* Check for new leak errors *)
IF fbErrorTriggers.NewLeakError() THEN
bLeakMonitorReset := FALSE; // If there is a new error turn off reset
ELSIF bLeakMonitorReset THEN
// If there are no new errors and reset is on, reset the errors
fbLeakMonitor.Reset();
fbErrorTriggers.ResetLeakTriggers();
END_IF
(* Check for new Amphos beam errors *)
IF fbErrorTriggers.stNewErrors.bAmphosBeam THEN
bAmphosReset := FALSE; // If there is a new error turn off reset
ELSIF bAmphosReset THEN
// If there are no new errors and reset is on, reset the errors
fbAmphos.Reset();
fbErrorTriggers.ResetAmphosTrigger();
END_IF
(* Check for new OPCPA errors *)
IF fbErrorTriggers.stNewErrors.bOpcpaBeam THEN
bOpcpaReset := FALSE; // If there is a new error turn off reset
ELSIF bOpcpaReset THEN
// If there are no new errors and reset is on, reset the errors
fbOpcpa.Reset();
fbErrorTriggers.ResetOpcpaTrigger();
END_IF
(* Check for new Beam Dump chiller errors *)
IF fbErrorTriggers.stNewErrors.bDumpChiller THEN
bDumpChillerReset := FALSE; // If there is a new error turn off reset
ELSIF bDumpChillerReset THEN
fbDumpChiller.Reset();
fbErrorTriggers.ResetDumpChillerTrigger();
END_IF
(* Check for new Baseplate chiller errors *)
IF fbErrorTriggers.stNewErrors.bBaseplateChiller THEN
bBaseplateChillerReset := FALSE; // If there is a new error turn off reset
ELSIF bBaseplateChillerReset THEN
// If there are no new errors and reset is on, reset the errors
fbBaseplateChiller.Reset();
fbErrorTriggers.ResetBaseplateChillerTrigger();
END_IF
(* Remove Master Latch Reset after one scan *)
IF bMasterLatchReset AND bLatchStart THEN
bMasterLatchReset := FALSE;
bLatchStart := FALSE;
END_IF
END_PROGRAM
- Related: