// method can be called twice every cycle: from application AND MTL_Node.cyclic()->_errorHandler()->error()
IF (THIS^.diCurrTaskIndex = 0) THEN
	THIS^.diCurrTaskIndex := Tc2_System.GETCURTASKINDEXEX();			// get current task index
END_IF
IF (THIS^.diCurrTaskIndex > 0) THEN
	THIS^.udiRefCycleCount REF=TwinCAT_SystemInfoVarList._TaskInfo[THIS^.diCurrTaskIndex].CycleCount;
	IF (THIS^.udiCycleCountOld <> THIS^.udiRefCycleCount) THEN	// first call in this task-cycle ->continue
		THIS^.udiCycleCountOld := THIS^.udiRefCycleCount;		// safe current value
	ELSE	// 2. call in this task-cycle
		IF (xSavedCondition = xCondition) THEN	// input not changed in 2. call in same task-cycle -> nothing more to do
			// need to set output
			IF (udiAssertStep = 0) THEN		// error was active and now quitted in this task-cycle in previous call
				assert	:= FALSE;
			ELSE							// all other steps: error is active
				assert	:= TRUE;
			END_IF
			RETURN;		// -> go out
		ELSE
			// proceed: input-value has changed and needs to be processed
		END_IF
	END_IF
END_IF

// check once if provided values are valid
IF (THIS^.eAlarmClassOld <> THIS^.eClass) AND (xCondition) THEN
	CASE eClass OF
		PopUpMessage, PopUpMessage_NoAck, Message, Message_NoAck, PopUpWarning, PopUpWarning_NoAck, Warning, Warning_NoAck, Alarm, Alarm_SingleAck:
			// do nothing: eAlarmClass is valid
		ELSE
			SUPER^.logmsg(MTL_eLogLevel.ERROR, tc2_Standard.CONCAT('Application-Error: Unsupported value for ErrorClass: 0x', DWORD_TO_HEXSTR(DINT_TO_DWORD(eClass),1,FALSE)));
	END_CASE
	IF (THIS^.udiError = 0) THEN
		sTmp				:= Tc2_Utilities.F_ToUCase(SUPER^.Name);
		IF (0 = Tc2_Standard.FIND(sTmp, GVL_Error.gc_sMtlSystem)) THEN
			SUPER^.logmsg(MTL_eLogLevel.WARNING , 'Application-Error: udiError not set. Errornumber can not be queried / active error can not be identified.');
		END_IF
		sTmp				:= '';
	END_IF
	CASE eStopMode OF
		MTL_eStopMode.None, MTL_eStopMode.Cancel, MTL_eStopMode.Abort, MTL_eStopMode.Stop, MTL_eStopMode.Pause:
			// do nothing: eStopMode is valid
		ELSE
			SUPER^.logmsg(MTL_eLogLevel.ERROR, 'Application-Error: no valid StopMode set');
	END_CASE
	CASE dwLightTowerClass OF
		MTL_eLightTower.OFF, NO_PRODUCTION, PRODUCTION, LOGIC_WARNING, PROCESS_WARNING, STATION_ALARM, QUALITY_ALARM, QUALITY_STOPP:
			// do nothing: dwLightTowerClass is valid
		ELSE
			SUPER^.logmsg(MTL_eLogLevel.ERROR, 'Application-Error: no valid LigthTowerClass set');
	END_CASE
	IF (sInfo = '') THEN
		SUPER^.logmsg(MTL_eLogLevel.WARNING, 'Application-Error: sInfo not set. No info-logmessage will be generated when error is active.');
	END_IF
	THIS^.eAlarmClassOld	:= THIS^.eClass;
END_IF

// store condition for asynchron handling
xSavedCondition := xCondition;

