); // Set error active if fb has error IF _fbPosolytPumpInlet.xError THEN stModbusErrors.stBitmap.bPumpPos := 1; _xErrorActive := TRUE; END_IF // Set warning if fb has warning IF _fbPosolytPumpInlet.xWarning THEN _xWarningActive := TRUE; END_IF // Set safety interlock flag if fb has safety interlocks active IF NOT stHMIInterface.stNS11.stInterlock.xSafetyINTLKOk THEN xSafetyIntlksOk := FALSE; END_IF // =============================== // Pump negolyt segment inlet // =============================== // Safety Interlocks stHMIInterface.stNS21.stInterlock.asSafetyINTLKName[0] := 'Emergency stop ok'; _stNegolytPumpInletSIntlk.0 := xEmergencyStopOk; stHMIInterface.stNS11.stInterlock.asSafetyINTLKName[1] := 'Segment inlet pressure to high'; _stNegolytPumpInletSIntlk.1 := NOT _fbPressureNegolytSegmentInlet.xErrorHigh; stHMIInterface.stNS11.stInterlock.asSafetyINTLKName[2] := 'Segment inlet pressure to low'; _stNegolytPumpInletSIntlk.2 := NOT _fbPressureNegolytSegmentInlet.xErrorLow; // Process interlocks stHMIInterface.stNS11.stInterlock.asProcessINTLKName[0] := 'Posolyt Pump Error'; _stNegolytPumpInletPIntlk.0 := NOT _fbPosolytPumpInlet.xError; // Pump fb _fbNegolytPumpInlet( xReleaseManualMode:= _xReleaseManualMode, wProcessINTLK:= _stNegolytPumpInletPIntlk, wProcessINTLKUsed:= _stNegolytPumpInletPIntlkUsed, wSafetyINTLK:= _stNegolytPumpInletSIntlk, wSafetyINTLKUsed:= _stNegolytPumpInletSIntlkUsed, xReleaseErrors:= xReleaseErrors, xConfirmAlarms:= xConfirmAlarms, rSPautomatic:= _rSetpointNegolytPumpInlet, xReleaseAnalogInLimitErrors:= xReleaseLimitErrors AND GVL_SCADA.xDummy, stMotorAnalogConfig:= stUnitConfig.stConfigNegolytPump, stHMIInterface:= stHMIInterface.stNS21, xWarning=> ); // Set error active if fb has error IF _fbNegolytPumpInlet.xError THEN stModbusErrors.stBitmap.bPumpNeg := 1; _xErrorActive := TRUE; END_IF // Set warning if fb has warning IF _fbNegolytPumpInlet.xWarning THEN _xWarningActive := TRUE; END_IF // Set safety interlock flag if fb has safety interlocks active IF NOT stHMIInterface.stNS21.stInterlock.xSafetyINTLKOk THEN xSafetyIntlksOk := FALSE; END_IF _xPumpsReady := stHMIInterface.stNS21.stInterlock.xProcessINTLKOk AND stHMIInterface.stNS21.stInterlock.xSafetyINTLKOk AND stHMIInterface.stNS11.stInterlock.xProcessINTLKOk AND stHMIInterface.stNS11.stInterlock.xSafetyINTLKOk; // =============================== // Pressure sensor posolyt segment inlet // =============================== _fbPressurePosolytSegmentInlet( stScalingConfig:= stUnitConfig.stConfigPosolytPressureSegmentInlet, stEWConfig:= stUnitConfig.stEWLPosolytPressureSegmentInlet, stEWDelayConfig:= stUnitConfig.stEWDPosolytPressureSegmentInlet, xReleaseErrors:= xReleaseErrors, xReleaseLimitErrors:= xReleaseLimitErrors AND _fbPosolytPumpInlet.IsRunning AND _fbPosolytPumpInlet.xInTarget AND (NOT xStartBalancing), // AND (_fbPosolytPumpInlet.rSPautomatic > 40), xReleaseHardwareErrors:= xReleaseErrors, xConfirmAlarms:= xConfirmAlarms, stHMIInterface => stHMIInterface.stP11); // Filter pressure sensor data for HMI _rFilteredPressPosolytInlet := _rFilteredPressPosolytInlet * 0.9 + stHMIInterface.stP11.rValue * 0.1; stHMIInterface.stP11.rValue := _rFilteredPressPosolytInlet; // Set modbus error register bits IF _fbPressurePosolytSegmentInlet.xErrorLow THEN stModbusErrors.stBitmap.bPInPosLow := 1; END_IF IF _fbPressurePosolytSegmentInlet.xErrorHigh THEN stModbusErrors.stBitmap.bPInPosHigh := 1; END_IF IF _fbPressurePosolytSegmentInlet.xError THEN stModbusErrors.stBitmap.bPInPosError := 1; END_IF // Set modbus warning register bits IF _fbPressurePosolytSegmentInlet.xWarningLow THEN stModbusWarnings.stBitmap.bPInPosLow := 1; END_IF IF _fbPressurePosolytSegmentInlet.xWarningHigh THEN stModbusWarnings.stBitmap.bPInPosHigh := 1; END_IF // Set error active if fb has error IF _fbPressurePosolytSegmentInlet.xError THEN _xErrorActive := TRUE; END_IF // Set warning if fb has warning IF _fbPressurePosolytSegmentInlet.xWarning THEN _xWarningActive := TRUE; END_IF // =============================== // Pressure sensors negolyt segment inlet // =============================== _fbPressureNegolytSegmentInlet( stScalingConfig:= stUnitConfig.stConfigNegolytPressureSegmentInlet, stEWConfig:= stUnitConfig.stEWLNegolytPressureSegmentInlet, stEWDelayConfig:= stUnitConfig.stEWDNegolytPressureSegmentInlet, xReleaseErrors:= xReleaseErrors, xReleaseLimitErrors:= xReleaseLimitErrors AND _fbNegolytPumpInlet.IsRunning AND _fbNegolytPumpInlet.xInTarget AND (NOT xStartBalancing),// AND (_fbNegolytPumpInlet.rSPautomatic > 40), xReleaseHardwareErrors:= xReleaseErrors, xConfirmAlarms:= xConfirmAlarms, stHMIInterface => stHMIInterface.stP21); // Filter pressure sensor data for HMI _rFilteredPressNegolytInlet := _rFilteredPressNegolytInlet * 0.9 + stHMIInterface.stP21.rValue * 0.1; stHMIInterface.stP21.rValue := _rFilteredPressNegolytInlet; // Set modbus error register bits IF _fbPressureNegolytSegmentInlet.xErrorLow THEN stModbusErrors.stBitmap.bPInNegLow := 1; END_IF IF _fbPressureNegolytSegmentInlet.xErrorHigh THEN stModbusErrors.stBitmap.bPInNegHigh := 1; END_IF IF _fbPressureNegolytSegmentInlet.xError THEN stModbusErrors.stBitmap.bPInNegError := 1; END_IF // Set modbus warning register bits IF _fbPressureNegolytSegmentInlet.xWarningLow THEN stModbusWarnings.stBitmap.bPInNegLow := 1; END_IF IF _fbPressureNegolytSegmentInlet.xWarningHigh THEN stModbusWarnings.stBitmap.bPInNegHigh := 1; END_IF // Set error active if fb has error IF _fbPressureNegolytSegmentInlet.xError THEN _xErrorActive := TRUE; END_IF // Set warning if fb has warning IF _fbPressureNegolytSegmentInlet.xWarning THEN _xWarningActive := TRUE; END_IF // =============================== // Pressure sensors posolyt tank inlet // =============================== _fbPressurePosolytTankInlet( stScalingConfig:= stUnitConfig.stConfigPosolytPressureTankInlet, stEWConfig:= stUnitConfig.stEWLPosolytPressureTankInlet, stEWDelayConfig:= stUnitConfig.stEWDPosolytPressureTankInlet, xReleaseErrors:= xReleaseErrors, xReleaseLimitErrors:= xReleaseLimitErrors, xReleaseHardwareErrors:= xReleaseErrors, xConfirmAlarms:= xConfirmAlarms, stHMIInterface => stHMIInterface.stP12); // Filter pressure sensor data for HMI _rFilteredPressPosolytTank := _rFilteredPressPosolytTank * 0.9 + stHMIInterface.stP12.rValue * 0.1; stHMIInterface.stP12.rValue := _rFilteredPressPosolytTank; // Set modbus error register bits IF _fbPressurePosolytTankInlet.xErrorLow THEN stModbusErrors.stBitmap.bPTankPosLow := 1; END_IF IF _fbPressurePosolytTankInlet.xErrorHigh THEN stModbusErrors.stBitmap.bPTankPosHigh := 1; END_IF IF _fbPressurePosolytTankInlet.xError THEN stModbusErrors.stBitmap.bPTankPosError := 1; END_IF // Set modbus warning register bits IF _fbPressurePosolytTankInlet.xWarningLow THEN stModbusWarnings.stBitmap.bPTankPosLow := 1; END_IF IF _fbPressurePosolytTankInlet.xWarningHigh THEN stModbusWarnings.stBitmap.bPTankPosHigh := 1; END_IF // Set error active if fb has error IF _fbPressurePosolytTankInlet.xError THEN _xErrorActive := TRUE; END_IF // Set warning if fb has warning IF _fbPressurePosolytTankInlet.xWarning THEN _xWarningActive := TRUE; END_IF // =============================== // Pressure sensors negolyt tank inlet // =============================== _fbPressureNegolytTankInlet( stScalingConfig:= stUnitConfig.stConfigNegolytPressureTankInlet, stEWConfig:= stUnitConfig.stEWLNegolytPressureTankInlet, stEWDelayConfig:= stUnitConfig.stEWDNegolytPressureTankInlet, xReleaseErrors:= xReleaseErrors, xReleaseLimitErrors:= xReleaseLimitErrors, xReleaseHardwareErrors:= xReleaseErrors, xConfirmAlarms:= xConfirmAlarms, stHMIInterface => stHMIInterface.stP22); // Filter pressure sensor data for HMI _rFilteredPressNegolytTank := _rFilteredPressNegolytTank * 0.9 + stHMIInterface.stP22.rValue * 0.1; stHMIInterface.stP22.rValue := _rFilteredPressNegolytTank; // Set modbus error register bits IF _fbPressureNegolytTankInlet.xErrorLow THEN stModbusErrors.stBitmap.bPTankNegLow := 1; END_IF IF _fbPressureNegolytTankInlet.xErrorHigh THEN stModbusErrors.stBitmap.bPTankNegHigh := 1; END_IF IF _fbPressureNegolytTankInlet.xError THEN stModbusErrors.stBitmap.bPTankNegError := 1; END_IF // Set modbus warning register bits IF _fbPressureNegolytTankInlet.xWarningLow THEN stModbusWarnings.stBitmap.bPTankNegLow := 1; END_IF IF _fbPressureNegolytTankInlet.xWarningHigh THEN stModbusWarnings.stBitmap.bPTankNegHigh := 1; END_IF // Set error active if fb has error IF _fbPressureNegolytTankInlet.xError THEN _xErrorActive := TRUE; END_IF // Set warning if fb has warning IF _fbPressureNegolytTankInlet.xWarning THEN _xWarningActive := TRUE; END_IF // =============================== // Temperature sensor posolyt tank inlet // =============================== _fbTempSensorPosolyt( stScalingConfig:= stUnitConfig.stConfigPosolytTempTankInlet, stEWConfig:= GVL_CONFIG.stUnitConfig.stEWLPosolytTempTankInlet, stEWDelayConfig:= GVL_CONFIG.stUnitConfig.stEWDPosolytTempTankInlet, xReleaseErrors:= xReleaseErrors, xReleaseLimitErrors:= xReleaseLimitErrors, xReleaseHardwareErrors:= xReleaseErrors, xConfirmAlarms:= xConfirmAlarms, stHMIInterface=> stHMIInterface.stT11); // Set modbus error register bits IF _fbTempSensorPosolyt.xErrorLow THEN stModbusErrors.stBitmap.bTPosLow := 1; END_IF IF _fbTempSensorPosolyt.xErrorHigh THEN stModbusErrors.stBitmap.bTPosHigh := 1; END_IF IF _fbTempSensorPosolyt.xError THEN stModbusErrors.stBitmap.bTPosError := 1; END_IF // Set modbus warning register bits IF _fbTempSensorPosolyt.xWarningLow THEN stModbusWarnings.stBitmap.bTPosLow := 1; END_IF IF _fbTempSensorPosolyt.xWarningHigh THEN stModbusWarnings.stBitmap.bTPosHigh := 1; END_IF IF _fbTempSensorPosolyt.xError THEN _xErrorActive := TRUE; END_IF IF _fbTempSensorPosolyt.xWarning THEN _xWarningActive := TRUE; END_IF // =============================== // Temperature sensor negolyt tank inlet // =============================== _fbTempSensorNegolyt( stScalingConfig:= stUnitConfig.stConfigNegolytTempTankInlet, stEWConfig:= GVL_CONFIG.stUnitConfig.stEWLNegolytTempTankInlet, stEWDelayConfig:= GVL_CONFIG.stUnitConfig.stEWDNegolytTempTankInlet, xReleaseErrors:= xReleaseErrors, xReleaseLimitErrors:= xReleaseLimitErrors, xReleaseHardwareErrors:= xReleaseErrors, xConfirmAlarms:= xConfirmAlarms, stHMIInterface=> stHMIInterface.stT21); // Set modbus error register bits IF _fbTempSensorNegolyt.xErrorLow THEN stModbusErrors.stBitmap.bTNegLow := 1; END_IF IF _fbTempSensorNegolyt.xErrorHigh THEN stModbusErrors.stBitmap.bTNegHigh := 1; END_IF IF _fbTempSensorNegolyt.xError THEN stModbusErrors.stBitmap.bTNegError := 1; END_IF // Set modbus warning register bits IF _fbTempSensorNegolyt.xWarningLow THEN stModbusWarnings.stBitmap.bTNegLow := 1; END_IF IF _fbTempSensorNegolyt.xWarningHigh THEN stModbusWarnings.stBitmap.bTNegHigh := 1; END_IF IF _fbTempSensorNegolyt.xError THEN _xErrorActive := TRUE; END_IF IF _fbTempSensorNegolyt.xWarning THEN _xWarningActive := TRUE; END_IF // =============================== // Voltage segment // =============================== _fbVoltageSegment( stScalingConfig:= GVL_CONFIG.stUnitConfig.stConfigVoltageSegment, stEWConfig:= GVL_CONFIG.stUnitConfig.stEWLVoltageSegment, stEWDelayConfig:= GVL_CONFIG.stUnitConfig.stEWDVoltageSegment, xReleaseErrors:= xReleaseErrors, xReleaseLimitErrors:= xReleaseLimitErrors AND _xEnableVoltageLimitChecks, xReleaseHardwareErrors:= xReleaseErrors, xConfirmAlarms:= xConfirmAlarms, stHMIInterface=> stHMIInterface.stE31, rScaledValue => rCurrentVoltage); // Set modbus error register bits IF _fbVoltageSegment.xErrorLow THEN stModbusErrors.stBitmap.bVLow := 1; END_IF IF _fbVoltageSegment.xErrorHigh THEN stModbusErrors.stBitmap.bVHigh := 1; END_IF IF _fbVoltageSegment.xError THEN stModbusErrors.stBitmap.bVError := 1; END_IF // Set modbus warning register bits IF _fbVoltageSegment.xWarningLow THEN stModbusWarnings.stBitmap.bVLow := 1; END_IF IF _fbVoltageSegment.xWarningHigh THEN stModbusWarnings.stBitmap.bVHigh := 1; END_IF // Set error active if fb has error IF _fbVoltageSegment.xError THEN _xErrorActive := TRUE; END_IF // Set warning if fb has warning IF _fbVoltageSegment.xWarning THEN _xWarningActive := TRUE; END_IF // =============================== // Check for EStop // =============================== IF (NOT xEmergencyStopOk) THEN _xErrorActive := TRUE; END_IF // =============================== // Write Voltage to HMI // =============================== stHMIInterface.rVoltage := stHMIInterface.rVoltage * 0.9 + _fbVoltageSegment.rScaledValue * 0.1; // =============================== // Check for pressure difference // =============================== _xDeltaPSegmentInletToHigh := (ABS(_fbPressurePosolytSegmentInlet.rScaledValue - _fbPressureNegolytSegmentInlet.rScaledValue) > GVL_CONFIG.stUnitConfig.rMaxDeltaPSegmentInlet); _xReleaseSignalDeltaPSegment( xSignal:= _xDeltaPSegmentInletToHigh, xRelease:= _xEnableCheckForDeltaPSegmentInlet, timOnDelay:= T#5S, timOffDelay:= T#2S, xReleaseSignal=> _xErrorDeltaPSegmentInlet); IF _xErrorDeltaPSegmentInlet AND (NOT _fbPressureDiffToBig.bRaised) THEN _fbPressureDiffToBig.Raise(0); END_IF IF (NOT _xErrorDeltaPSegmentInlet) AND _fbPressureDiffToBig.bRaised THEN _fbPressureDiffToBig.Clear(0, FALSE); END_IF IF _fbPressureDiffToBig.eConfirmationState = TcEventConfirmationState.WaitForConfirmation THEN _fbPressureDiffToBig.Confirm(0); END_IF IF _xErrorDeltaPSegmentInlet THEN _xErrorActive := TRUE; END_IF // =============================== // Check if all components are in automatic // =============================== _xAllComponentsInAutomatic := _fbPosolytValveTankOutlet.IsInAutomaticMode AND _fbNegolytValveTankOutlet.IsInAutomaticMode AND _fbPosolytPumpInlet.IsInAutomaticMode AND _fbNegolytPumpInlet.IsInAutomaticMode; // Raise warning IF NOT _fbNotAllAutomaticAlarm.bRaised AND (NOT _xAllComponentsInAutomatic) AND (NOT xAllToManualMode) THEN _fbNotAllAutomaticAlarm.Raise(0); END_IF // Clear warning and reset IF _fbNotAllAutomaticAlarm.bRaised AND _xAllComponentsInAutomatic THEN _fbNotAllAutomaticAlarm.Clear(0, TRUE); END_IF // Calculate shutdown discharge threshold _rShutdownDischargeVoltageThreshold := GVL_CONFIG.rMinimumUnitVoltage + GVL_CONFIG.rDeltaUnitVoltageShutdownDischarge; // =============================== // Run state machine for startup // and shutdown // NEEDS TO BE CALLED AFTER ALL COMPONENTS BECAUSE OF RESET AND ALARM ACKNOWLEDGEMENT!!! // (e.g. restart pumps after estop if segment voltage is still to high) // =============================== StateMachine(); // =============================== // Output error and warning flags // =============================== xError := _xErrorActive; xWarning := _xWarningActive; IF (NOT xSafetyIntlksOk) THEN stModbusErrors.stBitmap.bSafetyIntlk := 1; END_IF // =============================== // Reset modbus error register with alarm confirmation // =============================== IF xConfirmAlarms THEN stModbusErrors.dwRegister := 0; stModbusWarnings.dwRegister := 0; END_IF // =============================== // Handle general error message // =============================== IF xError AND (NOT _fbUnitError.bRaised) THEN _fbUnitError.Raise(0); END_IF IF (NOT xError) AND _fbUnitError.bRaised THEN _fbUnitError.Clear(0, FALSE); END_IF IF _fbUnitError.eConfirmationState = TcEventConfirmationState.WaitForConfirmation AND xConfirmAlarms THEN _fbUnitError.Confirm(0); END_IF // =============================== // Output all components in auto mode // =============================== xAllComponentsInAuto := _xAllComponentsInAutomatic;]]> = GVL_CONFIG.rMinimumUnitVoltage) OR xInSafetyCheckMode) AND (NOT _xErrorActive) AND (NOT _xWarningActive) THEN _tonVoltageCheckTimeput(IN := FALSE); xReady := TRUE; // Only enable Voltage Checks if not in safety check mode IF (NOT xInSafetyCheckMode) THEN _xEnableVoltageLimitChecks := TRUE; END_IF // Continue on normal startup path IF xEnable THEN stHMIInterface.eStatus := E_COMPONENT_STATUS.ON; _iState := 35; END_IF END_IF IF _tonVoltageCheckTimeput.Q OR _xErrorActive THEN _tonVoltageCheckTimeput(IN := FALSE); xError := TRUE; _iState := 900; END_IF // If enable signal is lost, goto shutdown IF (NOT xEnable) THEN _iState := 40; END_IF 35: // Unit in enabled state _rSetpointNegolytPumpInlet := GVL_CONFIG.rPumpNegolytOnPower; _rSetpointPosolytPumpInlet := GVL_CONFIG.rPumpPosolytOnPower; IF (NOT xEnable) THEN stHMIInterface.eStatus := E_COMPONENT_STATUS.SHUTDOWN; _iState := 40; END_IF // Goto error shutdown if an error occured IF _xErrorActive THEN _iState := 900; END_IF 40: // Close all valves _fbNegolytValveTankOutlet.ReqAutomaticClose(); _fbPosolytValveTankOutlet.ReqAutomaticClose(); xReady := FALSE; _iState := 45; 45: // Wait for valves to be closed IF _fbNegolytValveTankOutlet.IsClosed AND _fbPosolytValveTankOutlet.IsClosed THEN xInShutdownDischargeMode := TRUE; IF (_fbVoltageSegment.rScaledValue > _rShutdownDischargeVoltageThreshold) THEN xShutdownDischargeAllowed := TRUE; ELSE xShutdownDischargeAllowed := FALSE; END_IF _iState := 50; END_IF // When there is an error trying to close the valves, // dont try to discharge the segment IF _fbNegolytValveTankOutlet.xError OR _fbPosolytValveTankOutlet.xError THEN _xEnableVoltageLimitChecks := FALSE; _iState := 60; END_IF // Check for restart condition IF xEnable AND (NOT _xErrorActive) THEN _iState := 0; END_IF 50: // Wait for unit voltage to drop below a certain threshold IF (_fbVoltageSegment.rScaledValue > _rShutdownDischargeVoltageThreshold) AND xInverterEnabled THEN xShutdownDischargeAllowed := TRUE; ELSE xShutdownDischargeAllowed := FALSE; _xEnableVoltageLimitChecks := FALSE; _rSetpointNegolytPumpInlet := GVL_CONFIG.rPumpNegolytDisChrgPower; _rSetpointPosolytPumpInlet := GVL_CONFIG.rPumpPosolytDisChrgPower; _xEnableCheckForDeltaPSegmentInlet := FALSE; _iState := 51; END_IF // Check for restart condition IF (xEnable OR xStartBalancing) AND (NOT _xErrorActive) THEN xShutdownDischargeAllowed := FALSE; xInShutdownDischargeMode := FALSE; _iState := 0; END_IF IF _xErrorActive THEN _iState := 1000; END_IF 51: // Discharge without inverter _rSetpointNegolytPumpInlet := GVL_CONFIG.rPumpNegolytDisChrgPower; _rSetpointPosolytPumpInlet := GVL_CONFIG.rPumpPosolytDisChrgPower; IF (_fbVoltageSegment.rScaledValue <= GVL_CONFIG.rPumpshutoffThreshold) THEN xShutdownDischargeAllowed := FALSE; xInShutdownDischargeMode := FALSE; _iState := 60; END_IF // Check for restart condition IF xEnable AND (NOT _xErrorActive) THEN xShutdownDischargeAllowed := FALSE; xInShutdownDischargeMode := FALSE; _iState := 0; END_IF IF _xErrorActive THEN _iState := 1000; END_IF 60: // Disable pumps _fbPosolytPumpInlet.ReqAutomaticStop(); _fbNegolytPumpInlet.ReqAutomaticStop(); _iState := 65; 65: // Wait for pumps to be stopped IF _fbPosolytPumpInlet.IsStopped AND _fbNegolytPumpInlet.IsStopped THEN xOff := TRUE; _xReleaseManualMode := TRUE; IF NOT _xErrorActive THEN stHMIInterface.eStatus := E_COMPONENT_STATUS.OFF; _iState := 0; END_IF END_IF // Check for restart condition IF xEnable AND (NOT _xErrorActive) THEN stHMIInterface.eStatus := E_COMPONENT_STATUS.OFF; _iState := 0; END_IF // Check for error IF _xErrorActive THEN _iState := 1000; END_IF 69: // Check for minimum voltage IF (_fbVoltageSegment.rScaledValue <= GVL_CONFIG.rMinimumUnitVoltage) THEN _iState := 900; ELSE _rBalancingTargetVoltage := rBalancingTargetVoltage; _istate := 70; END_IF 70: // Wait for segment voltage to be in the range of the target voltage IF (_fbVoltageSegment.rScaledValue <= _rBalancingTargetVoltage) THEN xBalancingDone := TRUE; _iState := 71; END_IF // If enable signal is lost, goto shutdown IF (NOT xStartBalancing) THEN _iState := 40; END_IF IF _xErrorActive THEN _iState := 900; END_IF 71: // Close valves _fbNegolytValveTankOutlet.ReqAutomaticClose(); _fbPosolytValveTankOutlet.ReqAutomaticClose(); xReady := FALSE; _iState := 72; 72: // Wait for all valves to be closed IF _fbNegolytValveTankOutlet.IsClosed AND _fbPosolytValveTankOutlet.IsClosed THEN xInShutdownDischargeMode := TRUE; _rSetpointNegolytPumpInlet := GVL_CONFIG.rPumpNegolytDisChrgPower; _rSetpointPosolytPumpInlet := GVL_CONFIG.rPumpPosolytDisChrgPower; _iState := 73; END_IF 73: // Wait for start balancing signal to be off to prevent automatic restart IF (NOT xStartBalancing) THEN _iState := 50; END_IF 700: // Debug step IF (NOT xStartBalancing) THEN _iState := 40; END_IF 900: // Soft error shutdown _fbNegolytValveTankOutlet.ReqAutomaticClose(); _fbPosolytValveTankOutlet.ReqAutomaticClose(); _xEnableCheckForDeltaPSegmentInlet := FALSE; _rSetpointNegolytPumpInlet := GVL_CONFIG.rPumpNegolytDisChrgPower; _rSetpointPosolytPumpInlet := GVL_CONFIG.rPumpPosolytDisChrgPower; _fbNegolytPumpInlet.ReqAutomaticStart(); _fbPosolytPumpInlet.ReqAutomaticStart(); _xEnableVoltageLimitChecks := FALSE; xShutdownDischargeAllowed := FALSE; xInShutdownDischargeMode := FALSE; xReady := FALSE; _iState := 910; 910: // Wait for discharged or restart IF (_fbVoltageSegment.rScaledValue <= GVL_CONFIG.rPumpshutoffThreshold) THEN xShutdownDischargeAllowed := FALSE; xInShutdownDischargeMode := FALSE; _iState := 1000; END_IF // Check for restart condition IF (NOT xEnable) AND xError THEN xError := FALSE; END_IF IF (NOT xError) AND (xEnable OR xStartBalancing) THEN _iState := 0; END_IF IF _xErrorActive THEN _iState := 1000; END_IF 1000: // Error shutdown stHMIInterface.eStatus := E_COMPONENT_STATUS.ERROR; _fbNegolytValveTankOutlet.ReqAutomaticClose(); _fbPosolytValveTankOutlet.ReqAutomaticClose(); _rSetpointNegolytPumpInlet := GVL_CONFIG.rPumpNegolytDisChrgPower; _rSetpointPosolytPumpInlet := GVL_CONFIG.rPumpPosolytDisChrgPower; //_fbPosolytPumpInlet.ReqAutomaticStop(); //_fbNegolytPumpInlet.ReqAutomaticStop(); _xEnableVoltageLimitChecks := FALSE; xShutdownDischargeAllowed := FALSE; xInShutdownDischargeMode := FALSE; xReady := FALSE; xOff := TRUE; xError := TRUE; _iState := 1001; 1001: // Alarm active // Only allow reset when enable is deactivated to avoid an // automatic restart of the unit IF (NOT _xErrorActive) AND (NOT xEnable) AND (NOT xStartBalancing) AND _xPumpsReady AND xConfirmAlarms THEN xError := FALSE; IF (_fbVoltageSegment.rScaledValue >= GVL_CONFIG.rPumpshutoffThreshold) THEN _iState := 1002; ELSE _iState := 0; END_IF END_IF 1002: _rSetpointNegolytPumpInlet := GVL_CONFIG.rPumpNegolytDisChrgPower; _rSetpointPosolytPumpInlet := GVL_CONFIG.rPumpPosolytDisChrgPower; _fbNegolytPumpInlet.ReqAutomaticStart(); _fbPosolytPumpInlet.ReqAutomaticStart(); _iState := 51; END_CASE]]>