FUNCTION_BLOCK "FB_ILS_MTRO_2Sep1Swi"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT 
      stInSettings : Struct
         nTroStopper1 : Int;
         nTroStopper2 : Int;
         nTroSwitchExit2 : Int;
         nTroSwitchExit3 : Int;
         xCar2NecRight : Bool;   // 2. Kreisel ist notwendig für Richtung rechts
         xCar2NecLeft : Bool;   // 2. Kreisel ist notwendig für Richtung links
         xPrioDir1 : Bool;   // Für diese Direction ist Prio Funktion relevant
         xPrioDir2 : Bool;   // Für diese Direction ist Prio Funktion relevant
         xPrioDir3 : Bool;
         xPrioDir4 : Bool;
         bSep1Type : Byte := 16#0;   // X0: TRUE - erstes Bein halten, X1: TRUE- Beladekontrolle, X2: TRUE - Beladeerfassung
         bSep2Type : Byte := 16#0;   // X0: TRUE - erstes Bein halten, X1: TRUE- Beladekontrolle, X2: TRUE - Beladeerfassung
         tPartSenHigh : Time := T#500ms;
         tInSenHigh : Time := T#500ms;
         xIsBorner1 : Bool;   // Hiermit  werden Dummys mit Barcode 1000-2000 angelegt
         xIsBorner2 : Bool;   // Hiermit  werden Dummys mit Barcode 1000-2000 angelegt
         nBornerDest1 : Int;   // Standard Destination festlegen für Borner (variabel)
         nBornerDest2 : Int;   // Standard Destination festlegen für Borner (variabel)
         tDummyTimeNormal : Time := T#3s;   // Zeit für Dummy anlegen (Dummy = 1)
         tDummyTimeBorner : Time := T#0ms;   // Zeit für Dummy anlegen (Dummy = 1000-2000) schneller...
      END_STRUCT;
      stInSeparator1 : Struct
         stSenInSep : "UDT_Sensor";   // Sensor in Stopper
         stSenSepLeft : "UDT_Sensor";   // Sensor nach Stopper
         stSenPart : "UDT_Sensor";   // Checkt, ob der Bügelträger beladen ist
         stSenStartScan : "UDT_Sensor";   // Sensor nach Stopper wenn Scanner vorhanden. Vermutlich startet dieser Sensor den Scanner
         Settings : "SettingsSeparator";
      END_STRUCT;
      stInSeparator2 : Struct
         stSenInSep : "UDT_Sensor";   // Sensor in Stopper
         stSenSepLeft : "UDT_Sensor";   // Sensor nach Stopper
         stSenPart : "UDT_Sensor";   // Checkt, ob der Bügelträger beladen ist
         stSenStartScan : "UDT_Sensor";   // Sensor nach Stopper wenn Scanner vorhanden. Vermutlich startet dieser Sensor den Scanner
         Settings : "SettingsSeparator";
      END_STRUCT;
      stInSwitch1 : Struct
         stSenExit3 : "UDT_Sensor";
         stSenExit4 : "UDT_Sensor";
         Settings : "SettingsSwitch";
      END_STRUCT;
      stInBarcodeReader1 : Struct
         Settings : "UDT_SettingsBarcodeReader";
      END_STRUCT;
      stInBarcodeReader2 : Struct
         Settings : "UDT_SettingsBarcodeReader";
      END_STRUCT;
      stInPriorityManagerDir1 : "UDT_Response";   // Schnittstelle Prioritätenmanager (z.B. bei Kreuzungen)
      stInPriorityManagerDir2 : "UDT_Response";
      stInPriorityManagerDir3 : "UDT_Response";
      stInPriorityManagerDir4 : "UDT_Response";
      stInSenJam2 : "UDT_Sensor";   // Stausensor Exit 2
      stInSenJam3 : "UDT_Sensor";   // Stausensor Exit 3
      nInMainTroNo : UInt;
      xInSftyOk : Bool;
      xInAllRdyToStart : Bool;
      xInJamAtExit2 : Bool;   // NIU Stau Exit 2
      xInJamAtExit3 : Bool;   // NIU Stau Exit 3
      xInCarouselRun1 : Bool;   // Rückmeldesignal von Carousel1: Motor läuft
      xInCarouselRun2 : Bool;   // Rückmeldesignal von Carousel2: Motor läuft
      xInTestMode : Bool;
      xInCancel : Bool;
      xInAreaStopActive : Bool;   // Bereichshalt
      xInRelease : Bool;   // Freigabe/Anforderung
      nInDirection : USInt;
   END_VAR

   VAR_OUTPUT 
      xOutStopper1 : Bool;
      xOutStopper2 : Bool;
      xOutSw1EntrTo1 : Bool;   // Weiche auf Eingang 1 stellen
      xOutSw1EntrTo2 : Bool;   // Weiche auf Eingang 2 stellen
      xOutSw1ExTo3 : Bool;   // Weiche auf Ausgang 3 stellen
      xOutSw1ExTo4 : Bool;   // Weiche auf Ausgang 4 stellen
      xOutJamAtEntry1 : Bool;
      xOutJamAtEntry2 : Bool;
      xOutCarouselReq1 : Bool;   // Motor 1 anfordern
      xOutCarouselReq2 : Bool;   // Motor 2 anfordern
      xOutCorrection : Bool;
      nOutStateLast : Int;
      stOutPriorityManagerDir1 : "UDT_Request";
      stOutPriorityManagerDir2 : "UDT_Request";
      stOutPriorityManagerDir3 : "UDT_Request";
      stOutPriorityManagerDir4 : "UDT_Request";
      xOutBookedDir1 : Bool;
      xOutBookedDir2 : Bool;
      xOutBookedDir3 : Bool;
      xOutBookedDir4 : Bool;
      stOutLastCarrier : "stCarrier";
      nOutScanResult : DInt;
      xOutNewScan : Bool;
   END_VAR

   VAR_IN_OUT 
      stInOutMachineState : "UDT_MainState";
      stInOutCognexInterface1 : "stCognexInterface";
      stInOutCognexInterface2 : "stCognexInterface";
      arInOutJamEntr1 : Array[*] of "stCarrier";   // Daten Staubereich Eingang 1
      stInOutJamEntr1 : "stJamData";
      arInOutJamEntr2 : Array[*] of "stCarrier";   // Daten Staubereich Eingang 2
      stInOutJamEntr2 : "stJamData";
      arInOutJamExit2 : Array[*] of "stCarrier";   // Daten Staubereich Ausgang 2
      stInOutJamExit2 : "stJamData";
      arInOutJamExit3 : Array[*] of "stCarrier";   // Daten Staubereich Ausgang 3
      stInOutJamExit3 : "stJamData";
      stInOutHMI : "UDT_HMI_TRO";
   END_VAR

   VAR 
      fbStateManager { S7_SetPoint := 'False'} : "FB_StateManager";
      fbSeparator1 { S7_SetPoint := 'False'} : "FB_ILS_STRO_Sep";
      fbSeparator2 : "FB_ILS_STRO_Sep";
      fbSwitch1 { S7_SetPoint := 'False'} : "FB_ILS_STRO_Switch";
      fbBarcodeReader1 { S7_SetPoint := 'False'} : "FB_BarcodeReaderCognex";   // Instanz Barcode-Reader1
      fbBarcodeReader2 : "FB_BarcodeReaderCognex";   // Instanz Barcode-Reader2
   END_VAR
   VAR RETAIN
      stActRequest : Struct
         xNBT : Bool;   // Es handelt sich um einen Nullbügelträger
         xCancelled : Bool;   // Abbruchanforderung durch MFR
         xDirectionChange : Bool;
         nActReqIndex : USInt;   // 0 = nichts zu tun | 1-200: Aktuell bearbeiteter Index
         nActArrIndex : USInt;
         nDirection : USInt;   // 0: Es bleibt hier alles so wie es ist! | 1: E1->A3 | 2: E1->A4 | 3: E2->A3 | 4: E2->A4
         nLastDirection : USInt;
         nRequestedNoBT : USInt;   // Anzahl Trolleys die ausgefahren werden sollen
         nReasonForStop : USInt;   // 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
         nActNoStopper : USInt;   // Anzahl der Stopper-öffnungen in diesem Auftrag
         nActNoInSwitch : USInt;   // Anzahl BT die sich noch in Weiche befinden müssten
         nActNoInSwitchLast : USInt;
         xLongSignal : Bool;
      END_STRUCT;
      nState : Int;
   END_VAR
   VAR 
      sStateText : String["cStateText"];   // Aktueller State der Schrittkette (textuell)
   END_VAR
   VAR RETAIN
      nSetSwitch1 : USInt;   // 0: Es bleibt hier alles so wie es ist! | 1: E1->A2 | 2: E1->A3
      xReleaseTrolleySep1 : Bool;   // Öffne-Befehl
      xReleaseTrolleySep2 : Bool;
      xErrorMotor : Bool;   // Fehler weil Motor-Run fehlt
      xMTRORdy { S7_SetPoint := 'True'} : Bool;   // MainTRO ist bereit für neue Aufträge (Signal an JobManager)
      xWrongDirDetect : Bool;   // Wrong Dir wurde erkannt
   END_VAR
   VAR 
      tOnSvReleaseSep1 {InstructionName := 'TON_TIME'; LibVersion := '1.0'; S7_SetPoint := 'False'} : TON_TIME;   // Supervision - Freigabe Separator1
      tOnSvReleaseSep2 {InstructionName := 'TON_TIME'; LibVersion := '1.0'} : TON_TIME;   // Supervision - Freigabe Separator2
      xStartScan : Bool;
      xHandshakeScan : Bool;
      nBarcodeResult : DInt;
      nBarcodeHelp : DInt;
      sBarcodeString : String;
      xCodeEven : Bool;
      xTrolleyWithPart1 : Bool;
      xTrolleyWithPart2 : Bool;
      xTrolleyWoPart1 : Bool;
      xTrolleyWoPart2 : Bool;
      xReadSecondLeg : Bool;
      wErrorWord1 : Word;
      wErrorWord2 : Word;
      nLastDirection : USInt;
      tOnSwitchDelay {InstructionName := 'TON_TIME'; LibVersion := '1.0'} : TON_TIME;
      stCarrierDummy { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'; S7_SetPoint := 'False'} : "stCarrier" := (1, (), 16#01);
      nArrayMax1 : Int;
      nArrayMax2 : Int;
      nBarcodeEmpty1 : Int := 0;
      nBarcodeEmpty2 : Int;
      tOnMonCarrArrive1 {InstructionName := 'TON_TIME'; LibVersion := '1.0'} : TON_TIME;   // Überwachungszeit zwischen Carrier Online & Separator Sensor Belegung
      tOnMonCarrArrive2 {InstructionName := 'TON_TIME'; LibVersion := '1.0'} : TON_TIME;
      fbMonitoringCarrNotArrive1 : "FB_Monitoring";
      fbMonitoringCarrNotArrive2 : "FB_Monitoring";
      fbMonitoringCarrWoData1 : "FB_Monitoring";
      fbMonitoringCarrWoData2 : "FB_Monitoring";
   END_VAR

   VAR_TEMP 
      nIndex : USInt;
      tmpActUnivTon : Bool;
      tmpReqFinished : Bool;   // Temp Signal für Switch
      xBtEmpty : Bool;
      xCarouselRun : 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
      stEmptyCarrier : "stCarrier";
      stBookingInfo : "stEventBookingInfo";
      arEmptyCarrier : Array[1..1] of "stCarrier";   // Platzhalter für CarrierArray
      xGoodRead : Bool;
      stEventGoodRead : "stEventScanInfo";
      arEventCorrectionInfo : Array[0..1] of "stEventCorrectionInfo";
      stEventNew : "stEventScanInfo";
      stEventUnknown : "stEventScanInfo";
      xTemp : Bool;
      xNewCarrier : Bool;
      xUnknownCarrier : Bool;
      xTmpCorrection : Bool;
      xStartSwitchDelay : Bool;
      xBookedDir1 : Bool;
      xBookedDir2 : Bool;
      xBookedDir3 : Bool;
      xBookedDir4 : Bool;
      stTempCarrier : "stCarrier";
      tmpCarrierEmpty : "stCarrier";
   END_VAR

   VAR CONSTANT 
      "2SEP1SWITCH" : USInt := 3;
      c0000_StepOff : Int := 0;   // Schrittkette aus
      c0100_StepUndefined : Int := 100;   // Schrittkette undefiniert / Init
      c1000_StepWaitForTrolley1 : Int := 1000;   // Warte auf Trolley 1
      c1100_StepScannerTrig1 : Int := 1100;   // Scanner Triggern 
      c1200_StepScannerEval1 : Int := 1200;   // Scanergebnis auswerten 
      c1300_StepCheckLoad : Int := 1300;   // Beladung prüfen
      c1400_StepCheckSep1 : Int := 1400;   // Separator checken
      c1500_StepReleaseSep1 : Int := 1500;   // Freigabe an Separator
      c2000_StepWaitForTrolley2 : Int := 2000;   // Warte auf Trolley 2
      c2100_StepScannerTrig2 : Int := 2100;   // Scanner Triggern (nur wenn 1.Achse kein Ergebnis)
      c2200_StepScannerEval2 : Int := 2200;   // Scanergebnis auswerten (nur wenn 1.Achse kein Ergebnis)
      c2250_StepCheckDir : Int := 2250;
      c2225_StepGetDir : Int := 2225;
      c2300_StepCheckSep2 : Int := 2300;   // Separator checken
      c2350_StepCheckSwi : Int := 2350;
      c2400_StepCheckJam : Int := 2400;   // Stau überprüfen
      c2500_StepReleaseSep2 : Int := 2500;   // Freigabe an Separator
      cCarrierDummy : Int := 1;
      cCarrierUnknown : Int := 2;
   END_VAR


BEGIN
	// (* Company: Schönenberger Systeme GmbH / (C) Copyright (2025). All rights reserved.
	// -----------------------------------------------------------------------------------------
	// Title: FB_MTRO_1Sep1Swi
	// Comment/Function: MainTRO-Function block for controlling TRO with 1x Sep and 1x Switch 
	// Library/Family: "MainTRO"
	// Author: department: "Automatisierung" ; person in charge / contact: E.Yüksel, T. Molina, T.Schiller
	// Target System: CPU 1518F-4 PN/DP
	// Engineering: TIA Portal V20
	// Restrictions: -
	// Requirements: (hardware, technological package, etc.)
	// -----------------------------------------------------------------------------------------
	// Change log table:
	// Version     | Date       | Signature (Safety) | Expert in charge | Changes applied
	// ------------|------------|--------------------|------------------|-----------------------
	// 001.000.000 | 2022-12-15 | -                  | Yüksel, Molina   | Header added on 15.12.2022
	// 002.000.000 | 2025-02-11 | -                  | Yüksel           | Adapt to ILS with Minitrolley, without external MFR
	//                                                                    
	// *)
	
	// REGION Zweiten Motor einbinden
	//     IF #stInSettings.xCar2NecLeft AND
	//         (#stActRequest.nDirection = 1 OR #stActRequest.nDirection = 3) THEN
	//         #xCarouselRun := #xInCarouselRun1 AND #xInCarouselRun2; //Nach links wird 2. Motor gebraucht und aktuelle Richtung ist LINKS
	//     ELSIF #stInSettings.xCar2NecLeft AND
	//         (#stActRequest.nDirection = 2 OR #stActRequest.nDirection = 4) THEN
	//         #xCarouselRun := #xInCarouselRun1; //Nach links wird 2. Motor gebraucht und aktuelle Richtung ist RECHTS
	//     ELSIF #stInSettings.xCar2NecRight AND
	//         (#stActRequest.nDirection = 1 OR #stActRequest.nDirection = 3) THEN
	//         #xCarouselRun := #xInCarouselRun1; //Nach rechts wird 2. Motor gebraucht und aktuelle Richtung ist LINKS
	//     ELSIF #stInSettings.xCar2NecRight AND
	//         (#stActRequest.nDirection = 2 OR #stActRequest.nDirection = 4) THEN
	//         #xCarouselRun := #xInCarouselRun1 AND #xInCarouselRun2; //Nach rechts wird 2. Motor gebraucht und aktuelle Richtung ist RECHTS
	//     ELSE
	//         #xCarouselRun := #xInCarouselRun1; //normal
	//     END_IF;
	// END_REGION
	
	// REGION Schrittkette
	//     REGION !!!IN ARBEIT - NUR VORBEREITET!!!!!
	//         (*
	// Um Schrittkette herum alles für 2 Seps erweitert, also ganz simpel 1Sep1Swi genommen und alles für den zweiten kopiert, Schrittkette noch nicht gemacht.
	// Prinzip lässt sich so aber nicht ohne weiteres umsetzen
	// *)
	        
	//     END_REGION
	    
	//     CASE #nState OF
	         
	//         #c0000_StepOff:
	//             REGION 0000: Off
	//                 //akt. Zustand
	//                 #sStateText := 'OFF';
	//                 ///////// Ausgänge /////////
	                
	//                 ///////// Statics //////////
	//                 #xReleaseTrolleySep1 := FALSE;
	//                 #xReleaseTrolleySep2 := FALSE;
	//                 #nSetSwitch1 := 0;
	//                 #xOutNewScan := FALSE;
	//                 /////////  Timer  //////////
	                
	//                 //////// Transition ////////
	                
	//             END_REGION
	            
	//         #c0100_StepUndefined:
	            
	//             REGION 0100: Undefined
	//                 // akt. Zustand
	//                 #sStateText := 'Undefined';
	//                 ///////// Ausgänge /////////
	                
	//                 ///////// Statics //////////
	//                 #xReleaseTrolleySep1 := FALSE;
	//                 #xReleaseTrolleySep2 := FALSE;
	//                 #nSetSwitch1 := 0;
	//                 #xMTRORdy := FALSE;
	//                 #xCodeEven := FALSE;
	                
	//                 /////////  Timer  //////////
	                
	//                 //////// Transition ////////
	                
	//                 #nState := #c1000_StepWaitForTrolley1;
	                
	//             END_REGION
	            
	//         #c1000_StepWaitForTrolley1:
	//             REGION 1000: Wait for Trolley
	//                 //akt. Zustand
	//                 #sStateText := 'Wait for Trolley';
	//                 ///////// Ausgänge /////////
	                
	//                 ///////// Statics //////////
	                
	//                 #xReleaseTrolleySep1 := FALSE;
	//                 #xReleaseTrolleySep2 := FALSE;
	//                 #xCodeEven := FALSE;
	//                 #xMTRORdy := TRUE;
	//                 #xOutNewScan := FALSE;
	                
	//                 //Transition
	//                 IF NOT #stInOutHMI.UDT_Ctrl.xPause THEN
	//                     IF #fbSeparator1.stOutMainTro.xBtPresent THEN //Separator meldet Belegung
	//                         IF #stInSeparator1.Settings.xPluggedScanner THEN //Scanner verbaut?
	//                             #nState := #c1100_StepScannerTrig1; //Nächster Schritt -> Scannen
	//                         ELSIF #arInOutJamEntr1[1].bStatus.%X0 THEN // Kein Scanner verbaut, aber Carrier online (z.B. Dummy wurde angelegt)
	//                             IF #stInSeparator1.Settings.xPluggedPart THEN
	//                                 #nState := #c1300_StepCheckLoad; // Nächster Schritt -> Beladung prüfen
	//                             ELSE
	//                                 #nState := #c1400_StepCheckSep1; //Nächster Schritt -> Separator chekcen
	//                             END_IF;
	//                         END_IF;
	//                     END_IF;
	//                 END_IF;
	                
	//             END_REGION
	            
	//         #c1100_StepScannerTrig1:
	//             REGION 1100: Scanner Trigger 1
	                
	//                 // akt. Zustand
	//                 #sStateText := 'Scanner Trigger 1';
	                
	//                 ///////// Ausgänge /////////
	                
	//                 ///////// Statics //////////
	//                 #xReleaseTrolleySep1 := FALSE;
	                
	//                 IF #fbBarcodeReader1.xOutReadyForNewScan THEN //Scanner bereit
	//                     #xStartScan := TRUE; //Startbefehl 
	//                 END_IF;
	                
	//                 /////////  Timer  //////////
	                
	//                 //////// Transition ////////
	                
	//                 IF #fbBarcodeReader1.xOutReadingDone THEN //Scanner Rückmeldung
	//                     #xStartScan := FALSE;
	//                     #nState := #c1200_StepScannerEval1; //Weiter
	//                 END_IF;
	//             END_REGION
	            
	//         #c1200_StepScannerEval1:
	//             REGION 1200: Scanner Evaluation 1
	                
	//                 // akt. Zustand
	//                 #sStateText := 'Scanner Evaluation 1';
	                
	//                 ///////// Ausgänge /////////
	                
	//                 ///////// Statics //////////
	//                 #xReleaseTrolleySep1 := FALSE;
	                
	//                 // Logic - TODO in eigenen FC packen?..
	                
	//                 IF #fbBarcodeReader1.xOutCodeGood THEN
	//                     #nBarcodeResult := LINT_TO_DINT(#fbBarcodeReader1.#nOutBarcode); // Good read vom Barcode reader übernehmen
	                    
	//                     REGION Event log Good read
	//                         #xGoodRead := TRUE; // Trigger
	//                         #stEventGoodRead.nScanType := 4;
	//                         #stEventGoodRead.sBarcode := DELETE(IN := DINT_TO_STRING(#nBarcodeResult), L := 1, P := 1);
	//                         #stEventGoodRead.sReaderId := DELETE(IN := INT_TO_STRING(#stInBarcodeReader1.Settings.#nStation), L := 1, P := 1);
	//                     END_REGION
	                    
	//                     REGION Gerade Zahl erkannt
	//                         IF (((#nBarcodeResult / 10) MOD 100) MOD 2 <> 1) THEN //anderes Ergebnis als 1 bedeutet, (xxxxxYYx) YY=gerade, also hinteres Bein von MiniTrolley
	//                             #xCodeEven := TRUE; //Bit sagt Separator dass hinteres Bein und nicht erstes zur Korrektur in Schrittkette
	//                             // #nBarcodeTarget := #nBarcodeTarget - 10; //Mache danach die gerade Zahl zur ungeraden UPDATE: WEGEN 8. ZIFFER KLAPPT DAS SO NICHT
	//                             #nBarcodeHelp := (#nBarcodeResult / 10) - 1;
	                            
	//                             "FC_Ean8_CheckDigit"(sInDigits := DELETE(IN := DINT_TO_STRING(IN := #nBarcodeHelp), L := 1, P := 1),
	//                                                  sOutBarcode => #sBarcodeString,
	//                                                  nOutBarcode => #nBarcodeResult);
	                            
	//                             //    #sOutBarcode := #sBarcodeString;
	//                         END_IF;
	//                     END_REGION
	                    
	//                 ELSIF #fbBarcodeReader1.#xOutCodeBad THEN
	//                     #nBarcodeResult := #arInOutJamEntr1[1].nBarcode;  //erwarteter Barcode wird aus JamDaten übernommen
	//                 END_IF;
	                
	//                 IF (#nBarcodeResult > 100) AND
	//                     (#nBarcodeResult < 2147483647) AND  // Good Read (2.147.483.647 Maximum von DINT)
	//                     (#arInOutJamEntr1[1].nBarcode = 0 OR #arInOutJamEntr1[1].nBarcode = 1) THEN    //Wenn keine Daten oder ein Dummy erwartet werden   
	                    
	//                     #xTmpCorrection := TRUE;
	//                     // REGION Carr_Glob_Correction
	                    
	                    
	//                     //     "FC_CARR_GLOB_CORRECTION"(xInStart := TRUE, //Führe Korrektur aus
	//                     //                               nInBarcodeScan := #nBarcodeResult,
	//                     //                               nInStation := #stInBarcodeReader.Settings.nStation,
	//                     //                               xOutNotFound => #xTemp,
	//                     //                               arOutEventLogInfo => #arEventCorrectionInfo,
	//                     //                               InOutCarrierExpect := #arInOutJamEntr1[1]);
	//                     // END_REGION
	                    
	                    
	//                     // IF NOT #xTemp THEN
	//                     //     ;
	//                     //     // #stInOutCarrier.stCarrData.nNrOfScans += 1;
	//                     // ELSE
	//                     //     #arInOutJamEntr1[1].nDestination := "cDestNONE"; //neuer Carrier // TODO
	//                     //     //     #stInOutCarrier.stCarrData.nNrOfScans += 1;
	//                     //     #arInOutJamEntr1[1].nBarcode := #nBarcodeResult; //Hier werden neue Carrier im System angelegt
	//                     //     #arInOutJamEntr1[1].bStatus.%X0 := TRUE;
	//                     // END_IF;
	                    
	//                     // REGION Event Log New Carrier
	                    
	//                     //     #xNewCarrier := TRUE; // Trigger
	//                     //     #stEventNew.nScanType := 2;
	//                     //     #stEventNew.sBarcode := DELETE(IN := DINT_TO_STRING(#arInOutJamEntr1[1].nBarcode), L := 1, P := 1);
	//                     //     #stEventNew.sDest := DELETE(IN := INT_TO_STRING(#arInOutJamEntr1[1].nDestination), L := 1, P := 1);
	//                     //     #stEventNew.sReaderId := DELETE(IN := INT_TO_STRING(#stInBarcodeReader.Settings.#nStation), L := 1, P := 1);
	                    
	//                     // END_REGION
	                    
	//                 ELSIF
	//                     (#nBarcodeResult > 100) AND
	//                     (#nBarcodeResult < 2147483647) AND // Good Read (2.147.483.647 Maximum von DINT)
	//                     #arInOutJamEntr1[1].nBarcode = #nBarcodeResult THEN //Barcodes stimmen überein ODER es wird hier gelandet mit BadRead wobei normaler Barcode erwartet wird-> mache normal weiter
	//                     ;
	//                 ELSIF
	//                     (#nBarcodeResult > 100) AND
	//                     (#nBarcodeResult < 2147483647) AND
	//                     #arInOutJamEntr1[1].nBarcode <> #nBarcodeResult AND //Barcodes stimmen nicht überein, erwarteter Carrier enthält aber normalen Barcode
	//                     #arInOutJamEntr1[1].nBarcode <> 0 AND
	//                     #arInOutJamEntr1[1].nBarcode <> 1 THEN
	                    
	//                     #xTmpCorrection := TRUE;
	                    
	//                     // REGION Carr_Glob_Correction
	                    
	//                     //     "FC_CARR_GLOB_CORRECTION"(xInStart := TRUE, //Führe Korrektur aus
	//                     //                               nInBarcodeScan := #nBarcodeResult,
	//                     //                               nInStation := #stInBarcodeReader.Settings.nStation,
	//                     //                               xOutNotFound => #xTemp,
	//                     //                               arOutEventLogInfo => #arEventCorrectionInfo,
	//                     //                               InOutCarrierExpect := #arInOutJamEntr1[1]);
	//                     // END_REGION
	                    
	//                     // IF NOT #xTemp THEN
	//                     //     ;
	//                     //     // #stInOutCarrier.stCarrData.nNrOfScans += 1;
	//                     // ELSE
	//                     //     #arInOutJamEntr1[1].nDestination := "cDestNONE"; //neuer Carrier // TODO
	//                     //     //     #stInOutCarrier.stCarrData.nNrOfScans += 1;
	//                     //     #arInOutJamEntr1[1].nBarcode := #nBarcodeResult; //Hier werden neue Carrier im System angelegt
	//                     //     #arInOutJamEntr1[1].bStatus.%X0 := TRUE;
	//                     // END_IF;
	                    
	//                     // REGION Event Log New Carrier
	                    
	//                     //     #xNewCarrier := TRUE; // Trigger
	//                     //     #stEventNew.nScanType := 2;
	//                     //     #stEventNew.sBarcode := DELETE(IN := DINT_TO_STRING(#arInOutJamEntr1[1].nBarcode), L := 1, P := 1);
	//                     //     #stEventNew.sDest := DELETE(IN := INT_TO_STRING(#arInOutJamEntr1[1].nDestination), L := 1, P := 1);
	//                     //     #stEventNew.sReaderId := DELETE(IN := INT_TO_STRING(#stInBarcodeReader.Settings.#nStation), L := 1, P := 1);
	                    
	//                     // END_REGION
	                    
	                    
	//                 ELSE        // Bad Read, falls nichts oder Dummy erwartet wird -> HANDLING TO DO!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	//                     #arInOutJamEntr1[1].bStatus.%X0 := TRUE;
	//                     #arInOutJamEntr1[1].nBarcode := 2; //unbekannter Carrier mit Badread, erwartet 0 und physikalisch vorhanden
	//                     #arInOutJamEntr1[1].nDestination := 123; //todo
	                    
	//                     REGION Event Log unknown Carrier
	                        
	//                         #xUnknownCarrier := TRUE; // Trigger
	//                         #stEventUnknown.nScanType := 3;
	//                         #stEventUnknown.sBarcode := DELETE(IN := DINT_TO_STRING(#arInOutJamEntr1[1].nBarcode), L := 1, P := 1);
	//                         #stEventUnknown.sDest := DELETE(IN := INT_TO_STRING(#arInOutJamEntr1[1].nDestination), L := 1, P := 1);
	//                         #stEventUnknown.sReaderId := DELETE(IN := INT_TO_STRING(#stInBarcodeReader1.Settings.#nStation + 50), L := 1, P := 1);
	                        
	//                     END_REGION
	                    
	//                 END_IF;
	                
	//                 #xHandshakeScan := TRUE;
	                
	//                 #nOutScanResult := #nBarcodeResult;
	//                 #xOutNewScan := TRUE;
	//                 /////////  Timer  //////////
	                
	//                 //////// Transition ////////
	//                 IF #stInSeparator1.Settings.xPluggedPart AND #stInSettings.bSep1Type.%X2 THEN
	//                     #nState := #c1300_StepCheckLoad;
	//                 ELSIF #xCodeEven THEN
	//                     #xCodeEven := FALSE;
	//                     #nState := #c2000_StepWaitForTrolley2; //Scanner bestätigt zweites Bein gelesen -> Korrigieren!
	//                 ELSE
	//                     #nState := #c1400_StepCheckSep1;
	//                 END_IF;
	                
	//             END_REGION
	            
	//         #c1300_StepCheckLoad:
	//             REGION 1300: Check Load 
	                
	//                 // akt. Zustand
	//                 #sStateText := 'Check Load';
	                
	//                 ///////// Ausgänge /////////
	//                 ///////// Statics //////////
	//                 #xHandshakeScan := FALSE;
	//                 #xReleaseTrolleySep1 := FALSE;
	//                 #xOutNewScan := FALSE;
	//                 /////////  Timer  //////////
	                
	//                 //////// Transition ////////
	//                 #tmpActUnivTon := TRUE;
	//                 IF (#arInOutJamEntr1[1].bStatus.%X1 AND #xTrolleyWithPart1) OR //Daten und physikalisch -> beladen Ok!
	//                     (NOT #arInOutJamEntr1[1].bStatus.%X1 AND #xTrolleyWoPart1) //Daten und physikalisch -> unbeladen Ok!
	//                 THEN
	//                     #nState := #c1400_StepCheckSep1; // Weiter
	//                 ELSIF #fbStateManager.tOutUnivTonR > T#3s THEN
	//                     #tmpReasonForStop := 123; // TODO: Beladekontrolle Fehler
	//                 END_IF;
	                
	//             END_REGION
	            
	//         #c1400_StepCheckSep1:
	//             REGION 1400: Check Separator                
	//                 // akt. Zustand
	//                 #sStateText := 'Check Sep';
	                
	//                 ///////// Ausgänge /////////
	//                 ///////// Statics //////////
	//                 #xReleaseTrolleySep1 := FALSE;
	//                 #xHandshakeScan := FALSE;
	//                 #xOutNewScan := FALSE;
	//                 /////////  Timer  //////////
	                
	//                 //////// Transition ////////
	//                 #tmpActUnivTon := TRUE;
	//                 IF #fbSeparator1.stOutMainTro.nStatus = "SepState_WaitForReq" THEN // Separator ist bereit
	//                     #nState := #c1500_StepReleaseSep1;
	//                 ELSIF #fbStateManager.tOutUnivTonR > T#3s THEN
	//                     #tmpReasonForStop := "Rsn_SubError";    // SubTRO: Separator ist nicht bereit
	//                 END_IF;
	                
	//             END_REGION
	            
	            
	//         #c1500_StepReleaseSep1:
	//             REGION 1500: Release Sep 1            
	//                 // akt. Zustand
	//                 #sStateText := 'Leave Sep 1';
	                
	//                 ///////// Ausgänge /////////
	//                 ///////// Statics //////////
	                
	//                 #xReleaseTrolleySep1 := (#xCarouselRun AND #xInSftyOk) AND
	//                 (NOT #stInSettings.bSep1Type.%X0 OR
	//                 (#xInRelease AND #stInSettings.bSep1Type.%X0 AND NOT #stInSettings.bSep1Type.%X1) OR
	//                 (#xInRelease AND #stInSettings.bSep1Type.%X0 AND #stInSettings.bSep1Type.%X1 AND
	//                 ((#arInOutJamEntr1[1].bStatus.%X1 AND #xTrolleyWithPart1) OR
	//                 (NOT #arInOutJamEntr1[1].bStatus.%X1 AND #xTrolleyWoPart1)))); // Erste Achse darf vereinzelt werden
	                
	//                 //////// Transition ////////    
	//                 IF #fbSeparator1.stOutMainTro.nStatus = "SepState_Finish" THEN
	//                     #nState := #c2000_StepWaitForTrolley2;
	//                 ELSIF #xReleaseTrolleySep1 AND #tOnSvReleaseSep1.Q THEN
	//                     #tmpReasonForStop := "Rsn_SubError";    //  Timeout-Fehler im SubTRO "Separator": Freigabe erteilt, aber Separator gibt keine Rückmeldung an MainTRO
	//                 END_IF;
	                
	//             END_REGION
	            
	//         #c2000_StepWaitForTrolley2:
	//             REGION 2000: Wait for Trolley 2
	//                 //akt. Zustand
	//                 #sStateText := 'Wait for Trolley 2';
	//                 ///////// Ausgänge /////////
	                
	//                 ///////// Statics //////////
	                
	//                 #xReleaseTrolleySep1 := FALSE;
	//                 #xHandshakeScan := FALSE;
	//                 #xOutNewScan := FALSE;
	                
	//                 //Korrektur 2.Bein kommt nicht
	//                 (*  IF NOT #fbSeparator1.stOutMainTro.xBtPresent (* AND #xInCarouselRun *)AND NOT #stInSeparator1.Settings.xPluggedScanner AND #fbStateManager.tOutTimeInStep > T#3s THEN
	//                     #nState := #c1000_StepWaitForTrolley1;
	//                 END_IF; *)
	                
	                
	//                 //Transition
	//                 IF NOT #stInOutHMI.UDT_Ctrl.xPause THEN
	//                     IF #fbSeparator1.stOutMainTro.xBtPresent AND //Separator meldet Belegung
	//                         #arInOutJamEntr1[1].bStatus.%X0 // Carrier ist online
	//                         AND ((#xInRelease AND NOT #stInSettings.bSep1Type.%X0) OR #stInSettings.bSep1Type.%X0)//Freigabe
	//                     THEN
	//                         IF #xReadSecondLeg // zweites Bein muss gelesen werden (TODO!!!!)
	//                             AND #stInSeparator1.Settings.xPluggedScanner // Scanner verbaut?
	//                         THEN
	//                             #nState := #c2100_StepScannerTrig2; // Nächster Schritt -> Scannen
	//                         ELSE
	//                             #nState := #c2225_StepGetDir;//#c2250_StepCheckDir; // Nächster Schritt -> Check Direction
	//                         END_IF;
	//                     END_IF;
	//                 END_IF;
	//             END_REGION
	            
	//         #c2100_StepScannerTrig2:
	//             REGION 2100: Scanner Trigger 2
	                
	//                 // akt. Zustand
	//                 #sStateText := 'Scanner Trigger 2';
	                
	//                 ///////// Ausgänge /////////
	                
	//                 ///////// Statics //////////
	//                 #xReleaseTrolleySep1 := FALSE;
	                
	//                 IF #fbBarcodeReader1.xOutReadyForNewScan THEN
	//                     #xStartScan := TRUE;
	//                 END_IF;
	                
	//                 /////////  Timer  //////////
	                
	//                 //////// Transition ////////
	                
	//                 IF #fbBarcodeReader1.xOutReadingDone THEN
	//                     #xStartScan := FALSE;
	//                     #nState := #c2200_StepScannerEval2;
	//                 END_IF;
	//             END_REGION
	            
	//         #c2200_StepScannerEval2:
	//             REGION 2200: Scanner Evaluation 2
	                
	//                 // akt. Zustand
	//                 #sStateText := 'Scanner Evaluation 2';
	                
	//                 ///////// Ausgänge /////////
	                
	//                 ///////// Statics //////////
	//                 #xReleaseTrolleySep1 := FALSE;
	                
	//                 // Logic
	                
	//                 IF #fbBarcodeReader1.xOutCodeGood THEN
	//                     #nBarcodeResult := LINT_TO_DINT(#fbBarcodeReader1.#nOutBarcode); // Good read vom Barcode reader
	//                 ELSIF #fbBarcodeReader1.#xOutCodeBad THEN
	//                     #nBarcodeResult := #arInOutJamEntr1[1].nBarcode;  //erwarteter Barcode wird aus JamDaten übernommen
	//                 END_IF;
	                
	//                 IF (#nBarcodeResult > 100) AND
	//                     (#nBarcodeResult < 2147483647) AND  // Good Read (2.147.483.647 Maximum von DINT)
	//                     (#arInOutJamEntr1[1].nBarcode = 0 OR #arInOutJamEntr1[1].nBarcode = 1) THEN    //Wenn keine Daten oder ein Dummy erwartet werden   
	//                     REGION TODO
	//                         (*  "FC_CARR_GLOB_CORRECTION"(xInStart := TRUE, //Führe Korrektur aus
	//                                                     nInBarcodeScan := #nBarcodeResult,
	//                                                     nInStation := 0, // todo
	//                                                     xOutNotFound => #xTemp,
	//                                                     arOutEventLogInfo => #arEventCorrectionInfo,
	//                                                     InOutCarrierExpect := #arInOutJamEntr1[1]); *)
	//                     END_REGION
	                    
	                    
	//                     IF NOT #xTemp THEN
	//                         ;
	//                         // #stInOutCarrier.stCarrData.nNrOfScans += 1;
	//                     ELSE
	//                         #arInOutJamEntr1[1].nDestination := "cDestNONE"; //neuer Carrier // TODO
	//                         //     #stInOutCarrier.stCarrData.nNrOfScans += 1;
	//                         #arInOutJamEntr1[1].nBarcode := #nBarcodeResult; //Hier werden neue Carrier im System angelegt
	//                         #arInOutJamEntr1[1].bStatus.%X0 := TRUE;
	//                     END_IF;
	//                 ELSIF
	//                     (#nBarcodeResult > 100) AND
	//                     (#nBarcodeResult < 2147483647) AND // Good Read (2.147.483.647 Maximum von DINT)
	//                     #arInOutJamEntr1[1].nBarcode = #nBarcodeResult THEN //Barcodes stimmen überein ODER es wird hier gelandet mit BadRead wobei normaler Barcode erwartet wird-> mache normal weiter
	//                     ;
	//                 ELSIF
	//                     (#nBarcodeResult > 100) AND
	//                     (#nBarcodeResult < 2147483647) AND
	//                     #arInOutJamEntr1[1].nBarcode <> #nBarcodeResult AND //Barcodes stimmen nicht überein, erwarteter Carrier enthält aber normalen Barcode
	//                     #arInOutJamEntr1[1].nBarcode <> 0 AND
	//                     #arInOutJamEntr1[1].nBarcode <> 1 THEN
	//                     ;
	//                     REGION TODO
	//                         (*           "FC_CARR_GLOB_CORRECTION"(xInStart := TRUE, //Führe Korrektur aus
	//                                                                        nInBarcodeScan := #nBarcodeResult,
	//                                                                        nInStation := 0, // todo
	//                                                                        xOutNotFound => #xTemp,
	//                                                                        arOutEventLogInfo => #arEventCorrectionInfo,
	//                                                                        InOutCarrierExpect := #arInOutJamEntr1[1]); *)
	//                     END_REGION
	                    
	//                 ELSE        // Bad Read, falls nichts oder Dummy erwartet wird -> HANDLING TO DO!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	//                     #arInOutJamEntr1[1].bStatus.%X0 := TRUE;
	//                     #arInOutJamEntr1[1].nBarcode := 2; //unbekannter Carrier mit Badread, erwartet 0 und physikalisch vorhanden
	//                     #arInOutJamEntr1[1].nDestination := 123; //todo
	//                 END_IF;
	                
	//                 #xHandshakeScan := TRUE;
	                
	//                 /////////  Timer  //////////
	                
	//                 //////// Transition ////////
	//                 #nState := #c2225_StepGetDir;//#c2250_StepCheckDir;
	//             END_REGION ;
	            
	//         #c2225_StepGetDir:
	//             REGION 2225: Get Direction
	//                 // akt. Zustand
	//                 #sStateText := 'Get Dir';
	                
	//                 ///////// Ausgänge /////////
	                
	//                 ///////// Statics //////////
	//                 #xReleaseTrolleySep1 := FALSE;
	                
	//                 #stActRequest.nDirection := #nInDirection;
	                
	//                 IF #stActRequest.nDirection = 0 THEN
	//                     #tmpReasonForStop := "Rsn_MfrMistake";
	//                 ELSE
	//                     #nState := #c2250_StepCheckDir;
	//                 END_IF;
	//             END_REGION
	            
	            
	            
	//         #c2250_StepCheckDir:
	//             REGION 2250: Check Direction      
	                
	//                 // akt. Zustand
	//                 #sStateText := 'Check Dir';
	                
	//                 ///////// Ausgänge /////////
	                
	//                 ///////// Statics //////////
	//                 #xReleaseTrolleySep1 := FALSE;
	                
	//                 //Richtungswechsel muss noch berücksichtigt werden!
	//                 IF #nLastDirection <> #stActRequest.nDirection THEN // Richtungswechsel -> Warten
	//                     //  #tmpActUnivTon := TRUE;
	//                     #xStartSwitchDelay := true;
	//                     IF #tOnSwitchDelay.Q THEN
	//                         #nSetSwitch1 := #stActRequest.nDirection;
	//                         #nLastDirection := #stActRequest.nDirection;
	//                         #nState := #c2300_StepCheckSep2;
	//                     END_IF;
	//                 ELSIF #nLastDirection = #nInDirection THEN // Gleiche Richtung -> Weiter
	//                     #nSetSwitch1 := #stActRequest.nDirection;
	//                     #nLastDirection := #stActRequest.nDirection;
	//                     #nState := #c2300_StepCheckSep2;
	//                 END_IF;
	//             END_REGION
	            
	            
	//         #c2300_StepCheckSep2:
	//             REGION 2300: Check Separator                
	//                 // akt. Zustand
	//                 #sStateText := 'Check Sep';
	                
	//                 ///////// Ausgänge /////////
	//                 ///////// Statics //////////
	//                 #xHandshakeScan := FALSE;
	//                 #xReleaseTrolleySep1 := FALSE;
	//                 /////////  Timer  //////////
	                
	//                 //////// Transition ////////
	//                 #tmpActUnivTon := TRUE;
	//                 IF #fbSeparator1.stOutMainTro.nStatus = "SepState_WaitForReq" THEN // Separator ist bereit
	//                     #nState := #c2350_StepCheckSwi;
	//                 ELSIF #fbStateManager.tOutUnivTonR > T#3s THEN
	//                     #tmpReasonForStop := "Rsn_SubError";    // SubTRO: Separator ist nicht bereit
	//                 END_IF;
	                
	//             END_REGION
	            
	            
	//         #c2350_StepCheckSwi:
	//             REGION 2300: Check Switch
	                
	//                 //akt. Zustand
	//                 #sStateText := 'Check Switch';
	                
	//                 ///////// Ausgänge /////////
	                
	//                 ///////// Statics //////////
	//                 #xReleaseTrolleySep1 := FALSE;
	                
	//                 #nSetSwitch1 := #stActRequest.nDirection;
	//                 /////////  Timer  //////////
	                
	//                 //////// Transition ////////
	                
	//                 CASE #stActRequest.nDirection OF
	//                     1:
	//                         IF NOT #fbSwitch1.stOutMainTro.xStatusIn AND
	//                             NOT #fbSwitch1.stOutMainTro.xStatusOut AND NOT #fbSwitch1.xOutPermSigOutSen3 THEN
	//                             #fbSwitch1.xInOutEnq := FALSE;
	//                             #nState := #c2400_StepCheckJam;
	//                         ELSE
	//                             #tmpReasonForStop := "Rsn_SubError"; // Fehler im SubTRO: Weiche
	//                         END_IF;
	//                     2:
	//                         IF NOT #fbSwitch1.stOutMainTro.xStatusIn AND
	//                             #fbSwitch1.stOutMainTro.xStatusOut AND NOT #fbSwitch1.xOutPermSigOutSen4 THEN
	//                             #fbSwitch1.xInOutEnq := FALSE;
	//                             #nState := #c2400_StepCheckJam;
	//                         ELSE
	//                             #tmpReasonForStop := "Rsn_SubError"; // Fehler im SubTRO: Weiche
	//                         END_IF;
	//                     ELSE
	//                         #tmpReasonForStop := "Rsn_GeneralError"; // Allgemeiner Fehler falls Direction irgendetwas anderes ist als 1 oder 2
	//                         #nState := #c2225_StepGetDir; // zurückgehen zu Get Direction
	//                 END_CASE;
	//             END_REGION
	            
	//         #c2400_StepCheckJam:
	//             REGION 2400: Check Jam
	//                 // akt. Zustand
	//                 #sStateText := 'Check Jam';
	//                 ///////// Ausgänge /////////
	//                 ///////// Statics //////////
	//                 #xReleaseTrolleySep1 := FALSE;
	//                 #nSetSwitch1 := #stActRequest.nDirection;
	                
	//                 /////////  Timer  //////////
	//                 //////// Transition ////////
	//                 CASE #stActRequest.nDirection OF
	//                     1: //Ausgang 2 wird auf Stau geprüft
	//                         IF (#stInOutJamExit2.Status.nCount = #stInOutJamExit2.Config.nCapacitySet) OR #stInSenJam2.xJam THEN  //Stau vom nächsten MainTro wird gemeldet
	//                             #tmpReasonForStop := "Rsn_JamNextError";
	//                         ELSIF #fbSwitch1.stOutMainTro.xJamAtExit3 THEN  //Stau vom SubTro wird gemeldet
	//                             #tmpReasonForStop := "Rsn_SubError";
	//                         ELSE
	//                             #nState := #c2500_StepReleaseSep2;  //ohne Stau nächster Schritt
	//                         END_IF;
	//                     2: //Ausgang 3 wird auf Stau geprüft
	//                         IF (#stInOutJamExit3.Status.nCount = #stInOutJamExit3.Config.nCapacitySet) OR #stInSenJam3.xJam THEN  //Stau vom nächsten MainTro wird gemeldet
	//                             #tmpReasonForStop := "Rsn_JamNextError";
	//                         ELSIF #fbSwitch1.stOutMainTro.xJamAtExit4 THEN  //Stau vom SubTro wird gemeldet
	//                             #tmpReasonForStop := "Rsn_SubError";
	//                         ELSE
	//                             #nState := #c2500_StepReleaseSep2;   //ohne Stau nächster Schritt
	//                         END_IF;
	//                     ELSE
	//                         #tmpReasonForStop := "Rsn_GeneralError"; // Allgemeiner Fehler falls Direction irgendetwas anderes ist als 1 oder 2
	//                         #nState := #c2225_StepGetDir; // zurückgehen zu Get Direction
	//                 END_CASE;
	                
	//             END_REGION
	            
	//         #c2500_StepReleaseSep2:
	//             REGION 2500: Leave, Switch confirmed
	                
	//                 // aktueller Zustand
	                
	//                 #sStateText := 'Leave Separator';
	                
	//                 ///////// Ausgänge /////////
	                
	//                 ///////// Statics //////////
	//                 // Freigabe an Separator, wenn alle Bedingungen erfüllt
	//                 #xReleaseTrolleySep1 := #xInSftyOk AND
	//                 #xCarouselRun AND
	//                 NOT #xWrongDirDetect AND
	//                 NOT #stActRequest.xLongSignal AND
	//                 NOT #stInOutJamEntr1.Status.bByte.%X3 AND
	                
	//                 (#stInPriorityManagerDir1.xReleaseOk AND #stActRequest.nDirection = 1 AND #stInSettings.xPrioDir1)
	//                 OR (#stActRequest.nDirection = 1 AND NOT #stInSettings.xPrioDir1)
	//                 OR (#stInPriorityManagerDir2.xReleaseOk AND #stActRequest.nDirection = 2 AND #stInSettings.xPrioDir2)
	//                 OR (#stActRequest.nDirection = 2 AND NOT #stInSettings.xPrioDir2)
	//                 OR (NOT #stInSettings.xPrioDir1 AND NOT #stInSettings.xPrioDir2) AND
	                
	//                 (#stActRequest.nDirection = 1 OR #stActRequest.nDirection = 2);
	                
	//                 #nSetSwitch1 := #stActRequest.nDirection;
	//                 /////////  Timer  //////////
	                
	//                 // Reason for Stop
	                
	//                 // IF #stInMfr.xPause THEN
	//                 //     #tmpReasonForStop := "Rsn_MfrPausedTro";
	//                 // END_IF;
	                
	//                 IF NOT #xCarouselRun THEN
	//                     #tmpReasonForStop := "Rsn_CarouselError";
	//                 END_IF;
	                
	//                 IF #xWrongDirDetect THEN
	//                     #tmpReasonForStop := "Rsn_WrongDirection";
	//                 END_IF;
	                
	//                 IF #stActRequest.xLongSignal THEN
	//                     #tmpReasonForStop := "Rsn_LongSignalDetected";
	//                 END_IF;
	                
	//                 //////// Transition ////////
	                
	//                 CASE #stActRequest.nDirection OF
	//                     1, 2:
	//                         IF #fbSeparator1.stOutMainTro.nStatus = "SepState_Finish" THEN  // Separator meldet erfolgreiches Vereinzeln
	//                             REGION NEU: Buchen 1->3
	//                                 IF #stActRequest.nDirection = 1 THEN
	//                                     #stTempCarrier := #arInOutJamEntr1[1];
	                                    
	//                                     "FC_Route"(xInSingle := FALSE,
	//                                                xInSeparate := FALSE,
	//                                                xInSepEdge := TRUE,
	//                                                xInSensor := FALSE,
	//                                                xInDelay := FALSE,
	//                                                stInCarrier := #stEmptyCarrier,
	//                                                stOutBookingInfo => #stBookingInfo,
	//                                                arJamEntr := #arInOutJamEntr1,
	//                                                arOnTheWay := #arEmptyCarrier,
	//                                                arJamExit := #arInOutJamExit2);
	//                                     #xBookedDir1 := TRUE;
	//                                 END_IF;
	//                             END_REGION
	                            
	//                             REGION NEU: Buchen 1->4
	//                                 IF #stActRequest.nDirection = 2 THEN
	//                                     #stTempCarrier := #arInOutJamEntr1[1];
	//                                     "FC_Route"(xInSingle := FALSE,
	//                                                xInSeparate := FALSE,
	//                                                xInSepEdge := TRUE,
	//                                                xInSensor := FALSE,
	//                                                xInDelay := FALSE,
	//                                                stInCarrier := #stEmptyCarrier,
	//                                                stOutBookingInfo => #stBookingInfo,
	//                                                arJamEntr := #arInOutJamEntr1,
	//                                                arOnTheWay := #arEmptyCarrier,
	//                                                arJamExit := #arInOutJamExit3);
	                                    
	//                                     #xBookedDir2 := TRUE;
	//                                 END_IF;
	//                             END_REGION
	                            
	                            
	                            
	//                             #nState := #c1000_StepWaitForTrolley1;               // Nächster Schritt
	//                         ELSIF #xReleaseTrolleySep1 AND #tOnSvReleaseSep1.Q THEN      // Überwachungszeit nach Freigabe an Separator abgelaufen
	//                             #tmpReasonForStop := "Rsn_SubError";                    // Timeout-Fehler im Separator: Freigabe erteilt, aber Separator gibt keine Rückmeldung an MainTRO
	//                         END_IF;
	//                     ELSE
	//                         #tmpReasonForStop := "Rsn_GeneralError";                    // Allgemeiner Fehler
	//                         #nState := #c2225_StepGetDir;
	//                 END_CASE;
	//             END_REGION
	//     END_CASE;
	    
	// END_REGION
	
	// REGION Beladekontrolle
	//     //Beladekontrolle aktiviert
	//     REGION Sep1
	//         IF #stInSeparator1.Settings.xPluggedPart THEN
	            
	//             //Trolley beladen
	//             #xTrolleyWithPart1 :=
	//             #stInSeparator1.Settings.xPluggedPart AND
	//             #stInSeparator1.stSenInSep.xDbncdSensor
	//             AND #stInSeparator1.stSenPart.xDirectSensor
	//             AND #stInSeparator1.stSenPart.tDirectChangeLast > #stInSettings.tPartSenHigh;
	            
	//             //Trolley nicht beladen
	//             #xTrolleyWoPart1 :=
	//             #stInSeparator1.Settings.xPluggedPart AND
	//             #stInSeparator1.stSenInSep.xDbncdSensor AND
	//             #stInSeparator1.stSenInSep.tDirectChangeLast > #stInSettings.tInSenHigh AND
	//             NOT #stInSeparator1.stSenPart.xDirectSensor;
	            
	//             //Plausibel?
	//             IF #stInSeparator1.Settings.xPluggedPart AND ((#arInOutJamEntr1[1].bStatus.%X1 AND #xTrolleyWoPart1) OR
	//                 (NOT #arInOutJamEntr1[1].bStatus.%X1 AND #xTrolleyWithPart1))
	//             THEN
	//                 #wErrorWord1.%X2 := TRUE;
	//             ELSE
	//                 #wErrorWord1.%X2 := FALSE;
	//             END_IF;
	//         ELSE
	//             #xTrolleyWithPart1 := #xTrolleyWoPart1 := FALSE; // Beladekontrolle (Sensor) nicht verbaut
	//         END_IF;
	//     END_REGION
	
	//     REGION Sep2
	//         IF #stInSeparator2.Settings.xPluggedPart THEN
	            
	//             //Trolley beladen
	//             #xTrolleyWithPart2 :=
	//             #stInSeparator2.Settings.xPluggedPart AND
	//             #stInSeparator2.stSenInSep.xDbncdSensor
	//             AND #stInSeparator2.stSenPart.xDirectSensor
	//             AND #stInSeparator2.stSenPart.tDirectChangeLast > #stInSettings.tPartSenHigh;
	            
	//             //Trolley nicht beladen
	//             #xTrolleyWoPart2 :=
	//             #stInSeparator2.Settings.xPluggedPart AND
	//             #stInSeparator2.stSenInSep.xDbncdSensor AND
	//             #stInSeparator2.stSenInSep.tDirectChangeLast > #stInSettings.tInSenHigh AND
	//             NOT #stInSeparator2.stSenPart.xDirectSensor;
	            
	//             //Plausibel?
	//             IF #stInSeparator2.Settings.xPluggedPart AND ((#arInOutJamEntr2[1].bStatus.%X1 AND #xTrolleyWoPart2) OR
	//                 (NOT #arInOutJamEntr2[1].bStatus.%X1 AND #xTrolleyWithPart2))
	//             THEN
	//                 #wErrorWord2.%X2 := TRUE;
	//             ELSE
	//                 #wErrorWord2.%X2 := FALSE;
	//             END_IF;
	//         ELSE
	//             #xTrolleyWithPart2 := #xTrolleyWoPart2 := FALSE; // Beladekontrolle (Sensor) nicht verbaut
	//         END_IF;
	//     END_REGION
	// END_REGION
	
	// REGION Dummy Handling
	    
	//     #nArrayMax1 := DINT_TO_INT(UPPER_BOUND(ARR := #arInOutJamEntr1, DIM := 1));
	//     #nArrayMax2 := DINT_TO_INT(UPPER_BOUND(ARR := #arInOutJamEntr2, DIM := 1));
	    
	//     REGION Dummy erstellen
	//         REGION Sep1
	//             IF #stInSettings.xIsBorner1 THEN
	//                 IF #nBarcodeEmpty1 > 1999 OR #nBarcodeEmpty1 < 1000 THEN
	//                     #nBarcodeEmpty1 := 1000;
	//                 ELSE
	//                     IF #nState = 2500 AND #fbSeparator1.xOutTrolleyReleasedEdge THEN
	//                         #nBarcodeEmpty1 += 1;
	//                     END_IF;
	//                 END_IF;
	                
	//                 IF #fbSeparator1.stOutMainTro.xBtPresent AND
	//                     #fbSeparator1.stOutMainTro.nStatus = "SepState_WaitForReq" AND
	//                     #stInSeparator1.stSenInSep.tDirectChangeLast > #stInSettings.tDummyTimeBorner AND
	//                     #arInOutJamEntr1[1] = #tmpCarrierEmpty
	//                 THEN
	//                     #arInOutJamEntr1[1].nBarcode := #nBarcodeEmpty1;
	//                     #arInOutJamEntr1[1].bStatus.%X0 := TRUE;
	//                     #arInOutJamEntr1[1].nDestination := #stInSettings.nBornerDest1;
	//                 END_IF;
	//             ELSE
	//                 IF #fbSeparator1.stOutMainTro.xBtPresent AND
	//                     #fbSeparator1.stOutMainTro.nStatus = "SepState_WaitForReq" AND
	//                     #stInSeparator1.stSenInSep.tDirectChangeLast > #stInSettings.tDummyTimeNormal AND //Unterscheidung bei Borner?
	//                     #arInOutJamEntr1[1] = #tmpCarrierEmpty
	//                 THEN
	//                     #arInOutJamEntr1[1].nBarcode := #cCarrierDummy;
	//                     #arInOutJamEntr1[1].bStatus.%X0 := TRUE;
	//                 END_IF;
	//             END_IF;
	//         END_REGION
	//         REGION Sep2
	//             IF #stInSettings.xIsBorner2 THEN
	//                 IF #nBarcodeEmpty2 > 1999 OR #nBarcodeEmpty2 < 1000 THEN
	//                     #nBarcodeEmpty2 := 1000;
	//                 ELSE
	//                     IF #nState = 2500 AND #fbSeparator2.xOutTrolleyReleasedEdge THEN
	//                         #nBarcodeEmpty2 += 1;
	//                     END_IF;
	//                 END_IF;
	                
	//                 IF #fbSeparator2.stOutMainTro.xBtPresent AND
	//                     #fbSeparator2.stOutMainTro.nStatus = "SepState_WaitForReq" AND
	//                     #stInSeparator2.stSenInSep.tDirectChangeLast > #stInSettings.tDummyTimeBorner AND
	//                     #arInOutJamEntr2[1] = #tmpCarrierEmpty
	//                 THEN
	//                     #arInOutJamEntr2[1].nBarcode := #nBarcodeEmpty2;
	//                     #arInOutJamEntr2[1].bStatus.%X0 := TRUE;
	//                     #arInOutJamEntr2[1].nDestination := #stInSettings.nBornerDest2;
	//                 END_IF;
	//             ELSE
	//                 IF #fbSeparator2.stOutMainTro.xBtPresent AND
	//                     #fbSeparator2.stOutMainTro.nStatus = "SepState_WaitForReq" AND
	//                     #stInSeparator2.stSenInSep.tDirectChangeLast > #stInSettings.tDummyTimeNormal AND //Unterscheidung bei Borner?
	//                     #arInOutJamEntr2[1] = #tmpCarrierEmpty
	//                 THEN
	//                     #arInOutJamEntr2[1].nBarcode := #cCarrierDummy;
	//                     #arInOutJamEntr2[1].bStatus.%X0 := TRUE;
	//                 END_IF;
	//             END_IF;
	//         END_REGION
	        
	//     END_REGION
	    
	//     REGION Dummy löschen
	//         REGION Sep1
	//             IF #nArrayMax1 > 1 THEN //Staubereich mit Capacity > 0
	//                 IF (#arInOutJamEntr1[1] = #stCarrierDummy) //Dummy an erster Position
	//                     AND #arInOutJamEntr1[2] = #tmpCarrierEmpty AND //Keine Daten an zweiter Position
	//                     NOT #stInSeparator1.stSenInSep.xDirectSensor AND #stInSeparator1.stSenInSep.tDirectChangeLast > T#8s AND //keine Belegung
	//                     #fbSeparator1.stOutMainTro.nStatus = "SepState_WaitForBt" AND #fbSeparator1.#fbStateManager.tOutTimeInStep > T#8s //Separator Zustand abfragen
	//                 THEN
	//                     #arInOutJamEntr1[1] := #tmpCarrierEmpty; //Dummy löschen
	//                 ELSIF (#arInOutJamEntr1[1] = #stCarrierDummy) //Dasselbe wie oben aber mit nachrücken
	//                     AND (#arInOutJamEntr1[2] = #stCarrierDummy OR #arInOutJamEntr1[2] <> #stCarrierDummy) AND
	//                     NOT #stInSeparator1.stSenInSep.xDirectSensor AND #stInSeparator1.stSenInSep.tDirectChangeLast > T#8s AND
	//                     #fbSeparator1.stOutMainTro.nStatus = "SepState_WaitForBt" AND #fbSeparator1.#fbStateManager.tOutTimeInStep > T#8s //Separator Zustand abfragen
	//                 THEN
	//                     #arInOutJamEntr1[1] := #tmpCarrierEmpty;
	//                     "FC_TSHR_Shift"(xInShiftBack := TRUE,
	//                                     arTSHR := #arInOutJamEntr1);
	//                 END_IF;
	//             ELSIF #nArrayMax1 = 1 THEN
	//                 IF (#arInOutJamEntr1[1] = #stCarrierDummy) AND
	//                     NOT #stInSeparator1.stSenInSep.xDirectSensor AND #stInSeparator1.stSenInSep.tDirectChangeLast > T#8s AND
	//                     #fbSeparator1.stOutMainTro.nStatus = "SepState_WaitForBt" AND #fbSeparator1.#fbStateManager.tOutTimeInStep > T#8s //Separator Zustand abfragen
	//                 THEN
	//                     #arInOutJamEntr1[1] := #tmpCarrierEmpty;
	//                 END_IF;
	//             END_IF;
	//         END_REGION
	//         REGION Sep2
	//             IF #nArrayMax2 > 1 THEN //Staubereich mit Capacity > 0
	//                 IF (#arInOutJamEntr2[1] = #stCarrierDummy) //Dummy an erster Position
	//                     AND #arInOutJamEntr2[2] = #tmpCarrierEmpty AND //Keine Daten an zweiter Position
	//                     NOT #stInSeparator2.stSenInSep.xDirectSensor AND #stInSeparator2.stSenInSep.tDirectChangeLast > T#8s AND //keine Belegung
	//                     #fbSeparator2.stOutMainTro.nStatus = "SepState_WaitForBt" AND #fbSeparator2.#fbStateManager.tOutTimeInStep > T#8s //Separator Zustand abfragen
	//                 THEN
	//                     #arInOutJamEntr2[1] := #tmpCarrierEmpty; //Dummy löschen
	//                 ELSIF (#arInOutJamEntr2[1] = #stCarrierDummy) //Dasselbe wie oben aber mit nachrücken
	//                     AND (#arInOutJamEntr2[2] = #stCarrierDummy OR #arInOutJamEntr2[2] <> #stCarrierDummy) AND
	//                     NOT #stInSeparator2.stSenInSep.xDirectSensor AND #stInSeparator2.stSenInSep.tDirectChangeLast > T#8s AND
	//                     #fbSeparator2.stOutMainTro.nStatus = "SepState_WaitForBt" AND #fbSeparator2.#fbStateManager.tOutTimeInStep > T#8s //Separator Zustand abfragen
	//                 THEN
	//                     #arInOutJamEntr2[1] := #tmpCarrierEmpty;
	//                     "FC_TSHR_Shift"(xInShiftBack := TRUE,
	//                                     arTSHR := #arInOutJamEntr2);
	//                 END_IF;
	//             ELSIF #nArrayMax2 = 1 THEN
	//                 IF (#arInOutJamEntr2[1] = #stCarrierDummy) AND
	//                     NOT #stInSeparator2.stSenInSep.xDirectSensor AND #stInSeparator2.stSenInSep.tDirectChangeLast > T#8s AND
	//                     #fbSeparator2.stOutMainTro.nStatus = "SepState_WaitForBt" AND #fbSeparator2.#fbStateManager.tOutTimeInStep > T#8s //Separator Zustand abfragen
	//                 THEN
	//                     #arInOutJamEntr2[1] := #tmpCarrierEmpty;
	//                 END_IF;
	//             END_IF;
	//         END_REGION
	        
	//     END_REGION
	    
	// END_REGION
	
	// REGION Monitoring
	    
	//     REGION Carrier kommt nicht an / Daten ohne Belegung
	//         REGION Sep1
	//             #tOnMonCarrArrive1(IN := #arInOutJamEntr1[1].bStatus.%X0 AND NOT #stInSeparator1.stSenInSep.xDirectSensor,
	//                                PT := #stInSeparator1.Settings.tDelayToNextItem,
	//                                Q => #wErrorWord1.%X10); //TODO
	            
	//             #fbMonitoringCarrNotArrive1.stSettings.nErrorType := 1;
	//             #fbMonitoringCarrNotArrive1.stSettings.xErrLedIfMachineIsOff := TRUE;
	//             #fbMonitoringCarrNotArrive1.stSettings.xSelfQuit := TRUE;
	//             #fbMonitoringCarrNotArrive1(wInTextListId_Function := 1000,
	//                                         sInPrefix := #stInOutHMI.UDT_Config.sName,
	//                                         wInTextListId_Message := 1000,
	//                                         sInSuffix := '',
	//                                         xInQuitError := #stInOutMachineState.xQuitError,
	//                                         xInSignal := NOT #wErrorWord1.%X10,
	//                                         sInAlarmMessage := 'Carrier kommt nicht am Separator 1 an',
	//                                         InOutMachineState := #stInOutMachineState);
	//         END_REGION
	//         REGION Sep2
	//             #tOnMonCarrArrive2(IN := #arInOutJamEntr2[1].bStatus.%X0 AND NOT #stInSeparator2.stSenInSep.xDirectSensor,
	//                                PT := #stInSeparator2.Settings.tDelayToNextItem,
	//                                Q => #wErrorWord2.%X10); //TODO
	            
	//             #fbMonitoringCarrNotArrive2.stSettings.nErrorType := 1;
	//             #fbMonitoringCarrNotArrive2.stSettings.xErrLedIfMachineIsOff := TRUE;
	//             #fbMonitoringCarrNotArrive2.stSettings.xSelfQuit := TRUE;
	//             #fbMonitoringCarrNotArrive2(wInTextListId_Function := 1000,
	//                                         sInPrefix := #stInOutHMI.UDT_Config.sName,
	//                                         wInTextListId_Message := 1000,
	//                                         sInSuffix := '',
	//                                         xInQuitError := #stInOutMachineState.xQuitError,
	//                                         xInSignal := NOT #wErrorWord2.%X10,
	//                                         sInAlarmMessage := 'Carrier kommt nicht am Separator 2 an',
	//                                         InOutMachineState := #stInOutMachineState);
	//         END_REGION
	        
	//     END_REGION
	    
	//     REGION Carrier ohne Daten
	        
	//         REGION Sep1
	//             IF #stInSeparator1.stSenInSep.xDbncdSensor AND #stInSeparator1.stSenInSep.tDirectChangeLast > T#5s AND NOT #arInOutJamEntr1[1].bStatus.%X0 THEN
	//                 #wErrorWord1.%X5 := TRUE;
	//             ELSE
	//                 #wErrorWord1.%X5 := FALSE;
	//             END_IF;
	            
	//             #fbMonitoringCarrWoData1.stSettings.nErrorType := 1;
	//             #fbMonitoringCarrWoData1.stSettings.xErrLedIfMachineIsOff := TRUE;
	//             #fbMonitoringCarrWoData1.stSettings.xSelfQuit := TRUE;
	//             #fbMonitoringCarrWoData1(wInTextListId_Function := 1000,
	//                                      sInPrefix := #stInOutHMI.UDT_Config.sName,
	//                                      wInTextListId_Message := 1001,
	//                                      sInSuffix := '',
	//                                      InOutMachineState := #stInOutMachineState,
	//                                      xInQuitError := #stInOutMachineState.xQuitError,
	//                                      xInSignal := NOT #wErrorWord1.%X5,
	//                                      sInAlarmMessage := 'Sep1-Belegung ohne Daten');
	//         END_REGION
	//         REGION Sep2
	//             IF #stInSeparator2.stSenInSep.xDbncdSensor AND #stInSeparator2.stSenInSep.tDirectChangeLast > T#5s AND NOT #arInOutJamEntr2[1].bStatus.%X0 THEN
	//                 #wErrorWord2.%X5 := TRUE;
	//             ELSE
	//                 #wErrorWord2.%X5 := FALSE;
	//             END_IF;
	            
	//             #fbMonitoringCarrWoData2.stSettings.nErrorType := 1;
	//             #fbMonitoringCarrWoData2.stSettings.xErrLedIfMachineIsOff := TRUE;
	//             #fbMonitoringCarrWoData2.stSettings.xSelfQuit := TRUE;
	//             #fbMonitoringCarrWoData2(wInTextListId_Function := 1000,
	//                                      sInPrefix := #stInOutHMI.UDT_Config.sName,
	//                                      wInTextListId_Message := 1001,
	//                                      sInSuffix := '',
	//                                      InOutMachineState := #stInOutMachineState,
	//                                      xInQuitError := #stInOutMachineState.xQuitError,
	//                                      xInSignal := NOT #wErrorWord2.%X5,
	//                                      sInAlarmMessage := 'Sep2-Belegung ohne Daten');
	//         END_REGION
	//     END_REGION
	    
	// END_REGION
	
	// REGION Timer - Überwachungszeit
	    
	//     #tOnSwitchDelay(IN := #xStartSwitchDelay,
	//                     PT := T#5s);
	    
	//     #tOnSvReleaseSep1(IN := ((#nState = #c1500_StepReleaseSep1) OR (#nState = #c2500_StepReleaseSep2)) AND #xReleaseTrolleySep1,
	//                       PT := T#3s);
	    
	//     #tOnSvReleaseSep2(IN := ((#nState = #c1500_StepReleaseSep1) OR (#nState = #c2500_StepReleaseSep2)) AND #xReleaseTrolleySep2,
	//                       PT := T#3s);
	    
	// END_REGION
	
	// REGION Haltegrund Schrittkette
	    
	//     #stActRequest.nReasonForStop := #tmpReasonForStop;  //tmp aus Schrittkette übernehmen
	    
	// END_REGION
	
	// REGION Motorüberwachung
	    
	//     IF (#nState >= #c1500_StepReleaseSep1) AND (#nState <= #c2500_StepReleaseSep2) AND #fbStateManager.tOutTimeInStep > T#4s AND NOT #xCarouselRun THEN
	//         #xErrorMotor := TRUE;
	//     ELSE
	//         #xErrorMotor := FALSE;
	//     END_IF;
	    
	// END_REGION
	
	// REGION StateManager
	    
	//     #fbStateManager.stInSettings.nStartState := #c0100_StepUndefined;
	//     #fbStateManager.stInSettings.nStartStateTestMode := #c0000_StepOff;
	//     #fbStateManager.stInSettings.xActUnivTOn := TRUE;
	//     #fbStateManager.stInSettings.xRestartAtStartState := FALSE;
	//     #fbStateManager(xInFunctionEnabled := #stInOutMachineState.xRunning,
	//                     xInReset := #stInOutHMI.UDT_Ctrl.xReset OR #xInCancel,
	//                     xInRunUnivTOn := #tmpActUnivTon,
	//                     xInTestMode := #xInTestMode,
	//                     nInOutState := #nState);
	// END_REGION
	
	// REGION Aufruf der Sub-TROs
	    
	//     REGION Separator 1        
	//         #fbSeparator1(xInReset := #stInOutHMI.UDT_Ctrl.xReset OR #xInCancel,
	//                       xInErrQuit := #stInOutHMI.UDT_Ctrl.xErrorQuit,
	//                       stInOutMainState := #stInOutMachineState,
	//                       stInSettings := #stInSeparator1.Settings,
	//                       xInConveyorRun := #xCarouselRun,
	//                       stInTrolley := #stInSeparator1.stSenInSep,
	//                       xInReceiveReady := #xReleaseTrolleySep1,
	//                       stInOutHMI := #stInOutHMI.UDT_Separator1,
	//                       stInOutCarrDataInJam := #arInOutJamEntr1);
	        
	//         #stInOutHMI.UDT_Separator1.stStatus.xNullBt := #stInOutHMI.UDT_Ctrl.xPause;
	//         #stInOutHMI.UDT_Separator2.stStatus.xNullBt := #stInOutHMI.UDT_Ctrl.xPause;
	//     END_REGION
	    
	//     REGION Separator 2        
	//         #fbSeparator2(xInReset := #stInOutHMI.UDT_Ctrl.xReset OR #xInCancel,
	//                       xInErrQuit := #stInOutHMI.UDT_Ctrl.xErrorQuit,
	//                       stInOutMainState := #stInOutMachineState,
	//                       stInSettings := #stInSeparator2.Settings,
	//                       xInConveyorRun := #xCarouselRun,
	//                       stInTrolley := #stInSeparator2.stSenInSep,
	//                       xInReceiveReady := #xReleaseTrolleySep2,
	//                       stInOutHMI := #stInOutHMI.UDT_Separator2,
	//                       stInOutCarrDataInJam := #arInOutJamEntr2);
	        
	//         #stInOutHMI.UDT_Separator1.stStatus.xNullBt := #stInOutHMI.UDT_Ctrl.xPause;
	//         #stInOutHMI.UDT_Separator2.stStatus.xNullBt := #stInOutHMI.UDT_Ctrl.xPause;
	//     END_REGION
	    
	//     REGION Switch 1
	//         #fbSwitch1(stInSettings := #stInSwitch1.Settings,
	//                    stInSenExit3 := #stInSwitch1.stSenExit3,
	//                    stInSenExit4 := #stInSwitch1.stSenExit4,
	//                    nInMainTroNo := #nInMainTroNo,
	//                    nInSetSwitch := #nSetSwitch1,
	//                    nInSwitchNo := 0,
	//                    xInErrorQuit := "cTodoFalse",
	//                    xInSftyOk := #xInSftyOk,
	//                    xInAllRdyToStart := #xInAllRdyToStart,
	//                    xInCarouselRun := #xCarouselRun,
	//                    xInCancel := #stInOutHMI.UDT_Ctrl.xReset OR #xInCancel,
	//                    xInReqFinished := #tmpReqFinished,
	//                    xOutSwEntrTo1 => #xOutSw1EntrTo1,
	//                    xOutSwEntrTo2 => #xOutSw1EntrTo2,
	//                    xOutSwExTo3 => #xOutSw1ExTo3,
	//                    xOutSwExTo4 => #xOutSw1ExTo4,
	//                    stInOutMachineState := #stInOutMachineState,
	//                    stInOutHMI := #stInOutHMI.UDT_Switch1);
	//     END_REGION ;
	    
	//     REGION Barcode Reader 1
	//         #fbBarcodeReader1(stInSettings := #stInBarcodeReader1.Settings,
	//                           xInHWError := false, // todo
	//                           xInStartReading := #xStartScan,
	//                           xInHandshakeDone := #xHandshakeScan,
	//                           stInOutInterface := #stInOutCognexInterface1,
	//                           stInOutControlUnitCabinet := #stInOutMachineState,
	//                           stInOutHMI := #stInOutHMI.UDT_BarcodeReader1);
	//     END_REGION
	    
	//     REGION Barcode Reader 2
	//         #fbBarcodeReader2(stInSettings := #stInBarcodeReader2.Settings,
	//                           xInHWError := false, // todo
	//                           xInStartReading := #xStartScan,
	//                           xInHandshakeDone := #xHandshakeScan,
	//                           stInOutInterface := #stInOutCognexInterface2,
	//                           stInOutControlUnitCabinet := #stInOutMachineState,
	//                           stInOutHMI := #stInOutHMI.UDT_BarcodeReader2);
	//     END_REGION
	// END_REGION
	
	// REGION BT und NBT zählen
	    
	//     #stActRequest.nActNoInSwitch := #fbSwitch1.stOutMainTro.nFifoElementCount;
	    
	// END_REGION
	
	// REGION Long-Signale von Switch verarbeiten
	    
	//     (*  //Switch gibt LongSignal aus und hier wird es für MainTRO gemerkt
	//       IF (#stActRequest.nDirection = 1 AND #fbSwitch1.stOutMainTro.xSen3Long) OR
	//           (#stActRequest.nDirection = 2 AND #fbSwitch1.stOutMainTro.xSen4Long) THEN
	//           #stActRequest.xLongSignal := TRUE;
	//       ELSIF #fbSwitch1.stOutMainTro.xFifoEmpty THEN
	//           #stActRequest.xLongSignal := FALSE;
	//       END_IF;
	//       
	//       #tOnLongSignal(IN := #stActRequest.xLongSignal, //Extra Timer für Long-Signal um nach dieser Zeit einen einzelnen BT der noch im Switch ist zu quittieren
	//                      PT := #stInSwitch1.Settings.tSenWaitAfterLong); //"TimeLongSignalQuitMax"
	//       
	//       #fbSwitch1.xInDeqExternal :=   //Dequeue wird hier an Switch weitergegeben falls (nachdem Sep gesperrt wurde) nur noch ein einzelenr BT vermisst wird nach LongSignal
	//       NOT #fbSwitch1.xOutBtLeftSwitchWrongDir AND
	//       ((#nSetSwitch1 = 1 OR #nSetSwitch1 = 2 OR #nSetSwitch1 = 3 OR #nSetSwitch1 = 4) AND #stActRequest.xLongSignal AND #tOnLongSignal.Q AND #stActRequest.nActNoInSwitch = 1);
	//       
	//       
	//       IF #stActRequest.xLongSignal AND #tOnLongSignal.Q AND #stActRequest.nActNoInSwitch > 1 THEN //Falls nach LongSignal mehrere BT vermisst werden, werden die entsprechenden FIFO-Indizes an MFR als Missing ausgegeben
	//           #nIndex := 1;
	//           WHILE #nIndex <= 6 DO
	//               IF #fbSwitch1.arOutFifo[#nIndex] > 0 AND #fbSwitch1.arOutFifo[#nIndex] <= 6 THEN
	//                   #arReq[#nIndex].xMissingBT := TRUE;
	//               ELSIF #fbSwitch1.arOutFifo[#nIndex] = 0 THEN
	//                   #arReq[#nIndex].xMissingBT := FALSE;
	//               END_IF;
	//               #nIndex += 1;
	//           END_WHILE;
	//       ELSE //Wenn FIFO leer z.B. wegen Cancel, dann verschwinden hier die Missing Bits
	//           #arReq[1].xMissingBT := FALSE;
	//           #arReq[2].xMissingBT := FALSE;
	//           #arReq[3].xMissingBT := FALSE;
	//           #arReq[4].xMissingBT := FALSE;
	//           #arReq[5].xMissingBT := FALSE;
	//           #arReq[6].xMissingBT := FALSE;
	//       END_IF; *)
	    
	// END_REGION
	
	// REGION WrongDirection Handling
	    
	//     (*  IF #fbSwitch1.xOutBtLeftSwitchWrongDir THEN
	//           #xWrongDirDetect := TRUE;
	//       ELSIF #fbSwitch1.stOutMainTro.xFifoEmpty OR #stActRequest.xCancelled THEN
	//           #xWrongDirDetect := FALSE;
	//       END_IF;
	//       
	//       IF #xWrongDirDetect THEN
	//           #nIndex := 1;
	//           WHILE #nIndex <= 6 DO
	//               IF #fbSwitch1.arOutFifo[#nIndex] > 0 AND #fbSwitch1.arOutFifo[#nIndex] <= 6 THEN
	//                   #arReq[#fbSwitch1.arOutFifo[#nIndex]].xWrongDirection := TRUE;
	//               ELSE
	//                   #nIndex += 1;
	//               END_IF;
	//               #nIndex += 1;
	//           END_WHILE;
	//       ELSE
	//           #arReq[1].xWrongDirection := FALSE;
	//           #arReq[2].xWrongDirection := FALSE;
	//           #arReq[3].xWrongDirection := FALSE;
	//           #arReq[4].xWrongDirection := FALSE;
	//           #arReq[5].xWrongDirection := FALSE;
	//           #arReq[6].xWrongDirection := FALSE;
	//       END_IF; *)
	    
	// END_REGION
	
	// REGION HMI
	//     #stInOutHMI.UDT_Config.nTroType := 4; //1Sep
	    
	//     #stInOutHMI.UDT_State.nState := #nState;
	//     #stInOutHMI.UDT_State.sState := #sStateText;
	    
	//     #stInOutHMI.UDT_State.xError := // Error TRO ->
	//     #fbSeparator1.wOutErrorWord > 0 OR // Error Separator
	//     #stInOutHMI.UDT_Separator1.stStatus.bStatus = 2 OR //Error Separator
	//     #wErrorWord1.%X5 OR //Belegung ohne Daten
	//     #wErrorWord1.%X10 OR  // Carrier kommt nicht an 
	//     #stInOutHMI.UDT_BarcodeReader1.bStatus = 2 OR  //Error Reader
	    
	//     #fbSeparator2.wOutErrorWord > 0 OR // Error Separator
	//     #stInOutHMI.UDT_Separator2.stStatus.bStatus = 2 OR //Error Separator
	//     #wErrorWord2.%X5 OR //Belegung ohne Daten
	//     #wErrorWord2.%X10 OR  // Carrier kommt nicht an 
	//     #stInOutHMI.UDT_BarcodeReader2.bStatus = 2;  //Error Reader
	//     //Switch...
	// END_REGION
	
	// REGION Ausgänge schreiben
	    
	//     REGION Output
	//         #xOutCorrection := #xTmpCorrection;
	//         #xOutBookedDir1 := #xBookedDir1;
	//         #xOutBookedDir2 := #xBookedDir2;
	//         #xOutBookedDir3 := #xBookedDir3;
	//         #xOutBookedDir4 := #xBookedDir4;
	//         #stOutLastCarrier := #stTempCarrier;
	        
	//         #xOutStopper1 := #fbSeparator1.xOutStopper;
	//         #xOutStopper2 := #fbSeparator2.xOutStopper;
	//         #xOutSw1EntrTo1 := #fbSwitch1.xOutSwEntrTo1;
	//         #xOutSw1EntrTo2 := #fbSwitch1.xOutSwEntrTo2;
	//         #xOutSw1ExTo3 := #fbSwitch1.xOutSwExTo3;
	//         #xOutSw1ExTo4 := #fbSwitch1.#xOutSwExTo4;
	//         #xOutJamAtEntry1 := #fbSeparator1.stOutMainTro.xJamAtEntry;
	//         #xOutJamAtEntry2 := #fbSeparator2.stOutMainTro.xJamAtEntry;
	//         #xOutCarouselReq1 := (#nState >= #c1500_StepReleaseSep1) AND (#nState <= #c2500_StepReleaseSep2) AND NOT #stInOutHMI.UDT_Ctrl.xPause AND NOT #xInAreaStopActive;
	//         #xOutCarouselReq2 := #xOutCarouselReq1 AND
	//         ((#stInSettings.xCar2NecLeft AND (#stActRequest.nDirection = 1 OR #stActRequest.nDirection = 3)) OR
	//         (#stInSettings.xCar2NecRight AND (#stActRequest.nDirection = 2 OR #stActRequest.nDirection = 4)));
	//     END_REGION
	    
	// END_REGION
	
	// REGION Letzten Schritt wegschreiben
	//     #nOutStateLast := #fbStateManager.nStateLast;
	// END_REGION
	
	// REGION Priority Manager
	//     #stOutPriorityManagerDir1.nTroId := #nInMainTroNo;
	//     #stOutPriorityManagerDir1.stJamExit := #stInOutJamExit2;
	//     // #stOutPriorityManagerDir1.stJamEntry := ; todo
	//     #stOutPriorityManagerDir1.stSensor := #stInSeparator1.stSenInSep;
	//     #stOutPriorityManagerDir1.xMovement := #xInCarouselRun1 AND #xInCarouselRun2;
	//     //#stOutPriorityManagerDir1.xTrolleyPresent := ; // todo für mengengesteuert
	    
	//     #stOutPriorityManagerDir2.nTroId := #nInMainTroNo;
	//     #stOutPriorityManagerDir2.stJamExit := #stInOutJamExit3;
	//     // #stOutPriorityManagerDir2.stJamEntry := ; todo
	//     #stOutPriorityManagerDir2.stSensor := #stInSeparator1.stSenInSep;
	//     #stOutPriorityManagerDir2.xMovement := #xInCarouselRun1 AND #xInCarouselRun2;
	//     //#stOutPriorityManagerDir2.xTrolleyPresent := ; // todo für mengengesteuert
	    
	//     #stOutPriorityManagerDir3.nTroId := #nInMainTroNo;
	//     #stOutPriorityManagerDir3.stJamExit := #stInOutJamExit2;
	//     // #stOutPriorityManagerDir3.stJamEntry := ; todo
	//     #stOutPriorityManagerDir3.stSensor := #stInSeparator2.stSenInSep;
	//     #stOutPriorityManagerDir3.xMovement := #xInCarouselRun1 AND #xInCarouselRun2;
	//     //#stOutPriorityManagerDir3.xTrolleyPresent := ; // todo für mengengesteuert
	    
	//     #stOutPriorityManagerDir4.nTroId := #nInMainTroNo;
	//     #stOutPriorityManagerDir4.stJamExit := #stInOutJamExit3;
	//     // #stOutPriorityManagerDir4.stJamEntry := ; todo
	//     #stOutPriorityManagerDir4.stSensor := #stInSeparator2.stSenInSep;
	//     #stOutPriorityManagerDir4.xMovement := #xInCarouselRun1 AND #xInCarouselRun2;
	//     //#stOutPriorityManagerDir4.xTrolleyPresent := ; // todo für mengengesteuert
	    
	//     IF #stInSettings.xPrioDir1 THEN
	//         #stOutPriorityManagerDir1.xTransportReq := (#stActRequest.nDirection = 1) AND #nState = #c2500_StepReleaseSep2;
	//     END_IF;
	    
	//     IF #stInSettings.xPrioDir2 THEN
	//         #stOutPriorityManagerDir2.xTransportReq := (#stActRequest.nDirection = 2) AND #nState = #c2500_StepReleaseSep2;
	//     END_IF;
	    
	//     IF #stInSettings.xPrioDir3 THEN
	//         #stOutPriorityManagerDir3.xTransportReq := (#stActRequest.nDirection = 3) AND #nState = #c2500_StepReleaseSep2;
	//     END_IF;
	    
	//     IF #stInSettings.xPrioDir4 THEN
	//         #stOutPriorityManagerDir4.xTransportReq := (#stActRequest.nDirection = 4) AND #nState = #c2500_StepReleaseSep2;
	//     END_IF;
	// END_REGION
END_FUNCTION_BLOCK

