FUNCTION_BLOCK "FB_EmptyCarrBuffer"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT 
      nInBufferNr : Int;   // 101 oder 102
      xInBufferReq : Bool;   // Es soll eingelagert werden
      xInPause : Bool;   // Es wird pausiert für den anderen Puffer
      xInSftyOk : Bool;
      xInConveyorRunOut : Bool;
      xInBufferRelease : Bool;   // Puffer leeren normal
      xInBufferReleaseNext : Bool;   // Puffer leeren für Nachbarn
      arInSep : Array[1..5] of Struct   // Separatoren der Linien
         stSenTrolley : "UDT_Sensor";
         stSettings : "SettingsSeparator";
      END_STRUCT;
      arInJamSensor : Array[1..5] of "UDT_Sensor";   // Jamsensoren der Linien
      stInSenJamExit : "UDT_Sensor";   // Stausensor Exitstrecke
      stInPriorityManager : "UDT_Response";   // Schnittstelle Prioritätenmanager (z.B. bei Kreuzungen)
      stInSettings : Struct
         nDestGeneral : Int;
         nConvStations : Int;
         nStationsMax : Int;
         nStorageThreshold : Int := 10;
         nNoOfLines : USInt := 5;
         nNoOfPositions : USInt := 70;
         sJamSrc : String;
         sJamDest : String;
      END_STRUCT;
   END_VAR

   VAR_OUTPUT 
      xOutBypass : Bool;
      nOutLineNr : Int;
      xOutReadyToReceive : Bool;
      nOutFillLevel : Int;   // in Prozent
      xOutFull : Bool;
      arOutSwitchLine : Array[1..5] of Bool;
      nOutStateLast : Int;
      nOutActNo : Int;   // aktuelle Linie 1-5, oder 0 falls inaktiv
      xOutSwitchExitReady : Bool;
      xOutSepExitRelease : Bool;
      xOutCarouselReq : Bool;
      stOutPriorityManager : "UDT_Request";   // Schnittstelle Prioritätenmanager (z.B. bei Kreuzungen)
      arOutSeparatorStore : Array[1..5] of Bool;   // Ausgänge Separator Lagerstrecken Ventil
   END_VAR

   VAR_IN_OUT 
      stInOutControlUnitCabinet : "UDT_MainState";   // Hauptzustandsmaschine
      arInOutStorageLines : Array[*] of "stStorageLine";   // Daten Lagerlinien
      arInOutJamExit : Array[*] of "stCarrier";   // Jam nach Linien-Separatoren
      stInOutJamExit : "stJamData";   // Konfig+Status-Daten Staubereich Ausgang 1
      stInOutHMI : "UDT_HMI_TRO_PinStore";   // HMI Schnittstelle Separator Lagerlinien
   END_VAR

   VAR 
      fbStateManagerE : "FB_StateManager";   // Schrittkette eingangsseitig
      fbStateManagerA : "FB_StateManager";   // Schrittkette ausgangsseitig
      arfbSeparatorStorage { S7_SetPoint := 'False'} : Array[1..5] of "FB_ILS_STRO_Sep";   // Aufruf Separatoren Lagerlinien
      nStateE : Int;   // Schritt eingangsseitig
      nStateA : Int;   // Schritt ausgangsseitig
      sStateTextE : String[100] := '';   // Aktueller State der Schrittkette (textuell)
      sStateTextA : String[100];
      nLineNr { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;
      nSepNr : Int;
      xBypassNextBoom : Bool;
      xStart : Bool;
   END_VAR
   VAR RETAIN
      nActLine : Int;
   END_VAR
   VAR 
      nLastLine : Int;
      nTestStorageOut : Int := 1;
      stDummyCarrier { S7_SetPoint := 'False'} : "stCarrier";
      tOnSvReleaseSep {InstructionName := 'TON_TIME'; LibVersion := '1.0'; S7_SetPoint := 'False'} : TON_TIME;   // Supervision - Freigabe Separator
      xVersatz : Bool;
      fbCarrierWaitStore1 : "FB_CarrAccumulate1Sep";
      fbCarrierWaitStore2 : "FB_CarrAccumulate1Sep";
      fbCarrierWaitStore3 : "FB_CarrAccumulate1Sep";
      fbCarrierWaitStore4 : "FB_CarrAccumulate1Sep";
      fbCarrierWaitStore5 : "FB_CarrAccumulate1Sep";
      arArrayMax : Array[1..5] of Int;
      stCarrierDummy { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'; S7_SetPoint := 'False'} : "stCarrier" := (1, (), 16#01);
      nArrayMax : Int;
      fbEventLog_Route2 : "FB_EventLog_Booking";
      fbEventLogCorrection1 : "FB_EventLog_Correction";
      fbEventLogCorrection2 : "FB_EventLog_Correction";
      fbEventLogCarrierUnknown : "FB_EventLog_Scan";
      fbEventLogCarrierNew : "FB_EventLog_Scan";
      fbEventLogGoodRead : "FB_EventLog_Scan";
   END_VAR

   VAR_TEMP 
      nIdx : Int;
      tmpActUnivTonE : Bool;
      tmpActUnivTonA : Bool;
      tmpReasonForStop : USInt;   // Anhaltegrund in der Schrittkette | 0: Nichts | 5: Alle BT ausgefahren | 10: Fehler in SubTro | 15: Kein BT/NBT am Eingang | 20: Stau im nächsten MTRO | 25: NBT | 30: Falsch gefahren | 35: Initial-BT kam nicht am Ziel an | 40: Allgemeiner Fehler | 45: Abbruch durch MFR | 50: Fehler in Anfrage von MRF | 55: MFR hat TRO pausiert
      arTmpStorageData : Array[1..5] of "stJamData";
      arTmpSenJamLine : Array[1..5] of "UDT_Sensor";
      arTmpSenInSepLine : Array[1..5] of "UDT_Sensor";
      arLineRelease : Array[1..5] of Bool;
      xTmpSepExitRelease : Bool;
      nActNo : Int;
      nTmpArrayMax1 : Int;
      nTmpArrayMax2 : Int;
      nTmpArrayMax3 : Int;
      nTmpArrayMax4 : Int;
      nTmpArrayMax5 : Int;
      xTmpSwitchExitReady : Bool;
      xTmpSwitch : Bool;
      stCognexInterfaceDummy : "stCognexInterface";
      stEmptyCarrier : "stCarrier";
      tmpCarrierEmpty : "stCarrier";
      stBookingInfo : "stEventBookingInfo";
      arEmptyCarrier : Array[1..1] of "stCarrier";
      nCounter : DInt;
      xResult : Bool;
      xEventLogBookExit : Bool;
      arEventCorrectionInfo : Array[0..1] of "stEventCorrectionInfo";
      xUnknownCarrier : Bool;
      stEventGoodRead : "stEventScanInfo";
      stEventNew : "stEventScanInfo";
      stEventUnknown : "stEventScanInfo";
      xNewCarrier : Bool;
      xGoodRead : Bool;
   END_VAR

   VAR CONSTANT 
      c0000_StepOff : Int := 0;
      c0100_StepUndefined : Int := 100;
      c0200_StepIdle : Int := 200;
      c0400_StepWaitAndSwitch : Int := 400;
      c0800_StepSwitch : Int := 800;
      c0900_StepWorking : Int := 900;
      c1000_StepWaitForTrolley1 : Int := 1000;   // Warte auf Trolley 1
      c1200_StepWaitForChange : Int := 1200;
      c1400_StepCheckSep1 : Int := 1400;   // Separator checken
      c1500_StepReleaseSep1 : Int := 1500;   // Freigabe an Separator
      c2000_StepWaitForTrolley2 : Int := 2000;   // Warte auf Trolley 2
      c2300_StepCheckSep2 : Int := 2300;   // Separator checken
      c2400_StepCheckJam : Int := 2400;   // Stau überprüfen
      c2500_StepReleaseSep2 : Int := 2500;   // Freigabe an Separator
      cCarrierDummy : Int := 1;
   END_VAR


BEGIN
	
	
	REGION Schrittkette Einlagern
	    
	    (* zum Kopieren
	        #cxxxx_Stepxxxx:
	            REGION xxxx: xxxx
	                // akt. Zustand
	                #sStateText := 'xxxx';
	                ///////// Ausgänge /////////
	                
	                ///////// Statics //////////
	                
	                /////////  Timer  //////////
	                
	                //////// Transition ////////
	                #nState := #cxxxx_Stepxxxx;
	            END_REGION    
	*)
	    
	    CASE #nStateE OF
	        #c0000_StepOff:
	            REGION 0000: Off
	                // akt. Zustand
	                #sStateTextE := 'Off';
	                ///////// Ausgänge /////////
	                
	                ///////// Statics //////////
	               
	                /////////  Timer  //////////
	                
	                //////// Transition ////////
	                // SCHRITT 0 WIRD GEBRAUCHT!
	                //STATE MANAGER KÜMMERT SICH UM TRANSITION!
	            END_REGION
	            
	        #c0100_StepUndefined:
	            REGION 0100: Undefined
	                // akt. Zustand
	                #sStateTextE := 'Undefined';
	                ///////// Ausgänge /////////
	                
	                ///////// Statics //////////
	                
	                /////////  Timer  //////////
	                
	                //////// Transition ////////
	                #nStateE := #c0200_StepIdle;
	            END_REGION
	            
	        #c0200_StepIdle:
	            REGION 0200: Idle
	                // akt. Zustand
	                #sStateTextE := 'Idle';
	                ///////// Ausgänge /////////
	                
	                ///////// Statics //////////
	                
	                /////////  Timer  //////////
	                
	                //////// Transition ////////
	                IF NOT #xInPause THEN
	                    FOR #nIdx := 1 TO "cNoLines" DO
	                        IF #arInOutStorageLines[#nIdx].stData.Status.nCount (* #arTmpStorageData[#nIdx].Status.nCount *)< #arInOutStorageLines[#nIdx].stData.Config.nCapacitySet AND
	                            NOT #arInJamSensor[#nIdx].xJam (* #arTmpSenJamLine[#nIdx].xJam *)AND NOT #xInPause THEN
	                            #nLineNr := #nIdx;
	                            // #xBypassNextBoom := FALSE;
	                            EXIT;
	                        END_IF;
	                    END_FOR;
	                ELSE
	                    IF #nInBufferNr = "cMainTro101" THEN
	                        #xBypassNextBoom := TRUE; //geradeaus
	                    // ELSE
	                    //     #xBypassNextBoom := FALSE;
	                    END_IF;
	                END_IF;
	                
	                IF #xInBufferReq AND NOT #xInPause AND #nLineNr <> 0 AND NOT #xOutFull THEN
	                    #nStateE := #c0400_StepWaitAndSwitch;
	                END_IF;
	                
	            END_REGION
	            
	        #c0400_StepWaitAndSwitch:
	            REGION 0400: Wait and switch
	                // akt. Zustand
	                #sStateTextE := 'Wait and switch';
	                ///////// Ausgänge /////////
	                
	                ///////// Statics //////////
	                
	                /////////  Timer  //////////
	                
	                //////// Transition ////////
	                IF ((NOT #xBypassNextBoom AND #nInBufferNr = "cMainTro101") OR
	                    (#nInBufferNr = "cMainTro102")) AND #fbStateManagerE.tOutTimeInStep > T#3s THEN
	                    #nStateE := #c0900_StepWorking;
	                ELSIF #xBypassNextBoom AND #nInBufferNr = "cMainTro101" AND #fbStateManagerE.tOutTimeInStep > T#12s THEN
	                    #xBypassNextBoom := FALSE;
	                    #nStateE := #c0900_StepWorking;
	                ELSIF NOT #xInBufferReq THEN
	                    #nStateE := #c0200_StepIdle;
	                END_IF;
	            END_REGION
	            
	        #c0900_StepWorking:
	            REGION 900: Working
	                // akt. Zustand
	                #sStateTextE := 'Working';
	                ///////// Ausgänge /////////
	                // #arOutSwitchLine[#xLineNr] := TRUE;
	                ///////// Statics //////////
	                
	                /////////  Timer  //////////
	                
	                //////// Transition ////////
	                IF (* NOT #xInBufferReq *) (#xInPause AND #fbStateManagerE.tOutTimeInStep > T#5s) OR
	                    #arInOutStorageLines[#nLineNr].stData.Status.nCount (* #arTmpStorageData[#nLineNr].Status.nCount *)>= #arInOutStorageLines[#nLineNr].stData.Config.nCapacitySet OR
	                    #arInJamSensor[#nLineNr].xJam (* #arTmpSenJamLine[#nLineNr].xJam *)THEN
	                    #nStateE := #c1200_StepWaitForChange;
	                END_IF;
	            END_REGION
	            
	        #c1200_StepWaitForChange:
	            REGION 1200: Wait for change
	                // akt. Zustand
	                #sStateTextE := 'Wait for change';
	                ///////// Ausgänge /////////
	                // #arOutSwitchLine[#xLineNr] := TRUE;
	                ///////// Statics //////////
	                
	                /////////  Timer  //////////
	                
	                //////// Transition ////////
	                IF #fbStateManagerE.tOutTimeInStep > T#8s THEN
	                    #nStateE := #c0200_StepIdle;
	                END_IF;
	            END_REGION
	    END_CASE;
	    
	END_REGION
	
	REGION Schrittkette Auslagern
	    
	    (* zum Kopieren
	        #cxxxx_Stepxxxx:
	            REGION xxxx: xxxx
	                // akt. Zustand
	                #sStateText := 'xxxx';
	                ///////// Ausgänge /////////
	                
	                ///////// Statics //////////
	                
	                /////////  Timer  //////////
	                
	                //////// Transition ////////
	                #nState := #cxxxx_Stepxxxx;
	            END_REGION    
	*)
	    
	    CASE #nStateA OF
	        #c0000_StepOff:
	            REGION 0000: Off
	                // akt. Zustand
	                #sStateTextA := 'Off';
	                ///////// Ausgänge /////////
	                // #xTmpSepExitRelease := FALSE;
	                // #xTmpSwitchExitReady := FALSE;
	                // #xTmpSwitch := FALSE;
	                ///////// Statics //////////
	                // #xBypassNextBoom := FALSE;
	                FOR #nIdx := 1 TO 5 DO
	                    #arLineRelease[#nIdx] := FALSE;
	                END_FOR;
	                /////////  Timer  //////////
	                
	                //////// Transition ////////
	                // SCHRITT 0 WIRD GEBRAUCHT!
	                // #nSepNr := 0;
	                //STATE MANAGER KÜMMERT SICH UM TRANSITION!
	            END_REGION
	            
	        #c0100_StepUndefined:
	            REGION 0100: Undefined
	                // akt. Zustand
	                #sStateTextA := 'Undefined';
	                ///////// Ausgänge /////////
	                // #xTmpSepExitRelease := FALSE;
	                // #xTmpSwitchExitReady := FALSE;
	                // #xTmpSwitch := FALSE;
	                ///////// Statics //////////
	                // #xBypassNextBoom := FALSE;
	                FOR #nIdx := 1 TO 5 DO
	                    #arLineRelease[#nIdx] := FALSE;
	                END_FOR;
	                /////////  Timer  //////////
	                
	                //////// Transition ////////
	                // #nSepNr := 0;
	                #nStateA := #c1000_StepWaitForTrolley1;
	            END_REGION
	            
	        #c1000_StepWaitForTrolley1:
	            REGION 1000: Wait for Trolley
	                
	                ///////// Statics //////////
	                FOR #nIdx := 1 TO 5 DO
	                    #arLineRelease[#nIdx] := FALSE;
	                END_FOR;
	                
	                IF #xStart THEN
	                    IF #nActLine = 0 THEN
	                        #nActLine := 1;
	                    END_IF;
	
	                    IF #nActLine <> #nLastLine THEN
	                        #stDummyCarrier.nBarcode := 1000;
	                    END_IF;
	                    #nLastLine := #nActLine;
	                    IF #arfbSeparatorStorage[#nActLine].stOutMainTro.xBtPresent AND #arInOutStorageLines[#nActLine].arCarrier[1].bStatus.%X0 THEN
	                        #nStateA := #c1400_StepCheckSep1;
	                    ELSIF (NOT #arfbSeparatorStorage[#nActLine].stOutMainTro.xBtPresent OR NOT #arInOutStorageLines[#nActLine].arCarrier[1].bStatus.%X0) AND
	                        #fbStateManagerA.tOutTimeInStep > T#3s THEN
	                        FOR #nIdx := 1 TO 5 DO
	                            IF #arfbSeparatorStorage[#nIdx].stOutMainTro.xBtPresent AND #arInOutStorageLines[#nIdx].arCarrier[1].bStatus.%X0 = TRUE THEN
	                                #nActLine := #nIdx;
	                                #nLastLine := #nActLine;
	                                #nStateA := #c1400_StepCheckSep1;
	                                EXIT;
	                            END_IF;
	                        END_FOR;
	                    END_IF;
	                END_IF;
	            END_REGION
	        #c1400_StepCheckSep1:
	            REGION 1400: Check Separator
	                
	                FOR #nIdx := 1 TO 5 DO
	                    #arLineRelease[#nIdx] := FALSE;
	                END_FOR;
	                
	                CASE #nActLine OF
	                    1:
	                        IF #arfbSeparatorStorage[#nActLine].stOutMainTro.nStatus = "SepState_WaitForReq" THEN // Separator ist bereit
	                            #nStateA := #c1500_StepReleaseSep1;
	                        ELSIF #fbStateManagerE.tOutUnivTonR > T#3s THEN
	                            #tmpReasonForStop := "Rsn_SubError";    // SubTRO: Separator ist nicht bereit
	                        END_IF;
	                    2:
	                        IF #arfbSeparatorStorage[#nActLine].stOutMainTro.nStatus = "SepState_WaitForReq" THEN // Separator ist bereit
	                            #nStateA := #c1500_StepReleaseSep1;
	                        ELSIF #fbStateManagerE.tOutUnivTonR > T#3s THEN
	                            #tmpReasonForStop := "Rsn_SubError";    // SubTRO: Separator ist nicht bereit
	                        END_IF;
	                    3:
	                        IF #arfbSeparatorStorage[#nActLine].stOutMainTro.nStatus = "SepState_WaitForReq" THEN // Separator ist bereit
	                            #nStateA := #c1500_StepReleaseSep1;
	                        ELSIF #fbStateManagerE.tOutUnivTonR > T#3s THEN
	                            #tmpReasonForStop := "Rsn_SubError";    // SubTRO: Separator ist nicht bereit
	                        END_IF;
	                    4:
	                        IF #arfbSeparatorStorage[#nActLine].stOutMainTro.nStatus = "SepState_WaitForReq" THEN // Separator ist bereit
	                            #nStateA := #c1500_StepReleaseSep1;
	                        ELSIF #fbStateManagerE.tOutUnivTonR > T#3s THEN
	                            #tmpReasonForStop := "Rsn_SubError";    // SubTRO: Separator ist nicht bereit
	                        END_IF;
	                    5:
	                        IF #arfbSeparatorStorage[#nActLine].stOutMainTro.nStatus = "SepState_WaitForReq" THEN // Separator ist bereit
	                            #nStateA := #c1500_StepReleaseSep1;
	                        ELSIF #fbStateManagerE.tOutUnivTonR > T#3s THEN
	                            #tmpReasonForStop := "Rsn_SubError";    // SubTRO: Separator ist nicht bereit
	                        END_IF;
	                END_CASE;
	                
	            END_REGION
	            
	        #c1500_StepReleaseSep1:
	            REGION 1500: Release Sep 1            
	                // akt. Zustand
	                #sStateTextA := 'Leave Sep 1';
	                
	                ///////// Ausgänge /////////
	                ///////// Statics //////////
	                
	                FOR #nIdx := 1 TO 5 DO
	                    IF #nIdx = #nActLine THEN
	                        #arLineRelease[#nIdx] := TRUE;
	                    ELSE
	                        #arLineRelease[#nIdx] := FALSE;
	                    END_IF;
	                END_FOR;
	                
	                
	                //////// Transition ////////
	                CASE #nActLine OF
	                    1:  // Statement section case 1
	                        IF #arfbSeparatorStorage[#nActLine].stOutMainTro.nStatus = "SepState_Finish" THEN
	                            #nStateA := #c2000_StepWaitForTrolley2;
	                        ELSIF #arLineRelease[#nActLine] AND #tOnSvReleaseSep.Q THEN
	                            #tmpReasonForStop := "Rsn_SubError";    //  Timeout-Fehler im SubTRO "Separator": Freigabe erteilt, aber Separator gibt keine Rückmeldung an MainTRO
	                        END_IF;
	                    2:
	                        IF #arfbSeparatorStorage[#nActLine].stOutMainTro.nStatus = "SepState_Finish" THEN
	                            #nStateA := #c2000_StepWaitForTrolley2;
	                        ELSIF #arLineRelease[#nActLine] AND #tOnSvReleaseSep.Q THEN
	                            #tmpReasonForStop := "Rsn_SubError";    //  Timeout-Fehler im SubTRO "Separator": Freigabe erteilt, aber Separator gibt keine Rückmeldung an MainTRO
	                        END_IF;
	                    3:
	                        IF #arfbSeparatorStorage[#nActLine].stOutMainTro.nStatus = "SepState_Finish" THEN
	                            #nStateA := #c2000_StepWaitForTrolley2;
	                        ELSIF #arLineRelease[#nActLine] AND #tOnSvReleaseSep.Q THEN
	                            #tmpReasonForStop := "Rsn_SubError";    //  Timeout-Fehler im SubTRO "Separator": Freigabe erteilt, aber Separator gibt keine Rückmeldung an MainTRO
	                        END_IF;
	                    4:
	                        IF #arfbSeparatorStorage[#nActLine].stOutMainTro.nStatus = "SepState_Finish" THEN
	                            #nStateA := #c2000_StepWaitForTrolley2;
	                        ELSIF #arLineRelease[#nActLine] AND #tOnSvReleaseSep.Q THEN
	                            #tmpReasonForStop := "Rsn_SubError";    //  Timeout-Fehler im SubTRO "Separator": Freigabe erteilt, aber Separator gibt keine Rückmeldung an MainTRO
	                        END_IF;
	                    5:
	                        IF #arfbSeparatorStorage[#nActLine].stOutMainTro.nStatus = "SepState_Finish" THEN
	                            #nStateA := #c2000_StepWaitForTrolley2;
	                        ELSIF #arLineRelease[#nActLine] AND #tOnSvReleaseSep.Q THEN
	                            #tmpReasonForStop := "Rsn_SubError";    //  Timeout-Fehler im SubTRO "Separator": Freigabe erteilt, aber Separator gibt keine Rückmeldung an MainTRO
	                        END_IF;
	                    
	                END_CASE;
	                
	            END_REGION
	            
	        #c2000_StepWaitForTrolley2:
	            REGION 2000: Wait for Trolley 2
	                //akt. Zustand
	                #sStateTextA := 'Wait for Trolley 2';
	                ///////// Ausgänge /////////
	                
	                ///////// Statics //////////
	                
	                FOR #nIdx := 1 TO 5 DO
	                    #arLineRelease[#nIdx] := FALSE;
	                END_FOR;
	                
	                
	                //Transition
	                CASE #nActLine OF
	                    1:  // Statement section case 1
	                        IF #arfbSeparatorStorage[#nActLine].stOutMainTro.xBtPresent AND #arInOutStorageLines[#nActLine].arCarrier[1].bStatus.%X0 THEN
	                            #nStateA := #c2300_StepCheckSep2;
	                        END_IF;
	                    2:  // Statement section case 1
	                        IF #arfbSeparatorStorage[#nActLine].stOutMainTro.xBtPresent AND #arInOutStorageLines[#nActLine].arCarrier[1].bStatus.%X0 THEN
	                            #nStateA := #c2300_StepCheckSep2;
	                        END_IF;
	                        
	                    3:  // Statement section case 1
	                        IF #arfbSeparatorStorage[#nActLine].stOutMainTro.xBtPresent AND #arInOutStorageLines[#nActLine].arCarrier[1].bStatus.%X0 THEN
	                            #nStateA := #c2300_StepCheckSep2;
	                        END_IF;
	                        
	                    4:  // Statement section case 1
	                        IF #arfbSeparatorStorage[#nActLine].stOutMainTro.xBtPresent AND #arInOutStorageLines[#nActLine].arCarrier[1].bStatus.%X0 THEN
	                            #nStateA := #c2300_StepCheckSep2;
	                        END_IF;
	                        
	                    5:  // Statement section case 1
	                        IF #arfbSeparatorStorage[#nActLine].stOutMainTro.xBtPresent AND #arInOutStorageLines[#nActLine].arCarrier[1].bStatus.%X0 THEN
	                            #nStateA := #c2300_StepCheckSep2;
	                        END_IF;
	                END_CASE;
	            END_REGION
	            
	        #c2300_StepCheckSep2:
	            REGION 2300: Check Separator
	                FOR #nIdx := 1 TO 5 DO
	                    #arLineRelease[#nIdx] := FALSE;
	                END_FOR;
	                
	                //Transition
	                CASE #nActLine OF
	                    1:  // Statement section case 1
	                        #tmpActUnivTonA := TRUE;
	                        IF #arfbSeparatorStorage[#nActLine].stOutMainTro.nStatus = "SepState_WaitForReq" THEN // Separator ist bereit
	                            #nStateA := #c2400_StepCheckJam;
	                        ELSIF #fbStateManagerE.tOutUnivTonR > T#3s THEN
	                            #tmpReasonForStop := "Rsn_SubError";    // SubTRO: Separator ist nicht bereit
	                        END_IF;
	                    2:  // Statement section case 1
	                        #tmpActUnivTonA := TRUE;
	                        IF #arfbSeparatorStorage[#nActLine].stOutMainTro.nStatus = "SepState_WaitForReq" THEN // Separator ist bereit
	                            #nStateA := #c2400_StepCheckJam;
	                        ELSIF #fbStateManagerE.tOutUnivTonR > T#3s THEN
	                            #tmpReasonForStop := "Rsn_SubError";    // SubTRO: Separator ist nicht bereit
	                        END_IF;
	                    3:  // Statement section case 1
	                        #tmpActUnivTonA := TRUE;
	                        IF #arfbSeparatorStorage[#nActLine].stOutMainTro.nStatus = "SepState_WaitForReq" THEN // Separator ist bereit
	                            #nStateA := #c2400_StepCheckJam;
	                        ELSIF #fbStateManagerE.tOutUnivTonR > T#3s THEN
	                            #tmpReasonForStop := "Rsn_SubError";    // SubTRO: Separator ist nicht bereit
	                        END_IF;
	                    4:  // Statement section case 1
	                        #tmpActUnivTonA := TRUE;
	                        IF #arfbSeparatorStorage[#nActLine].stOutMainTro.nStatus = "SepState_WaitForReq" THEN // Separator ist bereit
	                            #nStateA := #c2400_StepCheckJam;
	                        ELSIF #fbStateManagerE.tOutUnivTonR > T#3s THEN
	                            #tmpReasonForStop := "Rsn_SubError";    // SubTRO: Separator ist nicht bereit
	                        END_IF;
	                    5:  // Statement section case 1
	                        #tmpActUnivTonA := TRUE;
	                        IF #arfbSeparatorStorage[#nActLine].stOutMainTro.nStatus = "SepState_WaitForReq" THEN // Separator ist bereit
	                            #nStateA := #c2400_StepCheckJam;
	                        ELSIF #fbStateManagerE.tOutUnivTonR > T#3s THEN
	                            #tmpReasonForStop := "Rsn_SubError";    // SubTRO: Separator ist nicht bereit
	                        END_IF;
	                END_CASE;
	                
	            END_REGION
	            
	        #c2400_StepCheckJam:
	            REGION 2400: Check Jam
	                // akt. Zustand
	                #sStateTextA := 'Check Jam';
	                ///////// Ausgänge /////////
	                ///////// Statics //////////
	                FOR #nIdx := 1 TO 5 DO
	                    #arLineRelease[#nIdx] := FALSE;
	                END_FOR;
	                
	                /////////  Timer  //////////
	                //////// Transition ////////
	                IF (#stInOutJamExit.Status.nCount = #stInOutJamExit.Config.nCapacitySet) //Zielstaubereich ist datentechnisch voll
	                    OR (#arInSep[1].stSettings.xPluggedJam AND #stInSenJamExit.xJam) // Stausensor *)
	                THEN
	                    #tmpReasonForStop := "Rsn_JamNextError";
	                ELSE
	                    #nStateA := #c2500_StepReleaseSep2;
	                END_IF;
	            END_REGION
	            
	        #c2500_StepReleaseSep2:
	            REGION 2500: Release Sep Second          
	                // akt. Zustand
	                #sStateTextA := 'Leave Sep';
	                
	                ///////// Ausgänge /////////
	                ///////// Statics //////////
	                #stOutPriorityManager.xTransportReq := #xInSftyOk AND #xInConveyorRunOut (* AND NOT #stInMfr.xPause *);
	                
	                FOR #nIdx := 1 TO 5 DO
	                    IF #nIdx = #nActLine THEN
	                        #arLineRelease[#nIdx] := #xInSftyOk AND #xInConveyorRunOut AND #stInPriorityManager.xReleaseOk AND NOT #arInOutStorageLines[#nIdx].stData.Status.bByte.%X3;
	                    ELSE
	                        #arLineRelease[#nIdx] := FALSE;
	                    END_IF;
	                END_FOR;
	                
	                //////// Transition ////////
	                //Transition
	                
	                FOR #nIdx := 1 TO #nActLine DO
	                    IF #nIdx = #nActLine THEN
	                        IF #arfbSeparatorStorage[#nActLine].stOutMainTro.nStatus = "SepState_Finish" THEN
	                            //Hier könnte man noch einbauen, ob optional nicht gebucht wird, z.B. für Fehlerkorrektur
	                            REGION Daten buchen Store1 -> ExitJam
	                                IF NOT #xVersatz THEN // Alles normal buchen
	                                    "FC_Route"(xInSingle := FALSE,
	                                               xInSeparate := FALSE,
	                                               xInSepEdge := TRUE,
	                                               xInSensor := FALSE,
	                                               xInDelay := FALSE,
	                                               stInCarrier := #stEmptyCarrier,
	                                               stOutBookingInfo => #stBookingInfo,
	                                               arJamEntr := #arInOutStorageLines[#nActLine].arCarrier,
	                                               arOnTheWay := #arEmptyCarrier,
	                                               arJamExit := #arInOutJamExit);
	                                    
	                                ELSE // Dummy (=ohne Daten) buchen
	                                    "FC_TSHR_AddAtEnd"(stInTrolley := #stDummyCarrier,
	                                                       nOutCounter => #nCounter,
	                                                       xOutResult => #xResult,
	                                                       arTSHR := #arInOutJamExit);
	                                    
	                                    #stDummyCarrier.nBarcode += 1;
	                                    
	                                    IF #stDummyCarrier.nBarcode > 1999 THEN
	                                        #stDummyCarrier.nBarcode := 1000;
	                                    END_IF;
	                                END_IF;
	                                #xVersatz := FALSE;
	                            END_REGION ;
	                            #xEventLogBookExit := TRUE;
	                            #nStateA := #c1000_StepWaitForTrolley1;
	                            EXIT;
	                        END_IF;
	                    END_IF;
	                END_FOR;
	                
	            END_REGION
	    END_CASE;
	    
	END_REGION
	
	REGION StateManager Einlagern
	    #fbStateManagerE.stInSettings.nStartState := #c0100_StepUndefined;
	    #fbStateManagerE.stInSettings.nStartStateTestMode := #c0000_StepOff;
	    #fbStateManagerE.stInSettings.xActUnivTOn := TRUE;
	    #fbStateManagerE.stInSettings.xRestartAtStartState := FALSE;
	    #fbStateManagerE(xInFunctionEnabled :=  #stInOutControlUnitCabinet.xRunning,
	                    // xInReset := (* #stInMfr.xCancel OR *)#xInCancel,
	                    xInRunUnivTOn := #tmpActUnivTonE,
	                    nInOutState := #nStateE);
	END_REGION
	
	REGION StateManager Auslagern
	    #fbStateManagerA.stInSettings.nStartState := #c0100_StepUndefined;
	    #fbStateManagerA.stInSettings.nStartStateTestMode := #c0000_StepOff;
	    #fbStateManagerA.stInSettings.xActUnivTOn := TRUE;
	    #fbStateManagerA.stInSettings.xRestartAtStartState := FALSE;
	    #fbStateManagerA(xInFunctionEnabled := #stInOutControlUnitCabinet.xRunning,
	                     // xInReset := (* #stInMfr.xCancel OR *)#xInCancel,
	                     xInRunUnivTOn := #tmpActUnivTonA,
	                     nInOutState := #nStateA);
	END_REGION
	
	(* REGION Separator Buffer Lines
	    
	    // #fb1Sep1SwiExit.stInSeparator1.Settings.nSeparatorNo := #nActNo;
	    // #fb1Sep1SwiExit.stInSeparator1.Settings.tDelayToNextItem := "TimeForSepWaiting_Short";
	    // #fb1Sep1SwiExit.stInSeparator1.Settings.tTrailingTime := t#0ms;
	    // #fb1Sep1SwiExit.stInSeparator1.Settings.tHandlingTime := t#0ms;
	    // #fb1Sep1SwiExit.stInSeparator1.Settings.tJam := "TimeForSepJam";
	    // #fb1Sep1SwiExit.stInSeparator1.Settings.xPluggedJam := TRUE;
	    // #fb1Sep1SwiExit.stInSeparator1.Settings.xPluggedPart := FALSE;
	    // #fb1Sep1SwiExit.stInSeparator1.Settings.xPluggedScanner := FALSE;
	    // #fb1Sep1SwiExit.stInSenJam2 := #stInSenJamExitLeft;
	    // #fb1Sep1SwiExit.stInSenJam3 := #stInSenJamExitRight;
	    
	    // #fb1Sep1SwiExit.stInSwitch1.Settings.nSwitchNo := 1;
	    // #fb1Sep1SwiExit.stInSwitch1.Settings.xPluggedExSen3 := TRUE;
	    // #fb1Sep1SwiExit.stInSwitch1.Settings.xPluggedExSen4 := TRUE;
	    
	    // #fb1Sep1SwiExit.stInPriorityManager.xReleaseOk := #xTmpSwitchExitReady;
	    
	    // CASE #nActNo OF
	    //     1: 
	    //         #fb1Sep1SwiExit.stInSeparator1.stSenInSep := #stInSenInSep1;
	    //     2:
	    //         #fb1Sep1SwiExit.stInSeparator1.stSenInSep := #stInSenInSep2;
	    //     3:
	    //         #fb1Sep1SwiExit.stInSeparator1.stSenInSep := #stInSenInSep3;
	    //     4:
	    //         #fb1Sep1SwiExit.stInSeparator1.stSenInSep := #stInSenInSep4;
	    //     5:
	    //         #fb1Sep1SwiExit.stInSeparator1.stSenInSep := #stInSenInSep5;
	    //     ELSE
	    //         ;
	    // END_CASE;
	    
	    // #fb1Sep1SwiExit(nInMainTroNo := #nInBufferNr,
	    //                 xInSftyOk := #xInSafetyOk,
	    //                 xInAllRdyToStart := TRUE,
	    //                 xInCarouselRun1 := #xInCarRun,
	    //                 xInRelease := #xTmpSepExitRelease,
	    //                 stInOutMachineState := #stInOutMainState,
	    //                 stInOutCognexInterface := #stCognexInterfaceDummy,
	    //                 arInOutJamEntr1 := #arInOutCarrierLine[#nActNo],
	    //                 stInOutJamEntr1 := #arInOutJamDataLine[#nActNo],
	    //                 arInOutJamExit2 := #arInOutJamCarrierExitLeft,
	    //                 stInOutJamExit2 := #stInOutDataJamExitLeft,
	    //                 arInOutJamExit3:= #arInOutJamCarrierExitRight,
	    //                 stInOutJamExit3:= #stInOutDataJamExitRight,
	    //                 stInOutHMI := #stInOutHMI,
	    //                 nOutStateLast => #nOutStateLast,
	    //                 xOutSw1ExTo3 => #xOutSwitchExit);
	    
	    // CASE #nActNo OF
	    //     1:
	    //         #arOutSepLine[1] := #fb1Sep1SwiExit.xOutStopper1;
	    //     2:
	    //         #arOutSepLine[2] := #fb1Sep1SwiExit.xOutStopper1;
	    //     3:
	    //         #arOutSepLine[3] := #fb1Sep1SwiExit.xOutStopper1;
	    //     4:
	    //         #arOutSepLine[4] := #fb1Sep1SwiExit.xOutStopper1;
	    //     5:
	    //         #arOutSepLine[5] := #fb1Sep1SwiExit.xOutStopper1;
	    //     ELSE
	    //         ;
	    // END_CASE;
	    
	END_REGION *)
	
	REGION Separator BufferLines
	    
	    REGION Separator Freigabe
	        //Benötigtem Sep Freigabe erteilen
	        // FOR #nIdx1 := 1 TO #stInSettings.nNoOfLines DO
	        //     IF #stInStorageCarrStats.stRdyToLeave.nLine = #nIdx1 THEN
	        //         #arLineRelease[#nIdx1] := TRUE;
	        //     END_IF;
	        // END_FOR;
	    END_REGION
	    
	    REGION Sep 1
	        #nActNo := 1;
	        #arfbSeparatorStorage[#nActNo](stInSettings := #arInSep[#nActNo].stSettings,
	                                       xInConveyorRun := #xInConveyorRunOut,
	                                       stInTrolley := #arInSep[#nActNo].stSenTrolley,
	                                       xInReceiveReady := NOT #fbCarrierWaitStore1.xOutLockSep1 AND #arLineRelease[#nActNo] AND NOT #arInOutJamExit[#arInSep[#nActNo].stSettings.nJamLength].bStatus.%X0,
	                                       xOutStopper => #arOutSeparatorStore[#nActNo],
	                                       stInOutMainState := #stInOutControlUnitCabinet,
	                                       stInOutHMI := #stInOutHMI.UDT_Separator1,
	                                       stInOutCarrDataInJam := #arInOutStorageLines[#nActNo].arCarrier);
	        
	        REGION Carrier anstauen lassen
	            #fbCarrierWaitStore1.stInTimes.tFreeSen1 := T#2000ms;
	            #fbCarrierWaitStore1.stInTimes.tTimerWait := T#3000ms;
	            #fbCarrierWaitStore1(stInSensor1 := #arInSep[#nActNo].stSenTrolley,
	                                 xInConvActive := true);
	        END_REGION
	        
	        REGION Dummy Handling
	            
	            #arArrayMax[#nActNo] := 10;
	            
	            REGION Dummy erstellen
	                IF #arfbSeparatorStorage[#nActNo].stOutMainTro.xBtPresent AND
	                    #arfbSeparatorStorage[#nActNo].stOutMainTro.nStatus = "SepState_WaitForReq" AND
	                    #arInSep[#nActNo].stSenTrolley.tDirectChangeLast > T#3s AND // variabel machen, Dummy immer anlegen?, Unterscheidung bei Borner?
	                    #arInOutStorageLines[#nActNo].arCarrier[1] = #tmpCarrierEmpty
	                THEN
	                    #arInOutStorageLines[#nActNo].arCarrier[1].nBarcode := #cCarrierDummy;
	                    #arInOutStorageLines[#nActNo].arCarrier[1].bStatus.%X0 := TRUE;
	                END_IF;
	                
	            END_REGION
	            
	            REGION Dummy löschen
	                IF #arArrayMax[#nActNo] > 1 THEN //Staubereich mit Capacity > 0
	                    IF (#arInOutStorageLines[#nActNo].arCarrier[1] = #stCarrierDummy) //Dummy an erster Position
	                        AND #arInOutStorageLines[#nActNo].arCarrier[2] = #tmpCarrierEmpty AND //Keine Daten an zweiter Position
	                        NOT #arInSep[#nActNo].stSenTrolley.xDirectSensor AND #arInSep[#nActNo].stSenTrolley.tDirectChangeLast > T#8s AND //keine Belegung
	                        #arfbSeparatorStorage[#nActNo].stOutMainTro.nStatus = "SepState_WaitForBt" AND #arfbSeparatorStorage[#nActNo].#fbStateManager.tOutTimeInStep > T#8s //Separator Zustand abfragen
	                    THEN
	                        #arInOutStorageLines[#nActNo].arCarrier[1] := #tmpCarrierEmpty; //Dummy löschen
	                    ELSIF (#arInOutStorageLines[#nActNo].arCarrier[1] = #stCarrierDummy) //Dasselbe wie oben aber mit nachrücken
	                        AND (#arInOutStorageLines[#nActNo].arCarrier[2] = #stCarrierDummy OR #arInOutStorageLines[#nActNo].arCarrier[2] <> #stCarrierDummy) AND
	                        NOT #arInSep[#nActNo].stSenTrolley.xDirectSensor AND #arInSep[#nActNo].stSenTrolley.tDirectChangeLast > T#8s AND
	                        #arfbSeparatorStorage[#nActNo].stOutMainTro.nStatus = "SepState_WaitForBt" AND #arfbSeparatorStorage[#nActNo].#fbStateManager.tOutTimeInStep > T#8s //Separator Zustand abfragen
	                    THEN
	                        #arInOutStorageLines[#nActNo].arCarrier[1] := #tmpCarrierEmpty;
	                        "FC_TSHR_Shift"(xInShiftBack := TRUE,
	                                        arTSHR := #arInOutStorageLines[#nActNo].arCarrier);
	                    END_IF;
	                ELSIF #nArrayMax = 1 THEN
	                    IF (#arInOutStorageLines[#nActNo].arCarrier[1] = #stCarrierDummy) AND
	                        NOT #arInSep[#nActNo].stSenTrolley.xDirectSensor AND #arInSep[#nActNo].stSenTrolley.tDirectChangeLast > T#8s AND
	                        #arfbSeparatorStorage[#nActNo].stOutMainTro.nStatus = "SepState_WaitForBt" AND #arfbSeparatorStorage[#nActNo].#fbStateManager.tOutTimeInStep > T#8s //Separator Zustand abfragen
	                    THEN
	                        #arInOutStorageLines[#nActNo].arCarrier[1] := #tmpCarrierEmpty;
	                    END_IF;
	                END_IF;
	                
	            END_REGION
	            
	        END_REGION
	        
	    END_REGION
	    
	    REGION Sep 2
	        #nActNo := 2;
	        IF #stInSettings.nNoOfLines >= #nActNo THEN
	            #arfbSeparatorStorage[#nActNo](stInSettings := #arInSep[#nActNo].stSettings,
	                                           xInConveyorRun := #xInConveyorRunOut,
	                                           stInTrolley := #arInSep[#nActNo].stSenTrolley,
	                                           xInReceiveReady := NOT #fbCarrierWaitStore2.xOutLockSep1 AND #arLineRelease[#nActNo] AND NOT #arInOutJamExit[#arInSep[#nActNo].stSettings.nJamLength].bStatus.%X0,
	                                           stInOutMainState := #stInOutControlUnitCabinet,
	                                           xOutStopper => #arOutSeparatorStore[#nActNo],
	                                           stInOutHMI := #stInOutHMI.UDT_Separator2,
	                                           stInOutCarrDataInJam := #arInOutStorageLines[#nActNo].arCarrier);
	        END_IF;
	        
	        REGION Carrier anstauen lassen
	            #fbCarrierWaitStore2.stInTimes.tFreeSen1 := T#2000ms;
	            #fbCarrierWaitStore2.stInTimes.tTimerWait := T#3000ms;
	            #fbCarrierWaitStore2(stInSensor1 := #arInSep[#nActNo].stSenTrolley,
	                                 xInConvActive := true);
	        END_REGION
	        
	        REGION Dummy Handling
	            
	            #arArrayMax[#nActNo] := 10;
	            
	            REGION Dummy erstellen
	                IF #arfbSeparatorStorage[#nActNo].stOutMainTro.xBtPresent AND
	                    #arfbSeparatorStorage[#nActNo].stOutMainTro.nStatus = "SepState_WaitForReq" AND
	                    #arInSep[#nActNo].stSenTrolley.tDirectChangeLast > T#3s AND // variabel machen, Dummy immer anlegen?, Unterscheidung bei Borner?
	                    #arInOutStorageLines[#nActNo].arCarrier[1] = #tmpCarrierEmpty
	                THEN
	                    #arInOutStorageLines[#nActNo].arCarrier[1].nBarcode := #cCarrierDummy;
	                    #arInOutStorageLines[#nActNo].arCarrier[1].bStatus.%X0 := TRUE;
	                END_IF;
	                
	            END_REGION
	            
	            REGION Dummy löschen
	                IF #arArrayMax[#nActNo] > 1 THEN //Staubereich mit Capacity > 0
	                    IF (#arInOutStorageLines[#nActNo].arCarrier[1] = #stCarrierDummy) //Dummy an erster Position
	                        AND #arInOutStorageLines[#nActNo].arCarrier[2] = #tmpCarrierEmpty AND //Keine Daten an zweiter Position
	                        NOT #arInSep[#nActNo].stSenTrolley.xDirectSensor AND #arInSep[#nActNo].stSenTrolley.tDirectChangeLast > T#8s AND //keine Belegung
	                        #arfbSeparatorStorage[#nActNo].stOutMainTro.nStatus = "SepState_WaitForBt" AND #arfbSeparatorStorage[#nActNo].#fbStateManager.tOutTimeInStep > T#8s //Separator Zustand abfragen
	                    THEN
	                        #arInOutStorageLines[#nActNo].arCarrier[1] := #tmpCarrierEmpty; //Dummy löschen
	                    ELSIF (#arInOutStorageLines[#nActNo].arCarrier[1] = #stCarrierDummy) //Dasselbe wie oben aber mit nachrücken
	                        AND (#arInOutStorageLines[#nActNo].arCarrier[2] = #stCarrierDummy OR #arInOutStorageLines[#nActNo].arCarrier[2] <> #stCarrierDummy) AND
	                        NOT #arInSep[#nActNo].stSenTrolley.xDirectSensor AND #arInSep[#nActNo].stSenTrolley.tDirectChangeLast > T#8s AND
	                        #arfbSeparatorStorage[#nActNo].stOutMainTro.nStatus = "SepState_WaitForBt" AND #arfbSeparatorStorage[#nActNo].#fbStateManager.tOutTimeInStep > T#8s //Separator Zustand abfragen
	                    THEN
	                        #arInOutStorageLines[#nActNo].arCarrier[1] := #tmpCarrierEmpty;
	                        "FC_TSHR_Shift"(xInShiftBack := TRUE,
	                                        arTSHR := #arInOutStorageLines[#nActNo].arCarrier);
	                    END_IF;
	                ELSIF #nArrayMax = 1 THEN
	                    IF (#arInOutStorageLines[#nActNo].arCarrier[1] = #stCarrierDummy) AND
	                        NOT #arInSep[#nActNo].stSenTrolley.xDirectSensor AND #arInSep[#nActNo].stSenTrolley.tDirectChangeLast > T#8s AND
	                        #arfbSeparatorStorage[#nActNo].stOutMainTro.nStatus = "SepState_WaitForBt" AND #arfbSeparatorStorage[#nActNo].#fbStateManager.tOutTimeInStep > T#8s //Separator Zustand abfragen
	                    THEN
	                        #arInOutStorageLines[#nActNo].arCarrier[1] := #tmpCarrierEmpty;
	                    END_IF;
	                END_IF;
	                
	            END_REGION
	            
	        END_REGION
	        
	        
	    END_REGION
	    
	    REGION Sep 3
	        #nActNo := 3;
	        IF #stInSettings.nNoOfLines >= #nActNo THEN
	            #arfbSeparatorStorage[#nActNo](stInSettings := #arInSep[#nActNo].stSettings,
	                                           xInConveyorRun := #xInConveyorRunOut,
	                                           stInTrolley := #arInSep[#nActNo].stSenTrolley,
	                                           xInReceiveReady := #arLineRelease[#nActNo] AND NOT #arInOutJamExit[#arInSep[#nActNo].stSettings.nJamLength].bStatus.%X0,
	                                           stInOutMainState := #stInOutControlUnitCabinet,
	                                           xOutStopper => #arOutSeparatorStore[#nActNo],
	                                           stInOutHMI := #stInOutHMI.UDT_Separator3,
	                                           stInOutCarrDataInJam := #arInOutStorageLines[#nActNo].arCarrier);
	        END_IF;
	        
	        REGION Carrier anstauen lassen
	            #fbCarrierWaitStore3.stInTimes.tFreeSen1 := T#2000ms;
	            #fbCarrierWaitStore3.stInTimes.tTimerWait := T#3000ms;
	            #fbCarrierWaitStore3(stInSensor1 := #arInSep[#nActNo].stSenTrolley,
	                                 xInConvActive := true);
	        END_REGION
	        
	        REGION Dummy Handling
	            
	            #arArrayMax[#nActNo] := 10;
	            
	            REGION Dummy erstellen
	                IF #arfbSeparatorStorage[#nActNo].stOutMainTro.xBtPresent AND
	                    #arfbSeparatorStorage[#nActNo].stOutMainTro.nStatus = "SepState_WaitForReq" AND
	                    #arInSep[#nActNo].stSenTrolley.tDirectChangeLast > T#3s AND // variabel machen, Dummy immer anlegen?, Unterscheidung bei Borner?
	                    #arInOutStorageLines[#nActNo].arCarrier[1] = #tmpCarrierEmpty
	                THEN
	                    #arInOutStorageLines[#nActNo].arCarrier[1].nBarcode := #cCarrierDummy;
	                    #arInOutStorageLines[#nActNo].arCarrier[1].bStatus.%X0 := TRUE;
	                END_IF;
	                
	            END_REGION
	            
	            REGION Dummy löschen
	                IF #arArrayMax[#nActNo] > 1 THEN //Staubereich mit Capacity > 0
	                    IF (#arInOutStorageLines[#nActNo].arCarrier[1] = #stCarrierDummy) //Dummy an erster Position
	                        AND #arInOutStorageLines[#nActNo].arCarrier[2] = #tmpCarrierEmpty AND //Keine Daten an zweiter Position
	                        NOT #arInSep[#nActNo].stSenTrolley.xDirectSensor AND #arInSep[#nActNo].stSenTrolley.tDirectChangeLast > T#8s AND //keine Belegung
	                        #arfbSeparatorStorage[#nActNo].stOutMainTro.nStatus = "SepState_WaitForBt" AND #arfbSeparatorStorage[#nActNo].#fbStateManager.tOutTimeInStep > T#8s //Separator Zustand abfragen
	                    THEN
	                        #arInOutStorageLines[#nActNo].arCarrier[1] := #tmpCarrierEmpty; //Dummy löschen
	                    ELSIF (#arInOutStorageLines[#nActNo].arCarrier[1] = #stCarrierDummy) //Dasselbe wie oben aber mit nachrücken
	                        AND (#arInOutStorageLines[#nActNo].arCarrier[2] = #stCarrierDummy OR #arInOutStorageLines[#nActNo].arCarrier[2] <> #stCarrierDummy) AND
	                        NOT #arInSep[#nActNo].stSenTrolley.xDirectSensor AND #arInSep[#nActNo].stSenTrolley.tDirectChangeLast > T#8s AND
	                        #arfbSeparatorStorage[#nActNo].stOutMainTro.nStatus = "SepState_WaitForBt" AND #arfbSeparatorStorage[#nActNo].#fbStateManager.tOutTimeInStep > T#8s //Separator Zustand abfragen
	                    THEN
	                        #arInOutStorageLines[#nActNo].arCarrier[1] := #tmpCarrierEmpty;
	                        "FC_TSHR_Shift"(xInShiftBack := TRUE,
	                                        arTSHR := #arInOutStorageLines[#nActNo].arCarrier);
	                    END_IF;
	                ELSIF #nArrayMax = 1 THEN
	                    IF (#arInOutStorageLines[#nActNo].arCarrier[1] = #stCarrierDummy) AND
	                        NOT #arInSep[#nActNo].stSenTrolley.xDirectSensor AND #arInSep[#nActNo].stSenTrolley.tDirectChangeLast > T#8s AND
	                        #arfbSeparatorStorage[#nActNo].stOutMainTro.nStatus = "SepState_WaitForBt" AND #arfbSeparatorStorage[#nActNo].#fbStateManager.tOutTimeInStep > T#8s //Separator Zustand abfragen
	                    THEN
	                        #arInOutStorageLines[#nActNo].arCarrier[1] := #tmpCarrierEmpty;
	                    END_IF;
	                END_IF;
	                
	            END_REGION
	            
	        END_REGION
	        
	    END_REGION
	    
	    REGION Sep 4
	        #nActNo := 4;
	        IF #stInSettings.nNoOfLines >= #nActNo THEN
	            #arfbSeparatorStorage[#nActNo](stInSettings := #arInSep[#nActNo].stSettings,
	                                           xInConveyorRun := #xInConveyorRunOut,
	                                           stInTrolley := #arInSep[#nActNo].stSenTrolley,
	                                           xInReceiveReady := #arLineRelease[#nActNo] AND NOT #arInOutJamExit[#arInSep[#nActNo].stSettings.nJamLength].bStatus.%X0,
	                                           stInOutMainState := #stInOutControlUnitCabinet,
	                                           xOutStopper => #arOutSeparatorStore[#nActNo],
	                                           stInOutHMI := #stInOutHMI.UDT_Separator4,
	                                           stInOutCarrDataInJam := #arInOutStorageLines[#nActNo].arCarrier);
	        END_IF;
	        
	        REGION Carrier anstauen lassen
	            #fbCarrierWaitStore4.stInTimes.tFreeSen1 := T#2000ms;
	            #fbCarrierWaitStore4.stInTimes.tTimerWait := T#3000ms;
	            #fbCarrierWaitStore4(stInSensor1 := #arInSep[#nActNo].stSenTrolley,
	                                 xInConvActive := true);
	        END_REGION
	        
	        REGION Dummy Handling
	            
	            #arArrayMax[#nActNo] := 10;
	            
	            REGION Dummy erstellen
	                IF #arfbSeparatorStorage[#nActNo].stOutMainTro.xBtPresent AND
	                    #arfbSeparatorStorage[#nActNo].stOutMainTro.nStatus = "SepState_WaitForReq" AND
	                    #arInSep[#nActNo].stSenTrolley.tDirectChangeLast > T#3s AND // variabel machen, Dummy immer anlegen?, Unterscheidung bei Borner?
	                    #arInOutStorageLines[#nActNo].arCarrier[1] = #tmpCarrierEmpty
	                THEN
	                    #arInOutStorageLines[#nActNo].arCarrier[1].nBarcode := #cCarrierDummy;
	                    #arInOutStorageLines[#nActNo].arCarrier[1].bStatus.%X0 := TRUE;
	                END_IF;
	                
	            END_REGION
	            
	            REGION Dummy löschen
	                IF #arArrayMax[#nActNo] > 1 THEN //Staubereich mit Capacity > 0
	                    IF (#arInOutStorageLines[#nActNo].arCarrier[1] = #stCarrierDummy) //Dummy an erster Position
	                        AND #arInOutStorageLines[#nActNo].arCarrier[2] = #tmpCarrierEmpty AND //Keine Daten an zweiter Position
	                        NOT #arInSep[#nActNo].stSenTrolley.xDirectSensor AND #arInSep[#nActNo].stSenTrolley.tDirectChangeLast > T#8s AND //keine Belegung
	                        #arfbSeparatorStorage[#nActNo].stOutMainTro.nStatus = "SepState_WaitForBt" AND #arfbSeparatorStorage[#nActNo].#fbStateManager.tOutTimeInStep > T#8s //Separator Zustand abfragen
	                    THEN
	                        #arInOutStorageLines[#nActNo].arCarrier[1] := #tmpCarrierEmpty; //Dummy löschen
	                    ELSIF (#arInOutStorageLines[#nActNo].arCarrier[1] = #stCarrierDummy) //Dasselbe wie oben aber mit nachrücken
	                        AND (#arInOutStorageLines[#nActNo].arCarrier[2] = #stCarrierDummy OR #arInOutStorageLines[#nActNo].arCarrier[2] <> #stCarrierDummy) AND
	                        NOT #arInSep[#nActNo].stSenTrolley.xDirectSensor AND #arInSep[#nActNo].stSenTrolley.tDirectChangeLast > T#8s AND
	                        #arfbSeparatorStorage[#nActNo].stOutMainTro.nStatus = "SepState_WaitForBt" AND #arfbSeparatorStorage[#nActNo].#fbStateManager.tOutTimeInStep > T#8s //Separator Zustand abfragen
	                    THEN
	                        #arInOutStorageLines[#nActNo].arCarrier[1] := #tmpCarrierEmpty;
	                        "FC_TSHR_Shift"(xInShiftBack := TRUE,
	                                        arTSHR := #arInOutStorageLines[#nActNo].arCarrier);
	                    END_IF;
	                ELSIF #nArrayMax = 1 THEN
	                    IF (#arInOutStorageLines[#nActNo].arCarrier[1] = #stCarrierDummy) AND
	                        NOT #arInSep[#nActNo].stSenTrolley.xDirectSensor AND #arInSep[#nActNo].stSenTrolley.tDirectChangeLast > T#8s AND
	                        #arfbSeparatorStorage[#nActNo].stOutMainTro.nStatus = "SepState_WaitForBt" AND #arfbSeparatorStorage[#nActNo].#fbStateManager.tOutTimeInStep > T#8s //Separator Zustand abfragen
	                    THEN
	                        #arInOutStorageLines[#nActNo].arCarrier[1] := #tmpCarrierEmpty;
	                    END_IF;
	                END_IF;
	                
	            END_REGION
	            
	        END_REGION
	    END_REGION
	    
	    REGION Sep 5
	        #nActNo := 5;
	        IF #stInSettings.nNoOfLines >= #nActNo THEN
	            #arfbSeparatorStorage[#nActNo](stInSettings := #arInSep[#nActNo].stSettings,
	                                           xInConveyorRun := #xInConveyorRunOut,
	                                           stInTrolley := #arInSep[#nActNo].stSenTrolley,
	                                           xInReceiveReady := #arLineRelease[#nActNo] AND NOT #arInOutJamExit[#arInSep[#nActNo].stSettings.nJamLength].bStatus.%X0,
	                                           stInOutMainState := #stInOutControlUnitCabinet,
	                                           xOutStopper => #arOutSeparatorStore[#nActNo],
	                                           stInOutHMI := #stInOutHMI.UDT_Separator5,
	                                           stInOutCarrDataInJam := #arInOutStorageLines[#nActNo].arCarrier);
	        END_IF;
	        
	        REGION Carrier anstauen lassen
	            #fbCarrierWaitStore5.stInTimes.tFreeSen1 := T#2000ms;
	            #fbCarrierWaitStore5.stInTimes.tTimerWait := T#3000ms;
	            #fbCarrierWaitStore5(stInSensor1 := #arInSep[#nActNo].stSenTrolley,
	                                 xInConvActive := true);
	        END_REGION
	        
	        REGION Dummy Handling
	            
	            #arArrayMax[#nActNo] := 10;
	            
	            REGION Dummy erstellen
	                IF #arfbSeparatorStorage[#nActNo].stOutMainTro.xBtPresent AND
	                    #arfbSeparatorStorage[#nActNo].stOutMainTro.nStatus = "SepState_WaitForReq" AND
	                    #arInSep[#nActNo].stSenTrolley.tDirectChangeLast > T#3s AND // variabel machen, Dummy immer anlegen?, Unterscheidung bei Borner?
	                    #arInOutStorageLines[#nActNo].arCarrier[1] = #tmpCarrierEmpty
	                THEN
	                    #arInOutStorageLines[#nActNo].arCarrier[1].nBarcode := #cCarrierDummy;
	                    #arInOutStorageLines[#nActNo].arCarrier[1].bStatus.%X0 := TRUE;
	                END_IF;
	                
	            END_REGION
	            
	            REGION Dummy löschen
	                IF #arArrayMax[#nActNo] > 1 THEN //Staubereich mit Capacity > 0
	                    IF (#arInOutStorageLines[#nActNo].arCarrier[1] = #stCarrierDummy) //Dummy an erster Position
	                        AND #arInOutStorageLines[#nActNo].arCarrier[2] = #tmpCarrierEmpty AND //Keine Daten an zweiter Position
	                        NOT #arInSep[#nActNo].stSenTrolley.xDirectSensor AND #arInSep[#nActNo].stSenTrolley.tDirectChangeLast > T#8s AND //keine Belegung
	                        #arfbSeparatorStorage[#nActNo].stOutMainTro.nStatus = "SepState_WaitForBt" AND #arfbSeparatorStorage[#nActNo].#fbStateManager.tOutTimeInStep > T#8s //Separator Zustand abfragen
	                    THEN
	                        #arInOutStorageLines[#nActNo].arCarrier[1] := #tmpCarrierEmpty; //Dummy löschen
	                    ELSIF (#arInOutStorageLines[#nActNo].arCarrier[1] = #stCarrierDummy) //Dasselbe wie oben aber mit nachrücken
	                        AND (#arInOutStorageLines[#nActNo].arCarrier[2] = #stCarrierDummy OR #arInOutStorageLines[#nActNo].arCarrier[2] <> #stCarrierDummy) AND
	                        NOT #arInSep[#nActNo].stSenTrolley.xDirectSensor AND #arInSep[#nActNo].stSenTrolley.tDirectChangeLast > T#8s AND
	                        #arfbSeparatorStorage[#nActNo].stOutMainTro.nStatus = "SepState_WaitForBt" AND #arfbSeparatorStorage[#nActNo].#fbStateManager.tOutTimeInStep > T#8s //Separator Zustand abfragen
	                    THEN
	                        #arInOutStorageLines[#nActNo].arCarrier[1] := #tmpCarrierEmpty;
	                        "FC_TSHR_Shift"(xInShiftBack := TRUE,
	                                        arTSHR := #arInOutStorageLines[#nActNo].arCarrier);
	                    END_IF;
	                ELSIF #nArrayMax = 1 THEN
	                    IF (#arInOutStorageLines[#nActNo].arCarrier[1] = #stCarrierDummy) AND
	                        NOT #arInSep[#nActNo].stSenTrolley.xDirectSensor AND #arInSep[#nActNo].stSenTrolley.tDirectChangeLast > T#8s AND
	                        #arfbSeparatorStorage[#nActNo].stOutMainTro.nStatus = "SepState_WaitForBt" AND #arfbSeparatorStorage[#nActNo].#fbStateManager.tOutTimeInStep > T#8s //Separator Zustand abfragen
	                    THEN
	                        #arInOutStorageLines[#nActNo].arCarrier[1] := #tmpCarrierEmpty;
	                    END_IF;
	                END_IF;
	                
	            END_REGION
	            
	        END_REGION
	    END_REGION
	    
	END_REGION
	
	REGION Ausgänge
	    
	    (* VON PIN STORE KOPIERT
	    REGION Output
	    #xOutConvReqSort := (#nStateE = #c1500_StepReleaseSep1) OR (#nStateE = #c2500_StepReleaseSep2); //TRUE;//#fbSeparatorPin.xOutConveyorRequest;
	    #xOutConvReqExit := (#nStateA = #c1500_StepReleaseSep1) OR (#nStateA = #c2500_StepReleaseSep2);
	    
	    FOR #nIdx2 := 1 TO #cUnloadingStations DO
	        IF #arfbStationUnloadPin[#nIdx2].xOutUnloadingError THEN
	            #xOutUnloadingError := TRUE;
	            EXIT;
	        ELSE
	            #xOutUnloadingError := FALSE;
	        END_IF;
	    END_FOR;
	    
	    #xOutCorrection := #xTmpCorrection;
	END_REGION
	    *)
	    
	    
	    REGION Einlagern
	        IF #nLineNr = 0 (* AND #nInBufferNr = "cMainTro102" *) THEN
	            #nOutLineNr := 1; //nur um Bereichslängenfehler zu vermeiden
	        ELSE
	            #nOutLineNr := #nLineNr;
	        END_IF;
	        #xOutBypass := #nInBufferNr = "cMainTro101" AND #xBypassNextBoom AND #nStateE = #c0200_StepIdle;
	        #xOutReadyToReceive := #nStateE = #c0900_StepWorking;
	        #nOutFillLevel := (
	        (* 100/(5*#stInStorageData1.Config.nCapacitySet)* *)
	        // (#stInStorageData1.Status.nCount +
	        // #stInStorageData2.Status.nCount +
	        // #stInStorageData3.Status.nCount +
	        // #stInStorageData4.Status.nCount +
	        // #stInStorageData5.Status.nCount)
	        (#arInOutStorageLines[1].stData.Status.nCount +
	        #arInOutStorageLines[2].stData.Status.nCount +
	        #arInOutStorageLines[3].stData.Status.nCount +
	        #arInOutStorageLines[4].stData.Status.nCount +
	        #arInOutStorageLines[5].stData.Status.nCount)
	        );
	        IF #nOutFillLevel >= (#arInOutStorageLines[1].stData.Config.nCapacitySet +
	            #arInOutStorageLines[2].stData.Config.nCapacitySet +
	            #arInOutStorageLines[3].stData.Config.nCapacitySet +
	            #arInOutStorageLines[4].stData.Config.nCapacitySet +
	            #arInOutStorageLines[5].stData.Config.nCapacitySet) THEN
	            #xOutFull := TRUE;
	        ELSE
	            #xOutFull := FALSE;
	        END_IF;
	        
	        FOR #nIdx := 1 TO 5 DO
	            #arOutSwitchLine[#nIdx] := FALSE;
	        END_FOR;
	        IF #nLineNr <> 0 (* AND #nLineNr <> 6 *) AND #nStateE > #c0400_StepWaitAndSwitch THEN
	            #arOutSwitchLine[#nLineNr] := TRUE;
	        END_IF;
	    END_REGION
	    
	    REGION Auslagern
	        // chjchjc
	        #xOutSepExitRelease := #xTmpSepExitRelease;
	        #xOutSwitchExitReady := #xTmpSwitchExitReady;
	        
	        
	        #nOutActNo := #nSepNr;
	        #xOutCarouselReq := #nStateA = #c2500_StepReleaseSep2;
	        
	    END_REGION
	
	END_REGION
	
	REGION Event Logs
	    
	    REGION Event: Umbuchung Lagerlinie auf Exit
	        IF #nActLine = 1 THEN
	            #stBookingInfo.sJamSrc := 'JamStore1';
	        ELSIF #nActLine = 2 THEN
	            #stBookingInfo.sJamSrc := 'JamStore2';
	        END_IF;
	        
	        #stBookingInfo.sJamDest := #stInSettings.sJamDest;
	        
	        #fbEventLog_Route2(xInTrigger := #xEventLogBookExit,
	                           stInEventBookingInfo := #stBookingInfo);
	    END_REGION
	    
	    // Pro Event wird ein Aufruf benötigt
	    REGION Korrekturvorgänge loggen
	        
	        #fbEventLogCorrection1(xInTrigger := #arEventCorrectionInfo[0].xTrigger,
	                               stInEventCorrectionInfo := #arEventCorrectionInfo[0]);
	        
	        #fbEventLogCorrection2(xInTrigger := #arEventCorrectionInfo[1].xTrigger,
	                               stInEventCorrectionInfo := #arEventCorrectionInfo[1]);
	        
	    END_REGION
	    
	    #fbEventLogCarrierUnknown(xInTrigger := #xUnknownCarrier,
	                              stInEventScanInfo := #stEventUnknown);
	    
	    #fbEventLogCarrierNew(xInTrigger := #xNewCarrier,
	                          stInEventScanInfo := #stEventNew);
	    
	    #fbEventLogGoodRead(xInTrigger := #xGoodRead,
	                        stInEventScanInfo := #stEventGoodRead);
	    
	END_REGION
	REGION Letzten Schritt wegschreiben
	    #nOutStateLast := #fbStateManagerA.nStateLast;
	END_REGION
	REGION Priority Manager
	    #stOutPriorityManager.nTroId := #nInBufferNr;
	    #stOutPriorityManager.stJamExit := #stInOutJamExit;
	    // #stOutPriorityManager.stJamEntry := ; todo
	    IF #nActNo > 0 THEN
	        #stOutPriorityManager.stSensor := #arInSep[#nActNo].stSenTrolley;
	    END_IF;
	    #stOutPriorityManager.xMovement := #xInConveyorRunOut;
	    //   #stOutPriorityManager.xTrolleyPresent := ; // todo für mengengesteuert
	    #stOutPriorityManager.xTransportReq := (* (#stActRequest.nDirection = 1) AND *)#nStateA = #c2500_StepReleaseSep2 AND #xStart;
	    
	END_REGION
	
	REGION HMI
	    #stInOutHMI.UDT_UnloadingStation1.xInHome := NOT #arOutSwitchLine[1];
	    #stInOutHMI.UDT_UnloadingStation1.xInWork := #arOutSwitchLine[1];
	    
	    #stInOutHMI.UDT_UnloadingStation2.xInHome := NOT #arOutSwitchLine[2];
	    #stInOutHMI.UDT_UnloadingStation2.xInWork := #arOutSwitchLine[2];
	    
	    #stInOutHMI.UDT_UnloadingStation3.xInHome := NOT #arOutSwitchLine[3];
	    #stInOutHMI.UDT_UnloadingStation3.xInWork := #arOutSwitchLine[3];
	    
	    #stInOutHMI.UDT_UnloadingStation4.xInHome := NOT #arOutSwitchLine[4];
	    #stInOutHMI.UDT_UnloadingStation4.xInWork := #arOutSwitchLine[4];
	    
	    #stInOutHMI.UDT_UnloadingStation5.xInHome := NOT #arOutSwitchLine[5];
	    #stInOutHMI.UDT_UnloadingStation5.xInWork := #arOutSwitchLine[5];
	    
	END_REGION
	
	
END_FUNCTION_BLOCK

