FUNCTION_BLOCK "FB_StopperSpecial"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT 
      stInSensor : "UDT_Sensor";   // "IN" Sensor, bzw der Sensor kurz vor Stopper
      stInSensorNext : "UDT_Sensor";   // IN Sensor des folgenden Stoppers
      tInSenWait : Time := T#3000ms;   // Wartezeit zwischen Sensor und Stopper
      tInWaitAfterRelease : Time := T#2000ms;   // Wartezeit nach MT Release
   END_VAR
   VAR_INPUT RETAIN
      xInActive : Bool;   // Stopper aktiviert
   END_VAR
   VAR_INPUT 
      xInSwitchReq : Bool;   // Schalter zum Umschalten des Stoppers
      xInRelease : Bool;   // MT rauslassen
      xInReceive : Bool;   // MT aufnehmen
   END_VAR

   VAR_OUTPUT 
      nOutState : Int;   // Ausgang für aktuellen Schritt
   END_VAR
   VAR_OUTPUT RETAIN
      xOutClamp : Bool;   // MT Fixieren
      xOutStopper : Bool;   // MT Rauslassen
   END_VAR
   VAR_OUTPUT 
      xOutReleaseDone : Bool;   // Flanke dass MT rausgelassen
   END_VAR

   VAR RETAIN
      nState : Int;
   END_VAR
   VAR 
      fbStateManager : "FB_StateManager";
   END_VAR
   VAR RETAIN
      nCountSensor { S7_SetPoint := 'True'} : Int;   // Flankenzähler vom eigenen Sensor
      nCountSensorNext : Int;   // Flankenzähler vom nächsten Sensor
   END_VAR

   VAR_TEMP 
      tmpActUnivTon : Bool;
      xTmpCloseClamp : Bool;
      xTmpOpenStopper : Bool;
      xTmpReleaseDone : Bool;
   END_VAR

   VAR CONSTANT 
      cStepOff : Int := 0;
      cStepUndefined : Int := 100;
      cStepIdle : Int := 200;
      cStepReceive : Int := 300;
      cStepClamp : Int := 350;
      cStepHold : Int := 400;
      cStepRelease : Int := 500;
      cStepWait : Int := 600;
   END_VAR


