FUNCTION_BLOCK "FB_BoomWorkStation"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT 
      xInRunning : Bool;
      xInSwitchPosition2 : Bool;   // true=Position 2 aktivieren, also Stopper 1!
      xInReceivingMT : Bool;   // MT empfangen
      xInReleaseMT : Bool;   // MT rauslassen
      stInSenStopper1 : "UDT_Sensor";   // "IN" Sensor, bzw der Sensor kurz vor Stopper 1
      stInSenStopper2 : "UDT_Sensor";   // IN Sensor des Stopper 2
      stInSenJamExit1 : "UDT_Sensor";   // Sensor Stau vor Vario am Ausgang
      stInSenJamExit2 : "UDT_Sensor";   // Sensor Stau am Ende von Vario
      tInSenWaitStopper1 : Time := T#300ms;   // Wartezeit zwischen Sensor und Stopper
      tInWaitAfterReleaseStopper1 : Time := T#4000ms;   // Wartezeit nach MT Release
      tInWaitBeforeSwitchStopper2 : Time := T#4000ms;   // Wartezeit bevor von Stopper 1 zu Stopper 2 geschalten werden kann nachdem ein Teil losgeschickt wurde
      tInTrailingStopper2 : Time := T#1500ms;   // Zeit wie lange ohne Belegung offen sein muss
   END_VAR

   VAR_OUTPUT 
      xOutStationMovement : Bool;
      xOutReadyForReceiving : Bool;
      nOutState : Int;
      xOutStopper1Clamp : Bool;
      xOutStopper1 : Bool;
      xOutStopper2 : Bool;
   END_VAR

   VAR_IN_OUT 
      arInOutCarrierStopper : Array[1..1] of "stCarrier";   // Carrierdaten im Stopper
      arInOutCarrierExit : Array[*] of "stCarrier";   // Carrierdaten im Exitbereich
      stInOutCarrierExit : "stJamData";   // JamStatus im Exitbereich
   END_VAR

   VAR 
      fbStateManager : "FB_StateManager";
      stBookingInfo : "stEventBookingInfo";
      nState : Int;
   END_VAR
   VAR RETAIN
      nActiveStopperNo : Int;   // 1=Stopper 1, 2=Stopper 2
      xStopperFull : Bool;
      nCountSensor1 { S7_SetPoint := 'True'} : Int := 0;   // Flankenzähler vom Sensor Stopper 1
      nCountSensor2 : Int := 0;   // Flankenzähler vom Sensor Stopper 2
   END_VAR
   VAR 
      tOnTrailingStopper2 {InstructionName := 'TON_TIME'; LibVersion := '1.0'} : TON_TIME;   // Timer für Öffnungszeit Stopper 2
   END_VAR

   VAR_TEMP 
      stTmpEmptyCarrier : "stCarrier";
      stTmpArrayEmptyCarrier : Array[1..1] of "stCarrier";
      xTmpActUnivTon : Bool;
      xTmpCloseClampStopper1 : Bool;
      xTmpOpenStopper1 : Bool;
      xTmpOpenStopper2 : Bool;
      xTmpMovement : Bool;
      xTmpTrailingStopper2 : Bool;
      xTmpReleaseDoneStopper1 : Bool;
      xTmpReleaseDoneStopper2 : Bool;
      xTmpReadyForReceiving : Bool;
   END_VAR

   VAR CONSTANT 
      cStepOff : Int := 0;
      cStepUndefined : Int := 100;
      cStepIdle : Int := 200;
      cStepStopper1Receive : Int := 1300;
      cStepStopper1Clamp : Int := 1350;
      cStepStopper1Hold : Int := 1400;
      cStepStopper1Release : Int := 1500;
      cStepStopper1Wait : Int := 1600;
      cStepStopper2Receive : Int := 2300;
      cStepStopper2Hold : Int := 2400;
      cStepStopper2Release : Int := 2500;
      cStepStopper2Wait : Int := 2600;
      cStepWaitForChange : Int := 3000;
   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 = #cStepStopper1Receive THEN
	        IF #stInSenStopper1.xDirectEdgePos THEN
	            #nCountSensor1 += 1;
	        END_IF;
	    ELSE
	        #nCountSensor1 := 0;
	    END_IF;
	    
	    //zählt Sensorflanken vom nächsten Sensor beim Durchfahren,
	    //da dies die einzige Rückmeldung beim Ausfahren ist
	    IF #nState = #cStepStopper2Release OR #nState = #cStepStopper1Wait OR
	        (#nState = #cStepIdle AND #fbStateManager.tOutTimeInStep < #tInWaitBeforeSwitchStopper2) THEN
	        IF #stInSenStopper2.xDirectEdgeNeg THEN
	            #nCountSensor2 += 1;
	        END_IF;
	    ELSE
	        #nCountSensor2 := 0;
	    END_IF;
	    
	END_REGION
	
	REGION Schrittkette
	    CASE #nState OF
	        #cStepOff:
	            REGION 000: Off
	                #nOutState := #cStepOff;
	                
	                #xTmpCloseClampStopper1 := FALSE;
	                #xTmpOpenStopper1 := FALSE;
	                #xTmpOpenStopper2 := FALSE;
	                #xTmpReadyForReceiving := FALSE;
	                #xTmpMovement := FALSE;
	                //////////////////////////////////////
	                
	            END_REGION
	            
	        #cStepUndefined:
	            REGION 100: Undefined
	                #nOutState := #cStepUndefined;
	                
	                #xTmpCloseClampStopper1 := FALSE;
	                #xTmpOpenStopper1 := FALSE;
	                #xTmpOpenStopper2 := FALSE;
	                #xTmpReadyForReceiving := FALSE;
	                #xTmpMovement := FALSE;
	                //////////////////////////////////////
	                
	                #nState := #cStepIdle;
	                
	            END_REGION
	            
	        #cStepIdle:
	            REGION 200: Idle
	                #nOutState := #cStepIdle;
	                
	                // #xTmpCloseClampStopper1 := FALSE;
	                // #xTmpOpenStopper1 := FALSE;
	                // #xTmpOpenStopper2 := FALSE;
	                #xTmpReadyForReceiving := NOT #xStopperFull;
	                #xTmpMovement := FALSE;
	                ///////////////////////////////////////
	                IF #xInSwitchPosition2 THEN
	                    #nActiveStopperNo := 1;
	                    #xTmpCloseClampStopper1 := FALSE;
	                    #xTmpOpenStopper1 := FALSE;
	                    #xTmpOpenStopper2 := TRUE;
	                ELSIF NOT #xInSwitchPosition2 AND (#nCountSensor2 >= 2 OR #fbStateManager.tOutTimeInStep > #tInWaitBeforeSwitchStopper2) THEN
	                    #nActiveStopperNo := 2;
	                    #xTmpCloseClampStopper1 := FALSE;
	                    #xTmpOpenStopper1 := TRUE;
	                    #xTmpOpenStopper2 := FALSE;
	                ELSE
	                    #xTmpCloseClampStopper1 := FALSE;
	                    #xTmpOpenStopper1 := FALSE;
	                    #xTmpOpenStopper2 := TRUE;
	                END_IF;
	                
	                IF (* #xInReceivingMT *) #xStopperFull AND #nActiveStopperNo = 1 THEN
	                    #nState := #cStepStopper1Receive;
	                ELSIF (* #xInReceivingMT *) #xStopperFull AND #nActiveStopperNo = 2 THEN
	                    #nState := #cStepStopper2Receive;
	                END_IF;
	                
	            END_REGION
	            
	            REGION ///// STOPPER 1 /////
	            END_REGION
	            
	        #cStepStopper1Receive:
	            REGION 1300: Stopper 1 Receive
	                #nOutState := #cStepStopper1Receive;
	                
	                #xTmpCloseClampStopper1 := FALSE;
	                #xTmpOpenStopper1 := FALSE;
	                #xTmpOpenStopper2 := TRUE;
	                #xTmpReadyForReceiving := FALSE;
	                #xTmpMovement := TRUE;
	                ///////////////////////////////////////
	                
	                
	                IF #nCountSensor1 >= 2 THEN
	                    #nState := #cStepStopper1Clamp;
	                END_IF;
	                
	                
	            END_REGION
	            
	        #cStepStopper1Clamp:
	            REGION 1350: Stopper 1 Clamp
	                #nOutState := #cStepStopper1Clamp;
	                
	                #xTmpCloseClampStopper1 := FALSE;
	                #xTmpOpenStopper1 := FALSE;
	                #xTmpOpenStopper2 := TRUE;
	                #xTmpReadyForReceiving := FALSE;
	                #xTmpMovement := TRUE;
	                ///////////////////////////////////////
	                
	                IF #fbStateManager.tOutTimeInStep > #tInSenWaitStopper1 THEN
	                    #xTmpCloseClampStopper1 := TRUE;
	                    #nState := #cStepStopper1Hold;
	                END_IF;
	                
	            END_REGION
	            
	        #cStepStopper1Hold:
	            REGION 1400: Stopper 1 Hold
	                #nOutState := #cStepStopper1Hold;
	                
	                #xTmpCloseClampStopper1 := TRUE;
	                #xTmpOpenStopper1 := FALSE;
	                #xTmpOpenStopper2 := TRUE;
	                #xTmpReadyForReceiving := FALSE;
	                #xTmpMovement := FALSE;
	                ///////////////////////////////////////
	                
	                IF #xInReleaseMT AND
	                    #stInOutCarrierExit.Status.nCount < #stInOutCarrierExit.Config.nCapacitySet AND
	                    NOT #stInSenJamExit1.xJam AND NOT #stInSenJamExit2.xJam THEN
	                    #xTmpCloseClampStopper1 := FALSE;
	                    #xTmpOpenStopper1 := TRUE;
	                    #nState := #cStepStopper1Release;
	                END_IF;
	                
	                
	            END_REGION
	            
	        #cStepStopper1Release:
	            REGION 1500: Stopper 1 Release
	                #nOutState := #cStepStopper1Release;
	                
	                #xTmpCloseClampStopper1 := FALSE;
	                #xTmpOpenStopper1 := TRUE;
	                #xTmpOpenStopper2 := TRUE;
	                #xTmpReadyForReceiving := FALSE;
	                #xTmpMovement := TRUE;
	                ///////////////////////////////////////
	                IF NOT #xInSwitchPosition2 THEN
	                    #nState := #cStepStopper1Wait;
	                ELSIF ((* NOT #xInSwitchReq AND *) #fbStateManager.tOutTimeInStep > #tInWaitAfterReleaseStopper1) THEN
	                    // #xTmpOpenStopper := TRUE;
	                    #xTmpReleaseDoneStopper1 := TRUE;
	                    #nState := #cStepIdle;//#cStepWait;
	                END_IF;
	                
	            END_REGION
	            
	        #cStepStopper1Wait:
	            REGION 1600: Stopper 1 Wait
	                #nOutState := #cStepStopper1Wait;
	                
	                #xTmpCloseClampStopper1 := FALSE;
	                #xTmpOpenStopper1 := TRUE;
	                #xTmpOpenStopper2 := TRUE;
	                #xTmpReadyForReceiving := FALSE;
	                #xTmpMovement := TRUE;
	                ///////////////////////////////////////
	                
	                IF #nCountSensor2 >= 2 THEN
	                    #xTmpReleaseDoneStopper1 := TRUE;
	                    #nState := #cStepIdle;
	                END_IF;
	                
	            END_REGION
	            
	            REGION ///// STOPPER 2 /////
	            END_REGION
	            
	        #cStepStopper2Receive:
	            REGION 2300: Stopper 2 Receive
	                #nOutState := #cStepStopper2Receive;
	                
	                #xTmpCloseClampStopper1 := FALSE;
	                #xTmpOpenStopper1 := TRUE;
	                #xTmpOpenStopper2 := FALSE;
	                #xTmpReadyForReceiving := FALSE;
	                #xTmpMovement := TRUE;
	                
	                ///////////////////////////////////////
	                
	                IF #stInSenStopper2.xDbncdSensor THEN
	                    #nState := #cStepStopper2Hold;
	                END_IF;
	                
	            END_REGION
	            
	        #cStepStopper2Hold:
	            REGION 2400: Stopper 2 Hold
	                #nOutState := #cStepStopper2Hold;
	                
	                #xTmpCloseClampStopper1 := FALSE;
	                #xTmpOpenStopper1 := TRUE;
	                #xTmpOpenStopper2 := FALSE;
	                #xTmpReadyForReceiving := FALSE;
	                #xTmpMovement := FALSE;
	                
	                ///////////////////////////////////////
	                
	                // IF NOT #stInSenStopper2.xDirectSensor THEN
	                //     #nState := #cStepStopper2Receive;
	                //     ELS
	                IF #xInReleaseMT AND #stInSenStopper2.xDbncdSensor AND
	                    #stInOutCarrierExit.Status.nCount < #stInOutCarrierExit.Config.nCapacitySet AND
	                    NOT #stInSenJamExit1.xJam AND NOT #stInSenJamExit2.xJam THEN
	                    #nState := #cStepStopper2Release;
	                END_IF;
	                
	                
	            END_REGION
	            
	        #cStepStopper2Release:
	            REGION 2500: Stopper 2 Release
	                #nOutState := #cStepStopper2Release;
	                
	                #xTmpCloseClampStopper1 := FALSE;
	                #xTmpOpenStopper1 := TRUE;
	                #xTmpOpenStopper2 := TRUE;
	                #xTmpReadyForReceiving := FALSE;
	                #xTmpMovement := TRUE;
	               
	                ////////////////////////////////////
	                
	                IF #nCountSensor2 >= 2 THEN
	                    #nState := #cStepStopper2Wait;
	                END_IF;
	                
	            END_REGION
	            
	        #cStepStopper2Wait:
	            REGION 2600: Stopper 2 Wait
	                #nOutState := #cStepStopper2Wait;
	                
	                #xTmpCloseClampStopper1 := FALSE;
	                #xTmpOpenStopper1 := TRUE;
	                #xTmpOpenStopper2 := TRUE;
	                #xTmpReadyForReceiving := FALSE;
	                #xTmpMovement := FALSE;
	                
	                #xTmpTrailingStopper2 := NOT #stInSenStopper2.xDirectSensor;
	                ///////////////////////////////////////
	                
	                IF #tOnTrailingStopper2.Q THEN
	                    #xTmpReleaseDoneStopper2 := TRUE;
	                    #nState := #cStepIdle;
	                END_IF;
	                
	            END_REGION
	            
	        #cStepWaitForChange:
	            REGION 3000: Wait For Change
	                #nOutState := #cStepWaitForChange;
	                
	                
	                ///////////////////////////////////////
	                
	                ;
	                
	                
	            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 := #xInRunning,
	                    xInRunUnivTOn := #xTmpActUnivTon,
	                    nInOutState := #nState);
	END_REGION
	
	REGION Timer
	    #tOnTrailingStopper2(IN := #xTmpTrailingStopper2,
	                 PT := #tInTrailingStopper2);
	END_REGION
	
	REGION Belegung
	    IF #nState > #cStepIdle OR #xInReceivingMT THEN
	        #xStopperFull := TRUE;
	    ELSIF #xTmpReleaseDoneStopper1 OR #xTmpReleaseDoneStopper2 THEN
	        #xStopperFull := FALSE;
	    END_IF;
	END_REGION
	
	
	REGION Stopper FC_Route
	    "FC_Route"(xInSingle := FALSE,
	               xInSeparate := FALSE,
	               xInSepEdge := #xTmpReleaseDoneStopper1 OR #xTmpReleaseDoneStopper2,
	               xInSensor := FALSE,
	               xInDelay := FALSE,
	               stInCarrier := #stTmpEmptyCarrier,
	               stOutBookingInfo => #stBookingInfo,
	               arJamEntr := #arInOutCarrierStopper,
	               arOnTheWay := #stTmpArrayEmptyCarrier,
	               arJamExit := #arInOutCarrierExit);
	END_REGION
	
	REGION Ausgänge
	    #xOutStopper1Clamp := #xTmpCloseClampStopper1;
	    #xOutStopper1 := #xTmpOpenStopper1;
	    #xOutStopper2 := #xTmpOpenStopper2;
	    #xOutStationMovement := #xTmpMovement;
	    #xOutReadyForReceiving := #xTmpReadyForReceiving;
	END_REGION
END_FUNCTION_BLOCK