CASE udiAssertStep OF
	0: // wait for error
		// node is deactivated and no new error is allowed to be set.
		// check is done in this place since existing/active errors must be reset/released (at the time when node is deactivated)
		IF THIS^.xDeactivated THEN
			RETURN;
		END_IF

		IF xCondition THEN
			xQuit		:= FALSE;
			xActive		:= TRUE;			// signal SCADA system error is active
			xError		:= TRUE;			// signal to errorhandler error is active
			xResetError	:= FALSE;			// remove reset request
			// get stop mode text for log message
			CASE eStopMode OF
				MTL_eStopMode.Cancel:	sTmp	:= ' (StopMode: Cancel)';
				MTL_eStopMode.Abort:	sTmp	:= ' (StopMode: Abort)';
				MTL_eStopMode.Stop:		sTmp	:= ' (StopMode: Stop)';
			END_CASE
			logmsg(MTL_eLogLevel.MESSAGE, Tc2_Standard.CONCAT(sInfo, sTmp));

			THIS^.itfMtlError.mNewErrorActive();
			GVL_Error.errorList.addToList(sInfo, name, eClass);

			itfMesError				:= THIS^.itfMtlError.mGetMesHandler();		// this might have been added later from application
			IF (itfMesError <> 0) AND (stMesError.udiErrorId <> 0) THEN
				itfMesError.mSendError(xActive := TRUE, udiMesErrorId := stMesError.udiErrorId, eMesErrorClass := stMesError.eClass, sMesErrorText := stMesError.sText, sMTLErrorText := 'MtlError');
			END_IF
			THIS^.xSCADAConfigured	:= THIS^.itfMtlError.mSCADAExists();	// set actual status

			THIS^.tActivationTime	:= TIME();			// store starting time
			THIS^.tDuration			:= T#0S;			// clear out old value

			udiAssertStep			:= 20;
		END_IF

		assert := xCondition;

	1: // condition reappeared
		xQuit		:= FALSE;
		xActive		:= TRUE;			// signal SCADA system error is active
		xError		:= TRUE;			// signal to errorhandler error is active
		xResetError	:= FALSE;			// remove reset request
		logmsg(MTL_eLogLevel.MESSAGE, Tc2_Standard.CONCAT(sInfo, ' (Condition reappeared)'));

		udiAssertStep := 20;

		assert := TRUE;

	20: // wait for confirmation from SCADA / stay in step if error is in SCADA not browsed (and generate a logmessage)
		THIS^.xSCADAConfigured			:= THIS^.itfMtlError.mSCADAExists();	// set actual status
		IF (NOT THIS^.xSCADAConfigured) OR ((DINT_TO_DWORD(eClass) AND GVL_Error.NOACK_BIT) = GVL_Error.NOACK_BIT) THEN
			udiAssertStep				:= 30;
		ELSE		// SCADA is configured: waiting for reaction from SCADA in bState (if error is browsed)
			IF (bState = MTL_eAlarmState.ACTIVE) OR (bState = MTL_eAlarmState.ACTIVE_BUT_QUIT) THEN
				IF xLogMsgSend THEN
					SUPER^.logmsg(MTL_eLogLevel.WARNING, 'SCADA is connected and handles the error');
					xLogMsgSend		:= FALSE;
				END_IF
				xPlcRestarted		:= FALSE;
				udiAssertStep		:= 30;
			ELSIF (bState = MTL_eAlarmState.SCADA_NOT_HANDLED) THEN			// No reaction from SCADA==> STAY FOREVER in this state if no reaction is seen from SCADA !!!
				THIS^.xScadaIsConnected	:= THIS^.itfMtlError.mSCADAIsConnected();
				IF (THIS^.xScadaIsConnected) THEN						// wait until SCADA is connected -> if error is browsed the bState will be changed
					IF (NOT xLogMsgSend) THEN							// generate logmessage only once
						tonWaitForScada(PT := T#1S, IN := TRUE);		// start timer to check if SCADA reacts => detection if MTL_fbError is browsed in SCADEA
						IF (tonWaitForScada.Q) THEN						// timer expired => no change from SCADA => error not browsed
							IF (NOT xPlcRestarted) THEN
								SUPER^.logmsg(MTL_eLogLevel.ERROR, 'Application Error: Error is not browsed in SCADA!! Error is NOT quit (continiously active) !!!');
								xLogMsgSend		:= TRUE;						// prevent multiple errorlogmessages
							ELSE
								xPlcRestarted	:= FALSE;
								xActive			:= FALSE;
								udiAssertStep	:= 21;
							END_IF
							tonWaitForScada(IN := FALSE);
						END_IF
					END_IF
				END_IF
			END_IF
		END_IF
		assert := TRUE;
		
	21: // try to get back the visiwin manager connection
		tonWaitForScada(PT := T#1S, IN := TRUE);
		IF (bState <> MTL_eAlarmState.SCADA_NOT_HANDLED) OR (tonWaitForScada.Q) THEN
			tonWaitForScada(IN := FALSE);
			xActive			:= TRUE;
			udiAssertStep	:= 20;
		END_IF
		assert := TRUE;
	
	30: // wait until condition is gone
		IF NOT xCondition THEN
			udiAssertStep	:= 40;
			xActive			:= FALSE;
			xQuit			:= FALSE;
		END_IF

		assert := TRUE;

	40: // wait until SCADA has handled error

		// condition appears again	 -> start from the beginning
		IF xCondition THEN
			IF THIS^.xDeactivated THEN
				udiAssertStep := 50;	// go out: node is deactivated and error does not need to be active any longer.
			ELSE
				udiAssertStep := 1;
			END_IF
		END_IF

		IF ((DINT_TO_DWORD(eClass) AND GVL_Error.NOACK_BIT) = GVL_Error.NOACK_BIT) THEN
			udiAssertStep := 50;

		ELSE
			IF xSCADAConfigured THEN
				IF bState = MTL_eAlarmState.ACTIVE
				OR bState = MTL_eAlarmState.REACTIVATED
				OR bState = MTL_eAlarmState.GONE_WITHOUT_QUIT
				OR bState = MTL_eAlarmState.ACTIVE_BUT_QUIT
				OR bState = MTL_eAlarmState.GONE_WITH_QUIT THEN
					;

				ELSIF (bState = MTL_eAlarmState.NO_ACTIVE) THEN
					udiAssertStep := 50;

				ELSE
					logmsg(MTL_eLogLevel.WARNING, tc2_standard.CONCAT('Unexpected error state in assert method! value: ', BYTE_TO_STRING(bState)) );
					udiAssertStep := 50;

				END_IF

			ELSE
				IF (xQuit) OR (NOT xCondition) THEN
					udiAssertStep := 50;
				END_IF
			END_IF

		END_IF

		assert := TRUE;

	50:  // the final state
		xError		:= FALSE;		// error is handled
		assert		:= FALSE;		// every thing is fine
		xQuit		:= FALSE;		// reset xQuit flag
		xResetError	:= FALSE;		// reset reset flag

		THIS^.itfMtlError.mErrorQuit();
		GVL_Error.errorList.removeFromList(name);

		itfMesError := THIS^.itfMtlError.mGetMesHandler();
		IF (itfMesError <> 0) AND (stMesError.udiErrorId <> 0) THEN
			itfMesError.mSendError(xActive := FALSE, udiMesErrorId := stMesError.udiErrorId, eMesErrorClass := stMesError.eClass, sMesErrorText := stMesError.sText, sMTLErrorText := 'MtlError');
		END_IF

		THIS^.tDuration	:= TIME() - THIS^.tActivationTime;			// 

		IF ((THIS^.eClass = MTL_eAlarmClass.Alarm) OR (THIS^.eClass = MTL_eAlarmClass.Alarm_SingleAck)) THEN
			SUPER^.logmsg(MTL_eLogLevel.MESSAGE, tc2_Standard.CONCAT('finished alarm-handling. Duration: ', TIME_TO_STRING(THIS^.tDuration)) );
		ELSE
			SUPER^.logmsg(MTL_eLogLevel.TRACE,  tc2_Standard.CONCAT('finished handling', TIME_TO_STRING(THIS^.tDuration)) );
		END_IF

		// start from the begining
		THIS^.udiAssertStep := 0;

	ELSE
		THIS^.udiAssertStep := 0;
END_CASE

IF (udiAssertStepOld <> udiAssertStep) THEN
	sTmp := tc2_Standard.CONCAT(' New step: ', UDINT_TO_STRING(udiAssertStep));
	sTmp := tc2_Standard.CONCAT(sTmp, tc2_Standard.CONCAT(' bState: ', BYTE_TO_STRING(bState)) );;
	sTmp := tc2_Standard.CONCAT(sTmp, tc2_Standard.CONCAT(' xActive: ', BOOL_TO_STRING(xActive)) );
	sTmp := tc2_Standard.CONCAT(sTmp, tc2_Standard.CONCAT(' xQuit: ', BOOL_TO_STRING(xQuit)) );
	sTmp := tc2_Standard.CONCAT(sTmp, tc2_Standard.CONCAT(' xCondition: ', BOOL_TO_STRING(xCondition)) );
	SUPER^.logmsg(MTL_eLogLevel.TRACE, tc2_Standard.CONCAT(tc2_Standard.CONCAT('Actual Step: ', UDINT_TO_STRING(udiAssertStepOld)), sTmp) );
	udiAssertStepOld := udiAssertStep;
END_IF