BEGIN
	REGION Count Sensor
	    //zählt Sensorflanken vom In Sensor beim Einfahren,
	    //da sich der Sensor etwas weiter VOR dem Stopper befindet
	    IF #nState = #cStepReceive THEN
	        IF #stInSensor.xDirectEdgePos THEN
	            #nCountSensor += 1;
	        END_IF;
	    ELSE
	        #nCountSensor := 0;
	    END_IF;
	    
	    //zählt Sensorflanken vom nächsten Sensor beim Durchfahren,
	    //da dies die einzige Rückmeldung beim Ausfahren ist
	    IF #nState = #cStepRelease OR #nState = #cStepWait THEN
	        IF #stInSensorNext.xDirectEdgeNeg THEN
	            #nCountSensorNext += 1;
	        END_IF;
	    ELSE
	        #nCountSensorNext := 0;
	    END_IF;
	    
	END_REGION
	
	REGION Schrittkette
	    CASE #nState OF
	        #cStepOff:
	            REGION 000: Off
	                #nOutState := #cStepOff;
	                
	                IF #xInActive THEN
	                    #xTmpCloseClamp := FALSE;
	                    #xTmpOpenStopper := FALSE;
	                ELSE
	                    #xTmpCloseClamp := FALSE;
	                    #xTmpOpenStopper := TRUE;
	                END_IF;
	
	               
	            END_REGION
	            
	        #cStepUndefined:
	            REGION 100: Undefined
	                #nOutState := #cStepUndefined;
	                
	                IF #xInActive THEN
	                    #xTmpCloseClamp := FALSE;
	                    #xTmpOpenStopper := FALSE;
	                ELSE
	                    #xTmpCloseClamp := FALSE;
	                    #xTmpOpenStopper := TRUE;
	                END_IF;
	
	                //////////////////////////////////////
	                
	                #nState := #cStepIdle;
	                
	            END_REGION
	            
	        #cStepIdle:
	            REGION 200: Idle
	                #nOutState := #cStepIdle;
	                
	                IF #xInActive THEN
	                    #xTmpCloseClamp := FALSE;
	                    #xTmpOpenStopper := FALSE;
	                ELSE
	                    #xTmpCloseClamp := FALSE;
	                    #xTmpOpenStopper := TRUE;
	                END_IF;
	
	                ///////////////////////////////////////
	                
	                IF #xInReceive AND #xInActive THEN
	                    #nState := #cStepReceive;
	                END_IF;
	               
	            END_REGION
	            
	        #cStepReceive:
	            REGION 300: Receive
	                #nOutState := #cStepReceive;
	                
	                #xTmpCloseClamp := FALSE;
	                #xTmpOpenStopper := FALSE;
	                ///////////////////////////////////////
	                
	                // IF #stInSensor.xDirectEdgePos THEN
	                //     #nState := #cStepClamp;
	                // END_IF;
	                IF #nCountSensor >= 2 THEN
	                    #nState := #cStepClamp;
	                END_IF;
	                
	                
	            END_REGION
	            
	        #cStepClamp:
	            REGION 350: Clamp
	                #nOutState := #cStepClamp;
	                
	                #xTmpCloseClamp := FALSE;
	                #xTmpOpenStopper := FALSE;
	                ///////////////////////////////////////
	                
	                IF #fbStateManager.tOutTimeInStep > #tInSenWait THEN
	                    #xTmpCloseClamp := TRUE;
	                    #nState := #cStepHold;
	                END_IF;
	                
	            END_REGION
	            
	        #cStepHold:
	            REGION 400: Hold
	                #nOutState := #cStepHold;
	                
	                #xTmpCloseClamp := TRUE;
	                #xTmpOpenStopper := FALSE;
	                ///////////////////////////////////////
	                
	                IF #xInRelease THEN
	                    #xTmpCloseClamp := FALSE;
	                    #xTmpOpenStopper := TRUE;
	                    #nState := #cStepRelease;
	                END_IF;
	                    
	                
	            END_REGION
	            
	        #cStepRelease:
	            REGION 500: Release
	                #nOutState := #cStepRelease;
	                
	                #xTmpCloseClamp := FALSE;
	                #xTmpOpenStopper := TRUE;
	                ///////////////////////////////////////
	                IF (#xInSwitchReq) THEN
	                    #nState := #cStepWait;
	                ELSIF (NOT #xInSwitchReq AND #fbStateManager.tOutTimeInStep > #tInWaitAfterRelease) THEN
	                    #xTmpOpenStopper := TRUE;
	                    #xTmpReleaseDone := TRUE;
	                    #nState := #cStepIdle;//#cStepWait;
	                END_IF;
	                
	            END_REGION
	            
	        #cStepWait:
	            REGION 600: Wait
	                #nOutState := #cStepWait;
	                
	                #xTmpCloseClamp := FALSE;
	                #xTmpOpenStopper := TRUE;
	                ///////////////////////////////////////
	                
	                IF #nCountSensorNext >= 2 THEN
	                    #xTmpReleaseDone := TRUE;
	                    #nState := #cStepIdle;
	                END_IF;
	                
	            END_REGION
	            
	        ELSE  // Statement section ELSE
	          
	            
	            #nState := #cStepUndefined;
	    END_CASE;
	END_REGION
	
	REGION State Manager
	    #fbStateManager.stInSettings.nStartState := #cStepUndefined;
	    #fbStateManager.stInSettings.xActUnivTOn := TRUE;
	    #fbStateManager.stInSettings.xRestartAtStartState := FALSE;
	    #fbStateManager(xInFunctionEnabled := TRUE,
	                    xInRunUnivTOn := #tmpActUnivTon,
	                    nInOutState := #nState);
	END_REGION
	
	REGION Ausgänge
	    #xOutClamp := #xTmpCloseClamp;
	    #xOutStopper := #xTmpOpenStopper;
	    #xOutReleaseDone := #xTmpReleaseDone;
	END_REGION ;
END_FUNCTION_BLOCK

