FUNCTION_BLOCK "FB_ILS_STRO_Sep"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT 
      xInConveyorRun : Bool;   // Antrieb läuft
      stInTrolley : "UDT_Sensor";   // Separator In-Sensor
      xInReceiveReady : Bool;   // Freigabe 
      xInErrQuit : Bool;   // Fehler quittieren
      xInReset : Bool;   // Baustein rücksetzen
      xInPinSort : Bool := false;   // Sep für das Einsortieren am Pinband
      stInSettings : "SettingsSeparator";
   END_VAR

   VAR_OUTPUT 
      stOutMainTro : "IntfSeparator";   // Interface für MainTro
      xOutConveyorRequest : Bool;
      xOutTrolleyRequest : Bool;
      xOutTrolleyInSep : Bool;
      xOutTrolleyReleasedEdge : Bool;   // Flanke bei neuen Trolley am Ausgang
      xOutStopper : Bool;
      wOutErrorWord : Word;
   END_VAR

   VAR_IN_OUT 
      stInOutMainState : "UDT_MainState";
      stInOutHMI : "UDT_HMI_Separator";   // HMI Schnittstelle 
      stInOutCarrDataInJam : Array[*] of "stCarrier";
   END_VAR

   VAR 
      fbStateManager : "FB_StateManager";
      stCarrierDummy { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : "stCarrier";
      tOnHandling {InstructionName := 'TON_TIME'; LibVersion := '1.0'} : TON_TIME;
      tOnTrailing {InstructionName := 'TON_TIME'; LibVersion := '1.0'} : TON_TIME;
      tOnMonitoring {InstructionName := 'TON_TIME'; LibVersion := '1.0'} : TON_TIME;
   END_VAR
   VAR RETAIN
      CountCarr {InstructionName := 'CTU_UDINT'; LibVersion := '1.0'} : CTU_UDINT;
   END_VAR
   VAR 
      rTrigCount {InstructionName := 'R_TRIG'; LibVersion := '1.0'} : R_TRIG;
      nArrayMax : Int;
   END_VAR
   VAR RETAIN
      nState : Int;
   END_VAR
   VAR 
      nLastStep { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;
      arStepHistory : Array[0..10] of Struct
         StepNum : Int;
         TimeStamp {InstructionName := 'DTL'; LibVersion := '1.0'} : DTL;
      END_STRUCT;
      fbMonitoringCarrStuck : "FB_Monitoring";   // Carrier verlässt Separator nicht
      fbMonitoringCarrMismatch : "FB_Monitoring";   // Separator Sensorik unplausibel (z.B. Part-Sensor ohne In-Sensor)
      wErrorWord : Word;
      stSimuSeparator : Struct
         nState : Int;
         xSensor : Bool;
      END_STRUCT;
      stSimuSensor : "UDT_Sensor";
      xCorrectionDone : Bool;   // Einmal probieren
   END_VAR

   VAR_TEMP 
      t_Status : Int;
      t_Handling : Bool;
      t_Trailing : Bool;
      t_Monitoring : Bool;
      tmpActUnivTon : Bool;
      nCount : UDInt;
      tmpCarrierEmpty : "stCarrier";
      tTrolley : "UDT_Sensor";
   END_VAR

   VAR CONSTANT 
      c000_StepInit : Int := 0;   // Init
      c100_StepWaitForTrolley : Int := 100;   // Warte auf Trolley
      c110_StepWaitForRelease : Int := 110;   // Warte auf Freigabe 
      c120_StepOpen : Int := 120;   // Separator öffnen
      c130_StepWaitForLeave : Int := 130;   // Warte auf Trolley verlassen
      c140_StepClose1 : Int := 140;   // Separator schliessen
   END_VAR


BEGIN
	// Prinzip: Unabhängig von Single Carrier oder Minitrolley -> Einzelachse am Separator takten
	// Separator übernimmt nur die simple Funktion eines Separator-Moduls (In-Sensor, Stopper Auf, Stopper Zu)
	// Alle anderen Überprüfungen (z.B. Zappler, Scanner) werden vom MainTro übernommen
	
	#nArrayMax := DINT_TO_INT(UPPER_BOUND(ARR := #stInOutCarrDataInJam, DIM := 1));
	
	REGION Info
	    (*Errors
	    #wOutErrorWord.%X0        Step failure
	    #wOutErrorWord.%X1        Carrier stuck
	    #wOutErrorWord.%X2        Carrier mismatch
	    #wOutErrorWord.%X3        Carrier not arriving
	    #wOutErrorWord.%X4        Motor not running
	    #wOutErrorWord.%X5        res5
	    #wOutErrorWord.%X6        res6
	    #wOutErrorWord.%X7        res7
	    #wOutErrorWord.%X8        res8
	    #wOutErrorWord.%X9        res9
	    #wOutErrorWord.%X10       res10
	    #wOutErrorWord.%X11       res11
	    #wOutErrorWord.%X12       res12
	    #wOutErrorWord.%X13       res13
	    #wOutErrorWord.%X14       res14
	    #wOutErrorWord.%X15       Modul reset
	    *)
	END_REGION
	
	REGION MT Separator Simu
	    //Simuliert Ablauf für Minitrolley (Sensorverhalten mit Timern nachgebildet)
	    IF #stInSettings.stSimu.xActive THEN
	        IF NOT #stInOutCarrDataInJam[1].bStatus.%X0 THEN
	            #stSimuSeparator.nState := 100;
	        END_IF;
	        
	        CASE #stSimuSeparator.nState OF
	            100:  //INIT / STANDBY
	                #stSimuSeparator.xSensor := FALSE;
	                IF #stInOutCarrDataInJam[1].bStatus.%X0
	           //         AND #stInOutCarrDataInJam[1].nSimuPos = #stInSettings.stSimu.stJamConfig.nMaxPos
	                    AND (#stOutMainTro.nStatus = "SepState_WaitForBt" OR #stOutMainTro.nStatus = "SepState_WaitForReq")
	                THEN
	                    #stSimuSeparator.nState := 200;
	                END_IF;
	            200:  // First MT
	                #stSimuSeparator.xSensor := TRUE;
	                IF #stOutMainTro.nStatus = "SepState_Open" THEN
	                    #tmpActUnivTon := TRUE;
	                    IF #fbStateManager.tOutUnivTonR > #stInSettings.stSimu.tSenTime THEN
	                        #stSimuSeparator.xSensor := FALSE;
	                        #stSimuSeparator.nState := 300;
	                    END_IF;
	                END_IF;
	            300:
	                IF #stOutMainTro.nStatus = "SepState_WaitForSecondLeg" THEN
	                    #stSimuSeparator.nState := 400;
	                END_IF;
	            400:
	                #stSimuSeparator.xSensor := TRUE;
	                IF #stOutMainTro.nStatus = "SepState_OpenSecond" THEN
	                    #tmpActUnivTon := TRUE;
	                    IF #fbStateManager.tOutUnivTonR > #stInSettings.stSimu.tSenTime THEN
	                        #stSimuSeparator.xSensor := FALSE;
	                        #stSimuSeparator.nState := 100;
	                    END_IF;
	                END_IF;
	        END_CASE;
	        
	    END_IF;
	    REGION Sensor Simu
	        // #fbSimuSensorInput(sInName := #stInTrolley.sName,
	        //                    xInSensor := #stSimuSeparator.xSensor,
	        //                    stInOutSensor := #stSimuSensor,
	        //                    stInOutHMI:= #stInOutHMI.
	        //                    stInOutControlUnitCabinet:=#stInOutMainState);
	    END_REGION
	    
	    REGION State Manager Simu
	   (*     #fbStateManager.stInSettings.nStartState := 0;
	        #fbStateManager.stInSettings.xActUnivTOn := TRUE;
	        #fbStateManager.stInSettings.xRestartAtStartState := FALSE;
	        #fbStateManager(xInFunctionEnabled := TRUE,
	                        xInRunUnivTOn := #tmpActUnivTon,
	                        nInOutState := #stSimuSeparator.#nState); *)
	    END_REGION
	END_REGION
	
	REGION Sensor Simu
	    IF #stInSettings.stSimu.xActive THEN
	        #tTrolley := #stSimuSensor;
	    ELSE
	        #tTrolley := #stInTrolley;
	    END_IF;
	END_REGION
	
	REGION ErrorQuitt
	    IF #xInErrQuit THEN
	        #wErrorWord := 0;
	    END_IF;
	END_REGION
	
	REGION Reset
	    IF #xInReset THEN
	        #nState := 000;                          // Setz alles auf 0
	        #wErrorWord.%X15 := true;             // warning, modul reset
	    END_IF;
	END_REGION
	
	
	REGION Step sequence
	    CASE #nState OF
	        #c000_StepInit:
	            REGION Step 000 - init
	                //akt. Zustand
	                #stOutMainTro.nStatus := "SepState_Init";
	                //Outputs
	                #xOutStopper := FALSE;              //Separator zu
	                #xOutTrolleyReleasedEdge := FALSE;  //Datenübergabe rücksetzen
	                #xOutConveyorRequest := FALSE;      // Förderer Anforderung rücksetzen
	                #xOutTrolleyRequest := FALSE;       // Trolley Anforderung rücksetzen
	                #xOutTrolleyInSep := FALSE;         // Trolley im Separator rücksetzen
	                
	                // SCHRITT 0 NICHT ENTFERNEN!
	                // STATE MANAGER MACHT DEN SCHRITTWECHSEL!
	                
	            END_REGION
	        #c100_StepWaitForTrolley:
	            REGION Step 100 - wait for trolley
	                //akt. Zustand
	                #stOutMainTro.nStatus := "SepState_WaitForBt"; // TODO
	                
	                #xOutStopper := FALSE;                      // Separator zu
	                #xOutTrolleyReleasedEdge := FALSE;          // Datenübergabe rücksetzen
	                #xOutConveyorRequest := FALSE;              // Förderer Anforderung rücksetzen 
	                #xOutTrolleyRequest := TRUE;                // Trolley Anforderung 
	                
	                #xCorrectionDone := FALSE;
	                
	                IF #tTrolley.xDirectSensor THEN              // Trolley im Separator
	                    #nState := #c110_StepWaitForRelease;        // Schrittwechsel   
	                END_IF;
	            END_REGION
	        #c110_StepWaitForRelease:
	            REGION Step 110 - wait release request
	                // akt. Zustand
	                #stOutMainTro.nStatus := "SepState_WaitForReq";
	                // Outputs
	                #xOutStopper := FALSE;                      // Separator ZU
	                #xOutTrolleyRequest := FALSE;
	                #xOutTrolleyInSep := (#xInPinSort AND #tTrolley.xDirectSensor) OR (NOT #xInPinSort AND #tTrolley.xDbncdSensor);
	                #xOutConveyorRequest := #xInReceiveReady AND NOT #stInOutHMI.stControl.xLockSeparator; //Bedingung von Außen erfüllt -> Conv anfordern
	                
	                #xCorrectionDone := FALSE;
	                //Transition
	                
	                IF #xInConveyorRun AND #xInReceiveReady AND #tTrolley.xDbncdSensor AND NOT #stInOutHMI.stControl.xLockSeparator THEN
	                    #nState := #c120_StepOpen;
	                ELSIF NOT #tTrolley.xDirectSensor THEN
	                    #nState := #c100_StepWaitForTrolley;
	                END_IF;
	                
	(*                //Transition
	                //Separator Pinband
	                IF #xInPinSort AND #xInConveyorRun AND NOT #xInScanDone AND #fbStateManager.tOutTimeInStep > T#80ms AND
	                    #tTrolley.xDirectSensor THEN
	                    #nState := #cStepOpen1;
	                    // ELSIF #xInPinSort AND #xInConveyorRun AND #xInScanWrongLeg AND
	                    //     #tTrolley.xDirectSensor THEN
	                    //     #nState := #cStepOpen2Correction";
	                //Normal
	                ELSIF (#xInConveyorRun AND
	                    ((#xInPluggedScan AND #xInScanDone) OR NOT #xInPluggedScan) AND
	                    ((#xInPluggedZappl AND #xInZappl) OR NOT #xInPluggedZappl) AND
	                    #xInReceiveReady AND
	                    
	                    ((#tTrolley.xDbncdSensor AND NOT #xInPluggedScan) OR
	                    (#tTrolley.xDirectSensor AND #xInPluggedScan)) AND    //Freigabe               
	                    
	                    NOT #stInOutHMI.stControl.xLockSeparator) // Keine HMI-Sperre
	                    OR (#stInOutHMI.stControl.xReleaseOverride AND #tTrolley.xDbncdSensor) // HMI Override
	                THEN
	                    #nState := #cStepOpen1;
	                //Fehlerhafte Lesung erkannt    
	                ELSIF (#xInConveyorRun AND
	                    #xInPluggedScan AND #xInScanWrongLeg AND
	                    #xInReceiveReady AND
	                    #tTrolley.xDirectSensor AND    //Freigabe               
	                    
	                    NOT #stInOutHMI.stControl.xLockSeparator) // Keine HMI-Sperre
	                    OR (#stInOutHMI.stControl.xReleaseOverride AND #tTrolley.xDbncdSensor) // HMI Override
	                THEN
	                    #nState := #cStepOpen2Correction;
	                    // ??????????????????????????????? Kein Receive?!
	             (*   ELSIF (NOT #xInPluggedScan AND
	                    NOT #xInPluggedZappl AND
	                    #tTrolley.xDbncdSensor AND    //Freigabe               
	                    
	                    NOT #stInOutHMI.stControl.xLockSeparator) // Keine HMI-Sperre
	                    OR (#stInOutHMI.stControl.xReleaseOverride AND #tTrolley.xDbncdSensor) // HMI Override
	                THEN
	                    #nState := #cStepOpen1; *)
	                // Trolley nicht mehr da     
	                ELSIF NOT #tTrolley.xDirectSensor THEN
	                    #nState := #cStepWaitForTrolley1;
	                END_IF; *)
	            END_REGION
	            
	        #c120_StepOpen:
	            REGION Step 120 - separator open
	                // akt. Zustand
	                #stOutMainTro.nStatus := "SepState_Open";
	                
	                //Outputs
	                #xOutConveyorRequest := TRUE;               // motor on
	                #xOutStopper := TRUE;                       // stopper open
	                #xOutTrolleyInSep := FALSE;
	                
	                //Überwachung
	                #t_Monitoring := #xInConveyorRun;
	                IF #tOnMonitoring.Q THEN
	                    #wOutErrorWord.%X1 := TRUE;             // err trolley stuck
	                END_IF;
	                
	                // Transition
	                IF NOT #tTrolley.xDbncdSensor THEN
	                    #nState := #c130_StepWaitForLeave;
	                ELSIF #tOnMonitoring.Q AND #stInSettings.xStuckCorrection AND NOT #xCorrectionDone THEN
	                    #nState := 121;
	                END_IF;
	                
	                (* //Transition
	                //Korrektur
	                IF #xInPinSort AND #xInScanWrongLeg THEN
	                    #nState := #cStepOpen2Correction;
	                //Mit Scanner
	                ELSIF #xInPluggedScan AND NOT #tTrolley.xDirectSensor THEN
	                    (* #xInConveyorRun AND    *)                 // motor on?
	                    #xOutStopper := FALSE;
	                    #nState := #cStepWaitForRelease2;
	                    #xOutFirstLegReleasedEdge := TRUE;
	                // Ohne Scanner
	                ELSIF NOT #xInPluggedScan AND
	                    NOT #tTrolley.xDbncdSensor                  // trolley running out?
	                THEN
	                    #nState := #cStepWaitForLeave1;
	                END_IF; *)
	            END_REGION
	            
	        121:
	            // akt. Zustand
	            #stOutMainTro.nStatus := "SepState_Open";
	            
	            //Outputs
	            #xOutConveyorRequest := TRUE;               // motor on
	            #xOutStopper := FALSE;                       // stopper open
	            #xOutTrolleyInSep := FALSE;
	            
	            #xCorrectionDone := TRUE;
	            
	            IF #fbStateManager.tOutTimeInStep > t#500ms THEN
	                #nState := #c120_StepOpen;
	            END_IF;
	        #c130_StepWaitForLeave:
	            REGION Step 130 - wait trolley exit
	                // akt. Zustand
	                #stOutMainTro.nStatus := "SepState_WaitForLeaveFirst";
	                
	                //Outputs
	                #xOutConveyorRequest := TRUE;               // motor on
	                #xOutStopper := TRUE;                       // stopper open
	                #t_Trailing := #xInConveyorRun AND NOT #tTrolley.xDirectSensor; // Zeit neu aufziehen wenn Sensor frei wird
	                
	                #xCorrectionDone := FALSE;
	                // Transition
	                IF #tOnTrailing.Q THEN
	                    #nState := #c140_StepClose1;
	                    #xOutTrolleyReleasedEdge := TRUE;
	                END_IF;
	            END_REGION
	        #c140_StepClose1:
	            REGION Step 140 - separator close
	                // akt. Zustand
	                #stOutMainTro.nStatus := "SepState_Finish";
	                
	                #xCorrectionDone := FALSE;
	                //Outputs
	                #xOutTrolleyReleasedEdge := FALSE;           // Datenübergabe
	                #xOutStopper := FALSE;                      // Separator ZU
	                #t_Handling := #xInConveyorRun;
	                
	                //Transition
	                #nState := #c100_StepWaitForTrolley;
	                
	            END_REGION
	(*        #cStepWaitForTrolley2:
	            REGION Step 200 - wait for trolley second 
	                // akt. Zustand
	                #stOutMainTro.nStatus := "SepState_WaitForSecondLeg";
	                
	                //Outputs
	                #xOutStopper := FALSE;                      // Separator ZU
	                #xOutTrolleyReleasedEdge := FALSE;          // Datenübergabe
	                #xOutFirstLegReleasedEdge := FALSE;
	                #xOutConveyorRequest := FALSE;    // 
	                #xOutTrolleyRequest := TRUE;
	                #xOutTrolleyScanRdy := FALSE;
	                
	                // Transition
	                // MT 2.Bein kommt nicht..
	                IF #fbStateManager.tOutTimeInStep > T#3s AND #xInConveyorRun AND
	                    NOT #xInPluggedScan THEN
	                    #nState := #cStepWaitForTrolley1;
	                END_IF;
	                
	                //Normal
	                IF
	                    #tTrolley.xDirectSensor                  // Trolley im Separator
	                THEN
	                    #nState := #cStepWaitForRelease2;
	                END_IF;
	            END_REGION
	        #cStepWaitForRelease2:
	            REGION Step 210 - wait release request second 
	                // akt. Zustand
	                #stOutMainTro.nStatus := "SepState_WaitForReqSecond";
	                
	                //Outputs
	                #xOutStopper := FALSE;                      // Separator ZU
	                #xOutTrolleyRequest := FALSE;
	                #xOutTrolleyInSep := (#xInPinSort AND #tTrolley.xDirectSensor) OR (NOT #xInPinSort AND #tTrolley.xDbncdSensor);
	                #xOutConveyorRequest := #xInReceiveReady AND NOT #stInOutHMI.stControl.xLockSeparator; //Bedingung von Außen erfüllt -> Conv anfordern
	                #xOutTrolleyScanRdy := #xInPluggedScan (* AND #xInScanDone *);
	                
	                //Transition
	                
	                // IF (#xInConveyorRun AND
	                //     ((#xInPinSort AND #xInScanWrongLeg) OR (#xInPinSort AND #xInScanDone)) AND
	                //     ((#xInPluggedZappl AND #xInZappl) OR NOT #xInPluggedZappl) AND
	                //     #xInReceiveReady AND
	                
	                //     ((#tTrolley.xDbncdSensor AND NOT #xInPluggedScan) OR
	                //     (#tTrolley.xDirectSensor AND #xInPluggedScan)) AND    //Freigabe               
	                
	                //     NOT #stInOutHMI.stControl.xLockSeparator) // Keine HMI-Sperre
	                //     OR (#stInOutHMI.stControl.xReleaseOverride AND #tTrolley.xDbncdSensor) // HMI Override
	                // THEN
	                //     #nState := #cStepOpen2Correction;
	                IF (#xInConveyorRun AND
	                    ((#xInPluggedScan (* AND #xInScanDone *)) OR NOT #xInPluggedScan) AND
	                    ((#xInPluggedZappl AND #xInZappl) OR NOT #xInPluggedZappl) AND
	                    #xInReceiveReady AND
	                    
	                    ((#tTrolley.xDbncdSensor AND NOT #xInPluggedScan) OR
	                    (#tTrolley.xDirectSensor AND #xInPluggedScan)) AND    //Freigabe               
	                    
	                    NOT #stInOutHMI.stControl.xLockSeparator) // Keine HMI-Sperre
	                    OR (#stInOutHMI.stControl.xReleaseOverride AND #tTrolley.xDbncdSensor) // HMI Override
	                THEN
	                    #nState := #cStepOpen2;
	                ELSIF NOT #tTrolley.xDirectSensor THEN
	                    #nState := #cStepWaitForTrolley2;
	                END_IF;
	            END_REGION
	        #cStepOpen2:
	            REGION Step 220 - separator open second
	                // akt. Zustand
	                #stOutMainTro.nStatus := "SepState_OpenSecond";
	                
	                // Outputs
	                #xOutConveyorRequest := TRUE;               // motor on
	                #xOutStopper := TRUE;                       // stopper open
	                #xOutTrolleyInSep := FALSE;
	                #xOutTrolleyScanRdy := FALSE;
	                
	                #t_Monitoring := #xInConveyorRun;
	                IF #tOnMonitoring.Q THEN
	                    #wErrorWord.%X1 := TRUE;             // err trolley stuck
	                END_IF;
	                
	                // Transition
	                // Mit Scanner
	                IF #xInPluggedScan AND NOT #tTrolley.xDirectSensor THEN
	                    #xOutStopper := FALSE;
	                    #nState := #cStepWaitForTrolley1;
	                    #xOutTrolleyReleasedEdge := TRUE;           // Datenübergabe
	                // Ohne Scanner
	                ELSIF NOT #xInPluggedScan AND
	                    (* #xInConveyorRun AND *)                     // monor on?
	                    NOT #tTrolley.xDbncdSensor                  // trolley running out?
	                THEN
	                    #nState := #cStepWaitForLeave2;
	                END_IF;
	            END_REGION
	        #cStepOpen2Correction:
	            REGION Step 225 - separator open second without Data
	                // akt. Zustand
	                #stOutMainTro.nStatus := "SepState_OpenSecondCorrection";
	                
	                // Outputs
	                #xOutConveyorRequest := TRUE;               // motor on
	                #xOutStopper := TRUE;                       // stopper open
	                #xOutTrolleyInSep := FALSE;
	                #xOutTrolleyScanRdy := FALSE;
	                
	                #t_Monitoring := #xInConveyorRun;
	                IF #tOnMonitoring.Q THEN
	                    #wErrorWord.%X1 := TRUE;             // err trolley stuck
	                END_IF;
	                
	                // Transition
	                IF #xInPluggedScan AND NOT #tTrolley.xDirectSensor THEN
	                    #xOutStopper := FALSE;
	                    #nState := #cStepWaitForTrolley1;
	                END_IF;
	            END_REGION
	        #cStepWaitForLeave2:
	            REGION Step 230 - wait trolley exit second
	                // akt. Zustand
	                #stOutMainTro.nStatus := "SepState_WaitForLeaveSecond";
	                
	                // Output
	                #xOutConveyorRequest := TRUE;               // motor on
	                #xOutStopper := TRUE;                       // stopper open
	                #t_Trailing := TRUE(* #xInConveyorRun *);
	                
	                // Transition
	                IF #tOnTrailing.Q THEN //....ansonsten schließe normal nach Trailing-Zeit 
	                    #nState := #cStepClose2;
	                    #xOutTrolleyReleasedEdge := TRUE;           // Datenübergabe
	                END_IF;
	                
	            END_REGION
	        #cStepClose2:
	            REGION Step 240 - separator close second
	                // akt. Zustand
	                #stOutMainTro.nStatus := "SepState_Finish";
	                
	                // Outputs
	                #xOutTrolleyReleasedEdge := FALSE;
	                #xOutStopper := FALSE;                      // Separator ZU
	                #t_Handling := TRUE;(* #xInConveyorRun *)
	                
	                // Transition
	                //WENN HIER BEARBEITUNGSZEIT EINGEFÜGT WIRD MUSS DER COUNTER UNTEN MIT FLANKE VERSORGT WERDEN
	                IF
	                    #tOnHandling.Q
	                THEN
	                    #nState := #cStepWaitForTrolley1;
	                END_IF;
	            END_REGION *)
	        ELSE
	            #wErrorWord.%X0 := true;                     // stepp error
	    END_CASE;
	    
	    REGION State Manager
	        #fbStateManager.stInSettings.nStartState := #c100_StepWaitForTrolley;
	        #fbStateManager.stInSettings.xActUnivTOn := TRUE;
	        #fbStateManager.stInSettings.xRestartAtStartState := FALSE;
	        #fbStateManager(xInFunctionEnabled := TRUE,
	                        xInRunUnivTOn := #tmpActUnivTon,
	                        nInOutState := #nState);
	    END_REGION
	    
	END_REGION
	
	REGION Counter
	    // #CountCarr(CU:=#nState = 040 AND NOT #xOutStopper,
	    //            PV:=1,
	    //            CV=>#nCount);
	END_REGION
	
	REGION Monitoring
	    REGION Carrier stuck
	        #fbMonitoringCarrStuck.stSettings.nErrorType := 1;
	        #fbMonitoringCarrStuck.stSettings.xErrLedIfMachineIsOff := TRUE;
	        #fbMonitoringCarrStuck.stSettings.xSelfQuit := TRUE;
	        #fbMonitoringCarrStuck(sInFctnName := #stInOutHMI.stConfig.sName,
	                               sInPrefix := 'Ausfahren Carrier',
	                               sInSuffix := #stInOutHMI.stConfig.sName,
	                               wInTextListId_Function := 200,
	                               wInTextListId_Message := 201,
	                               InOutMachineState := #stInOutMainState,
	                               xInQuitError := #xInErrQuit OR #stInOutMainState.xQuitError,
	                               xInSignal := NOT #tOnMonitoring.Q,
	                               sInAlarmMessage := 'Carrier verlaesst Separator nicht');
	    END_REGION
	    
	    REGION Carrier Mismatch
	        #fbMonitoringCarrMismatch.stSettings.nErrorType := 1;
	        #fbMonitoringCarrMismatch.stSettings.xErrLedIfMachineIsOff := TRUE;
	        #fbMonitoringCarrMismatch.stSettings.xSelfQuit := TRUE;
	        #fbMonitoringCarrMismatch(sInFctnName := #stInOutHMI.stConfig.sName,
	                                  sInPrefix := 'Carrier Mismatch',
	                                  InOutMachineState := #stInOutMainState,
	                                  xInQuitError := #xInErrQuit OR #stInOutMainState.xQuitError,
	                                  xInSignal := TRUE, //NOT #wOutErrorWord.%X2,
	                                  sInAlarmMessage := 'Carrier im Separator ist falsch');
	    END_REGION
	END_REGION
	
	REGION Timer
	    
	    #tOnHandling(IN := #t_Handling,
	                 PT := #stInSettings.tHandlingTime);
	    
	    #tOnTrailing(IN := #t_Trailing,
	                 PT := #stInSettings.tTrailingTime);
	    
	    #tOnMonitoring(IN := #t_Monitoring,
	                   PT := t#4999ms,
	                   Q => #wErrorWord.%X1);
	END_REGION
	
	REGION HMI
	    
	    #stInOutHMI.InSensor := #tTrolley;
	    
	    REGION Status
	        #stInOutHMI.stStatus.nState := #nState;
	        #stInOutHMI.stStatus.xSepStatus := #xOutStopper;
	        
	        IF #wErrorWord > 0 THEN // Keine Fehler 
	            #stInOutHMI.stStatus.bStatus := 2; // ERROR
	        ELSIF #stInOutHMI.stControl.xLockSeparator OR #stInOutHMI.stControl.xReleaseOverride THEN
	            #stInOutHMI.stStatus.bStatus := 3; // HMI Control aktiv
	        ELSE
	            CASE #nState OF
	                0:
	                    #stInOutHMI.stStatus.bStatus := 0; // NOT_AVAILABLE
	                1, 10, 20, 30, 40, 101, 110, 120, 130, 140:
	                    #stInOutHMI.stStatus.bStatus := 1; // AVAILABLE
	                ELSE  //Fallback
	                    #stInOutHMI.stStatus.bStatus := 0; // NOT AVAILABLE
	            END_CASE;
	        END_IF;
	        
	        #stInOutHMI.stStatus.xBtInSeparator := #tTrolley.xDbncdSensor;
	        #stInOutHMI.stStatus.xError := #wErrorWord > 0;
	        #stInOutHMI.stStatus.Errors.xBtNotLeaving := #wErrorWord.%X1;
	        // #stInOutHMI.stStatus.nCounterBt := #nCount;
	        #stInOutHMI.stStatus.xSepIsLocked := #stInOutHMI.stControl.xLockSeparator;
	    END_REGION
	    
	END_REGION
	
	REGION MainTRO
	    
	    #stOutMainTro.xJamAtEntry := "cTodoFalse";
	    #stOutMainTro.xBtPresent := #tTrolley.xDbncdSensor;
	    #stOutMainTro.xCarouselInRun := #xInConveyorRun;
	    //  #stOutMainTro.nCounterBt := 0; TODO
	    
	END_REGION
	
	
	REGION Outputs
	    #wOutErrorWord := #wErrorWord;
	END_REGION
END_FUNCTION_BLOCK

