FUNCTION_BLOCK "MHMOmniSchleuse"
TITLE = HM-Omni-Schleuse (Schrittkette)
{ S7_Optimized_Access := 'FALSE' }
AUTHOR : IBAE
FAMILY : Module
NAME : MHMOmni
VERSION : 0.1
//SCL-Portierung des AWL-Bausteins FB1274 "MHMOmniSchleuse" (verhaltensgleich).
//Statische Daten (SAVE/Para/Status2/Schleuse/Dyn) sind unveraendert -> Instanz-DBs bleiben gueltig.
//
//ABWEICHUNGEN ZUM AWL-ORIGINAL (bei Inbetriebnahme pruefen!):
//  - DatenOut-Aufrufe verwenden lokale Puffer statt der Merker-Scratch-Bereiche
//    MW200/M220../MB199/MW196 (Ergebnis identisch, keine Nebenwirkung auf Merker).
//    Die Merker-Schnittstelle zu den indirekten FCs (MW190..MW198, MD182, MD192,
//    M180.x) und die Fehler-Schnittstelle MW200/M200.x/M201.x bleiben erhalten.
//  - Erfolg von "DatenOut" wird ueber RE_VAL Bit7 statt BR/JBI erkannt
//    (bei PARA=0-Suchen aequivalent).
//  - Indirekte Aufrufe UC FC[LeserFC/ZielFC/DraussenFC] sind als CASE ueber die
//    projektierten FC-Nummern ausgefuehrt (Station UH06).
//  - Registerindirekte Zugriffe auf Weichen-/Leser-DB sind durch PEEK/POKE ersetzt.
//  - NW21 ("Schrittkette anhalten") ist im Original durch CLR+JU deaktiviert -> entfaellt.
//  - NW10-Schritt "NoLesung": das AWL verglich HMI.TrolleyID_Input mit einem
//    undefinierten Akku-Altwert; hier wird die beabsichtigte Pruefung
//    (TrolleyID_Input <> 0) verwendet. VERHALTEN PRUEFEN!
   VAR_INPUT 
      Schleusen_Nr : Int;   // Aufruf fuer Schleuse
      ErrQuit : Bool;   // Ablaufstoerung quittieren
      B_VorSchleuse : Bool;   // Sensor Trolley faehrt in Bereich
      B_InSchleuse : Bool;   // Sensor Trolley ist in Schleuse
      B_AusSchleuse : Bool;   // Sensor Trolley hat Schleuse verlassen
      B_Stau_raus : Bool;   // Sensor Stau im Bereich rausfahren
      Start_Ok : Bool;   // Starten ist erlaubt
      Antrieb_Schleuse_aktiv : Bool;   // Kreisel-Antrieb aktiv
      Antrieb_plus_aktiv : Bool;   // Kreisel-Antrieb plus aktiv
      Schleuse_geöffnet : Bool;   // Schleuse hat geoeffnet
      RestZeit_Bereich_plus : Int := 999;   // Bereich +1: Restzeit bis AFS stoppt (s)
   END_VAR

   VAR_OUTPUT 
      Y_Schleuse_Auf : Bool;   // Schleuse oeffnen
      Error : Word;   // Stoerungen uebergeben
   END_VAR

   VAR_IN_OUT 
      Antrieb_Schleuse_vor : Bool;   // Schleusen-Antrieb einschalten
      Antrieb_Schleuse_start : Bool;   // Schleusen-Antrieb mit Zeit starten
      Antrieb_Schleuse_stop : Bool;   // Schleusen-Antrieb stoppen
      Antrieb_Schleuse_PS : Bool;   // Schleusen-Antrieb Energie sparen
      Antrieb_plus_vor : Bool;   // Antrieb plus einschalten
      Antrieb_plus_start : Bool;   // Antrieb plus mit Zeit starten
      hStOk : Bool;   // Anzeige Start n. Stoerung aktivieren
   END_VAR

   VAR 
      SAVE : Struct
         Weichen_DB : Int;   // Weichen-FIFO-DB
         Weichen_DW : Int;   // Weichen-FIFO-DW
         "Weiche+1" : Int;   // Weiche +1, wo reserviert wurde
         Frei18 : Int;
         Frei20 : Int;
      END_STRUCT;
      Para : Struct   // Parameter
         Schleusen_DL_DB : Int;   // Einsprung Schleuse-Datenliste-DB
         Weichen_DL_DB : Int;   // Einsprung Weichen-Datenliste-DB
         Leser_DL_DB : Int;   // Einsprung Leser-Datenliste-DB
      END_STRUCT;
      Status2 : Struct
         Trolley_an_Schleuse : Bool;   // Trolley ist an Schleuse
         "Warten_3.V" : Bool;   // Warten auf 3.V
         "2.Lesung_aktiv" : Bool;   // 2.Lesung erfolgt
         "3.Lesung_aktiv" : Bool;   // 3.Lesung erfolgt
         TrolleyPos_übergeben : Bool;   // Trolley-Pos. uebergeben
         "Warten_4.V" : Bool;   // Warten auf 4.V
         Ausfahrzeit_lernen : Bool;   // Ausfahrzeit lernen
         "Weichen-Schritt" : Bool;   // Schritt 13-17 aktiv (Weiche evtl. belegen)
         Trolley_ist_draussen : Bool;   // Rueckmeldung von Sensor / Weiche
         Einfahrzeit_lernen : Bool;   // Einfahrzeit lernen
         Telegramm_gesendet : Bool;   // Telegramm wurde in Send-FIFO eingetragen
      END_STRUCT;
      Schleuse : "UDLHMOmniSchleuse";   // Statische Schleusendaten (aus DL)
      Dyn : Struct   // Dynamische Daten
         Status : Struct
            Trolley_fährt_in_Schleuse : Bool;   // Trolley faehrt in Schleuse
            Trolley_wartet_Lesung : Bool;   // Trolley wartet auf Auftrag
            "Trolley_wartet_auf_Ziel-FC" : Bool;
            "Trolley_wartet_auf_Weiche+1" : Bool;
            "Trolley_wartet_Bereich+1" : Bool;   // Trolley wartet auf Bereich +1
            Trolley_fährt_aus : Bool;   // Trolley faehrt aus
            MindestZeit_ok : Bool;   // Schleuse ist MindestZeit geoeffnet
            Trolley_draussen : Bool;   // Trolley ist ausgefahren
            Leser_triggern : Bool;
            SF_angefordert : Bool;
            Kein_Stop_mehr : Bool;   // Kein Stop mehr, Antrieb soll starten
            Trolley_fährt_rückwärts : Bool;   // Trolley in Schleuse rueckwaerts erkannt
            Weiche_geschaltet : Bool;
            "Trolley ausserhalb Weiche" : Bool;   // Trolley hat Weiche verlassen (von Weiche)
            Error_aktiv : Bool;   // Stoerung vorhanden
            Reset_aktiv : Bool := TRUE;   // Reset aktiv
         END_STRUCT;
         TrolleyID_Schleuse : DInt;   // Trolley-Nr in der Schleuse
         Trolley_EndZiel : Word;   // Trolley-EndZiel
         Trolley_ZwischenZiel : Word;   // Trolley-ZwischenZiel
         Trolley_ShopGroup : DInt;   // Trolley-ShopGroup
         Weichen_Ziel : Word;   // Weichen-Ziel (fuer WeichenModul von Ziel-FC)
         TrolleyID_Eingefahren : DInt;   // Trolley-Nr von Bereich -1 gemeldet
         TrolleyID_ausgefahren : DInt;   // TrolleyID des ausgefahrenen Trolleys
         HMI : Struct
            TrolleyID_in_Schleuse : DInt;   // Trolley-Nr in Schleuse (IN:PLC, OUT:PLC)
            TrolleyID_Input : DInt;   // Trolley-Nr Input (IN:HMI, OUT:PLC)
            Schleuse_resetten : Bool;   // Schleuse resetten (IN:HMI, Out:PLC)
         END_STRUCT;
         Sk : "USk_ILS";   // Status der Schrittkette
         Leser : Struct
            IN : Struct
               xOutReadyForNewScan : Bool;   // DBX10.1: Reader ist bereit fuer Leseanforderung
               xOutReadingDone : Bool;   // DBX10.0: Lesevorgang abgeschlossen / Handshake raus
               xOutCodeGood : Bool;   // DBX278.0: Gute Lesung
               xOutCodeBad : Bool;   // DBX278.1: Schlechte Lesung
               nOutBarcode : DInt;   // DBD12: Trolley ID
            END_STRUCT;
            OUT : Struct
               xInStartReading : Bool;   // DBX4.1: Starte Lesevorgang
               xInHandshakeDone : Bool;   // DBX4.2: Handshake Daten abgeholt
               xInErrQuit : Bool;   // DBX4.4: Fehler ruecksetzen
               xInReset : Bool;   // DBX4.5: Allgemeines Ruecksetzen des Bausteins
            END_STRUCT;
         END_STRUCT;
         TrolleyID_unbekannt_Schleuse : DInt;   // TrolleyID unbekannt (Trolley in Schleuse)
         Rueckmld : Struct
            RET_VAL_BLKMOV_Schleuse : Int;   // Rueckmeldung nach BLKMOV-Aufruf
            RET_VAL_DL_Schleuse : Byte;
            RET_VAL_DL_Weiche : Byte;   // Rueckmeldung nach DatenOut-Aufruf
            RET_VAL_DL_Leser : Byte;   // Rueckmeldung nach DatenOut-Aufruf
         END_STRUCT;
         Error : "UErrHMOmniSchleuse";
         Stau_Zeit : Int;   // Sensor B_VorSep ist belegt [100ms]
         Mindest_Zeit : Int;   // Sensor B_VorSep ist frei [100ms]
         Leer_Zeit : Int;
         Stop_Ursache : Word;   // Stop-Stelle: Nw + Position
         Vereinzelungstakte : DInt;   // Anzahl der getaetigten Vereinzelungstakte
         ZwischenZiel_eingefahren : Word;   // Trolley-ZwischenZiel von Bereich -1
         Ohne_B : Int;
         SAVE2 : Struct
            Leser_DB : Int;   // Leser-FIFO-DB
            Leser_DD : DInt;   // Leser-FIFO-DD
         END_STRUCT;
         WarteZeit_PS : Int;
         Restzeit_bis_Schleuse : Int;
         Res200 : Array[1..16] of Int;   // Reserve
      END_STRUCT;
   END_VAR

   VAR_TEMP 
      Ueb_akt : Bool;   // Ueberwachungszeit aktivieren
      Weiter : Bool;   // Weiterschaltbedingung ist erfuellt
      Warte_neu : Bool;   // Wartezeit neu triggern
      Warte_stop : Bool;   // Wartezeit stoppen
      "Kein_Weichenbereich +1" : Bool;
      "Reservierung_Weiche+1_aktiv" : Bool;
      Leser_Zugriff : Bool;   // Leser-Zugriff vorhanden
      LeserFC_vorhanden : Bool;
      ZielFC_vorhanden : Bool;
      DraussenFC_vorhanden : Bool;
      "TrolleyID_Bereich-1" : Bool;   // Trolley-ID von Bereich -1 gemeldet
      Einfahrzeit_nicht_bekannt : Bool;
      LeserFC : Int;   // Leser-FC
      ZielFC : Int;   // Ziel-FC
      DraussenFC : Int;   // Draussen-FC
      tReVal : Byte;   // Rueckmeldung DatenOut (statt MB199)
      tPosition : Int;   // Position von DatenOut (statt MW196)
      tSuchInt : Int;   // Suchdaten 1 Wort (statt MW200)
      tSuchID : DInt;   // Suchdaten TrolleyID (statt MD220)
      tOutDaten : Array[0..19] of Word;   // OutDaten-Puffer (statt M220..)
      tByte : Byte;   // Byte-Zwischenwert (statt MB200-Scratch)
      tNeuSchritt : Int;   // Uebergabe an Neu_Mig
      tWartezeit : Int;   // Uebergabe an Plus (*10ms)
      tUebzeit : Int;   // Uebergabe an tueb (*1s)
      tWeichDb : DInt;   // Weichen-DB fuer PEEK/POKE
      tWeichBase : DInt;   // Weichen-DW Basisoffset
      tLeserDb : DInt;   // Leser-DB fuer PEEK/POKE
      tLeserBase : DInt;   // Leser-DD Basisoffset
   END_VAR


BEGIN
	   REGION NW1: Parameter-Uebergabe
	       #Para.Schleusen_DL_DB := 274;   // Einsprung Schleuse-DL (vor Aufruf uebergeben!)
	       #Para.Weichen_DL_DB := 279;   // Einsprung Weichen-DL
	       #Para.Leser_DL_DB := 273;   // Einsprung Leser-DL
	   END_REGION
	
	   REGION NW2: Anzeige OP
	       IF #ErrQuit THEN
	           #Dyn.Sk.Err_Uebzeit := FALSE;   // Ueberwachungszeit abgelaufen quittieren
	       END_IF;
	
	       IF NOT #Dyn.Sk.Bereich_ok THEN
	           #Dyn.Sk.OP_Schritt := 252;   // Bereichsstop / Not-Aus
	       ELSIF NOT #Dyn.Sk.Auto_akt AND NOT #Dyn.Sk.Hand_akt THEN
	           #Dyn.Sk.OP_Schritt := 253;   // Keine Betriebsart
	       ELSIF #Dyn.Sk.Hand_akt THEN
	           #Dyn.Sk.OP_Schritt := 255;   // Handbetrieb aktiv
	       ELSE
	           #Dyn.Sk.OP_Schritt := #Dyn.Sk.Akt_Schritt;   // Aktiver Schritt
	       END_IF;
	   END_REGION
	
	   REGION NW3: Out-Bits zum Zuruecksetzen (jeden Zyklus neu)
	       #Y_Schleuse_Auf := FALSE;
	       #Dyn.Status.Trolley_wartet_Lesung := FALSE;
	       #Dyn.Status."Trolley_wartet_auf_Ziel-FC" := FALSE;
	       #Dyn.Status."Trolley_wartet_auf_Weiche+1" := FALSE;
	       #Dyn.Status."Trolley_wartet_Bereich+1" := FALSE;
	       #Dyn.Status."Trolley_fährt_aus" := FALSE;
	       #Dyn.Status.Trolley_draussen := FALSE;
	       #Leser_Zugriff := FALSE;
	       #Status2."Weichen-Schritt" := FALSE;
	
	       #Dyn.Status.Reset_aktiv := #Dyn.Sk.Reset_Akt;
	   END_REGION
	
	   REGION NW4: HMI-Zeug
	       IF #Dyn.HMI.Schleuse_resetten THEN   // von HMI
	           #Dyn.HMI.Schleuse_resetten := FALSE;
	           #Dyn.Sk.Reset := TRUE;   // SK zuruecksetzen
	       END_IF;
	
	       #Dyn.HMI.TrolleyID_in_Schleuse := #Dyn.TrolleyID_Schleuse;   // an HMI
	   END_REGION
	
	   REGION NW5: Schrittkette zuruecksetzen
	       IF #ErrQuit THEN
	           #Dyn.Sk.Err_Uebzeit := FALSE;
	       END_IF;
	
	       IF #Dyn.Sk.Reset THEN   // SK zuruecksetzen
	           #Dyn.Sk.Akt_Schritt := 0;   // Schritt 0: Warten
	           #Dyn.Sk.Terr_Zelle := 0;   // Zeitwerte loeschen
	           #Dyn.Sk.Tok_Zelle := 0;
	
	           #Dyn.Error.Err_BLKMov := FALSE;
	           #Dyn.Sk.Reset := FALSE;
	           #Dyn.Sk.Err_Schritt := FALSE;
	           #Dyn.Sk.Err_Uebzeit := FALSE;
	           #Status2.Telegramm_gesendet := FALSE;
	           #Dyn.Sk.Reset_Akt := TRUE;   // Reset ist aktiv
	
	           #Dyn.Error.Schleuse_DL := FALSE;
	           #Dyn.Error.Undef_Schleuse := FALSE;
	           #Dyn.Error.Err_Trolley_nicht_in_Schleuse := FALSE;
	           #Dyn.Error.Err_Uebzeit := FALSE;
	           #Dyn.Error.Err_Schritt := FALSE;
	           #Dyn.Error.Err_Stau_Einfahrt := FALSE;
	           #Dyn.Error.Err_Trolley_raus := FALSE;
	           #Dyn.Error.Err_Raus_Sensor := FALSE;
	           #Dyn.Error.Err_Ziel := FALSE;
	           #Dyn.Error.Err_Weichen_DL := FALSE;
	           #Dyn.Error.Err_Undef_Weiche := FALSE;
	           #Dyn.Error.Err_Weiche_belegt := FALSE;
	           #Dyn.Error.Err_Kein_LeseErgebnis := FALSE;
	           #Dyn.Error.Err_Leser_nicht_bereit := FALSE;
	
	           #Dyn.Leser."IN".nOutBarcode := 0;
	
	           #Dyn.Stau_Zeit := 0;
	           #Dyn.Mindest_Zeit := 0;
	           #SAVE."Weiche+1" := 0;
	           #SAVE.Weichen_DB := 0;
	           #SAVE.Weichen_DW := 0;
	           #Dyn.SAVE2.Leser_DB := 0;
	           #Dyn.SAVE2.Leser_DD := 0;
	
	           #Schleuse.Schleusen_Nr := 0;   // Damit statische Werte neu aus Datenbank geholt werden!
	
	           GOTO mRET;
	       END_IF;
	   END_REGION
	
	   REGION NW6: Stoerungen nach aussen uebergeben (Schnittstelle MW200)
	       "MW200" := 16#0000;
	
	       "M200.0" := #Dyn.Error.Schleuse_DL;   // Schleuse-Datenliste fehlerhaft
	       "M200.1" := #Dyn.Error.Undef_Schleuse;   // undefinierte Schleuse
	       "M200.2" := #Dyn.Error.Err_Trolley_nicht_in_Schleuse;   // Trolley faehrt nicht in Schleuse
	       #Dyn.Error.Err_Uebzeit := #Dyn.Sk.Err_Uebzeit;   // Ueberwachungszeit ist abgelaufen
	       "M200.3" := #Dyn.Sk.Err_Uebzeit;
	       IF NOT #Dyn.Sk.Err_Uebzeit THEN   // AWL: NEG + R
	           #Dyn.Sk.Err_Uebzeit_AnzOk := FALSE;
	       END_IF;
	       #Dyn.Error.Err_Schritt := #Dyn.Sk.Err_Schritt;   // Schritt-Nummer ist nicht definiert
	       "M200.4" := #Dyn.Sk.Err_Schritt;
	       "M200.5" := #Dyn.Error.Err_Stau_Einfahrt AND NOT #B_InSchleuse AND NOT #Y_Schleuse_Auf;
	       "M200.6" := #Dyn.Error.Err_BLKMov;   // Error bei Block kopieren
	       "M200.7" := #Dyn.Error.Err_Trolley_raus;   // Trolley faehrt nicht aus
	       "M201.0" := #Dyn.Error.Err_Raus_Sensor;   // Raus-/Belade-Sensor wird nicht erreicht
	       "M201.1" := #Dyn.Error.Err_Ziel;   // Trolley-Ziel nicht bekannt
	       "M201.2" := #Dyn.Error.Err_Weichen_DL;   // Weichen-Datenliste fehlerhaft
	       "M201.3" := #Dyn.Error.Err_Undef_Weiche;   // undefinierte Weiche
	       "M201.4" := #Dyn.Error.Err_Weiche_belegt;   // Weiche bleibt belegt
	       "M201.5" := #Dyn.Error.Err_Kein_LeseErgebnis;
	       "M201.6" := #Dyn.Error.Err_Leser_nicht_bereit;
	       "M201.7" := #Dyn.Error.Barcode_nicht_bekannt;
	
	       // Andere Meldung als Ueberwachungszeit aktiv?
	       IF (("MW200" AND 2#1111_0111_1111_1111) <> 16#0000)
	          OR NOT #Dyn.Sk.Err_Uebzeit_AnzOk THEN
	           "M200.3" := FALSE;   // Ueb.Zeit-Meldung nicht an PC senden
	       END_IF;
	
	       IF #Dyn.Sk.Err_Uebzeit THEN
	           #Dyn.Sk.Err_Uebzeit_AnzOk := TRUE;   // Stoerung anzeigen ok, da 2.Zyklus aktiv!
	       END_IF;
	
	       #Error := "MW200";   // Schnittstelle nach aussen
	
	       // Stoerung vorhanden:
	       #Dyn.Status.Error_aktiv := ("MW200" <> 16#0000);
	       IF #Dyn.Status.Error_aktiv THEN
	           #hStOk := TRUE;
	       END_IF;
	
	       // Antrieb stoppen:
	       IF NOT #Dyn.Sk.Auto_akt OR #Dyn.Sk.Hand_akt OR NOT #Dyn.Sk.Bereich_ok THEN
	           #Antrieb_Schleuse_stop := TRUE;   // SystemVoraussetzungen fehlen
	       END_IF;
	
	       // Stoerungen pro Zyklus neu erzeugen:
	       #Dyn.Error.Schleuse_DL := FALSE;
	       #Dyn.Error.Undef_Schleuse := FALSE;
	       #Dyn.Error.Err_Schritt := FALSE;
	       #Dyn.Error.Err_BLKMov := FALSE;
	       #Dyn.Error.Err_Raus_Sensor := FALSE;
	       #Dyn.Error.Err_Ziel := FALSE;
	       #Dyn.Error.Err_Weichen_DL := FALSE;
	       #Dyn.Error.Err_Undef_Weiche := FALSE;
	       #Dyn.Error.Err_Weiche_belegt := FALSE;
	       #Dyn.Error.Barcode_nicht_bekannt := FALSE;
	
	       IF NOT #Dyn.Sk.Err_Uebzeit THEN
	           #Dyn.Error.Err_Trolley_nicht_in_Schleuse := FALSE;
	           #Dyn.Error.Err_Trolley_raus := FALSE;
	           #Dyn.Error.Err_Raus_Sensor := FALSE;
	       END_IF;
	   END_REGION
	
	   REGION NW7: Statische Schleusen-Parameter holen
	       IF #Schleuse.Schleusen_Nr = #Schleusen_Nr THEN   // schon geholt
	           #Dyn.Error.Schleuse_DL := FALSE;
	           #Dyn.Error.Undef_Schleuse := FALSE;
	       ELSE
	           #tSuchInt := #Schleusen_Nr;   // Search-Daten (AWL: MW200)
	           "DatenOut"(SSDB := #Para.Schleusen_DL_DB,
	                      SSDW := 0,
	                      PARA := WORD#16#0000,
	                      SEARCHDATEN := #tSuchInt,
	                      RE_VAL => #tReVal,
	                      Position => #tPosition,
	                      OUTDATEN := #Schleuse);   // Datensatz direkt in Schleuse-Struktur
	
	           #Dyn.Rueckmld.RET_VAL_DL_Schleuse := #tReVal;
	
	           IF #tReVal.%X7 THEN   // AWL: JBI G_Ok (Datensatz gefunden)
	               #Dyn.Error.Schleuse_DL := FALSE;
	               #Dyn.Error.Undef_Schleuse := FALSE;
	               #Dyn.Rueckmld.RET_VAL_BLKMOV_Schleuse := 0;   // kein BLKMOV mehr noetig
	               #Dyn.Error.Err_BLKMov := FALSE;
	               #Dyn.Stop_Ursache := 16#A063;
	
	               IF #Schleuse.Schleusen_Typ <> 1274 THEN   // Dieser Aufruf-FB?
	                   #Dyn.Error.Undef_Schleuse := TRUE;   // undefinierte Schleuse
	                   #Schleuse.Schleusen_Nr := 0;   // Schleuse ungueltig!
	                   #Dyn.Stop_Ursache := 16#A064;
	               END_IF;
	           ELSIF #tReVal.%X0 THEN   // kein Datenlisten-Bereich
	               #Dyn.Error.Schleuse_DL := TRUE;   // Schleusendatenbank fehlerhaft
	               #Dyn.Stop_Ursache := 16#A061;
	           ELSE
	               #Dyn.Error.Undef_Schleuse := TRUE;   // undefinierte Schleuse
	               #Dyn.Stop_Ursache := 16#A062;
	           END_IF;
	           GOTO mRET;   // in diesem Zyklus keine Schrittkette
	       END_IF;
	   END_REGION
	
	   REGION NW8: Einsprung Weiche plus ermitteln
	       IF #SAVE.Weichen_DB > 0 THEN   // Einsprung-Zeiger bekannt
	           #"Kein_Weichenbereich +1" := FALSE;
	       ELSE
	           #"Kein_Weichenbereich +1" := (#Schleuse.RausWeichen_Nr = 0);
	           IF #"Kein_Weichenbereich +1" THEN
	               #Dyn.Error.Err_Undef_Weiche := FALSE;   // keine Weiche projektiert
	           ELSE
	               #tSuchInt := #Schleuse.RausWeichen_Nr;   // Search-Daten
	               "DatenOut"(SSDB := #Para.Weichen_DL_DB,
	                          SSDW := 0,
	                          PARA := WORD#16#0000,
	                          SEARCHDATEN := #tSuchInt,
	                          RE_VAL => #tReVal,
	                          Position => #tPosition,
	                          OUTDATEN := #tOutDaten);
	
	               #Dyn.Rueckmld.RET_VAL_DL_Weiche := #tReVal;
	
	               IF #tReVal.%X7 THEN   // AWL: JBI W_Ok
	                   #SAVE.Weichen_DB := WORD_TO_INT(#tOutDaten[2]);   // (AWL: MW224)
	                   IF #SAVE.Weichen_DB <= 0 THEN   // sinnvoller Wert?
	                       #Dyn.Error.Err_Undef_Weiche := TRUE;   // undefinierte Weiche
	                   ELSE
	                       #SAVE.Weichen_DW := WORD_TO_INT(#tOutDaten[3]);   // (AWL: MW226)
	                   END_IF;
	               ELSE
	                   #Dyn.Error.Err_Weichen_DL := #tReVal.%X0;   // Weichen-Datenliste fehlerhaft
	                   IF NOT #tReVal.%X0 THEN
	                       #Dyn.Error.Err_Undef_Weiche := TRUE;   // undefinierte Weiche
	                   END_IF;
	               END_IF;
	           END_IF;
	       END_IF;
	   END_REGION
	
	   REGION NW9: Trolley in Schleuse entprellen
	       IF #B_InSchleuse THEN
	           #Dyn.Ohne_B := 0;
	       ELSIF #Status2.Trolley_an_Schleuse AND "1s-Impuls" THEN
	           #Dyn.Ohne_B := #Dyn.Ohne_B + 1;   // Zeit ohne Sensor +1s
	           IF #Dyn.Ohne_B >= 3 THEN   // Nach ca. 3s
	               #Status2.Trolley_an_Schleuse := FALSE;
	               #Dyn.Ohne_B := 0;
	           END_IF;
	       END_IF;
	   END_REGION
	
	   REGION NW10: Antrieb zusaetzlich starten / stoppen / Schleuse geoeffnet
	       IF #ErrQuit OR #"Schleuse_geöffnet" THEN
	           #Antrieb_Schleuse_start := TRUE;   // Antrieb starten
	           #Antrieb_plus_start := TRUE;   // Kreisel-Antrieb plus starten
	       END_IF;
	
	       IF #"Schleuse_geöffnet" THEN
	           #Dyn.Status."Trolley_fährt_in_Schleuse" := FALSE;
	       END_IF;
	
	       IF #"Schleuse_geöffnet"
	          AND (#Dyn.Status.Weiche_geschaltet OR #"Kein_Weichenbereich +1")
	          AND #Schleuse.Parameter_allg.Antrieb_Plus_vorhanden THEN
	           #Antrieb_plus_vor := TRUE;   // Antrieb plus einschalten
	       END_IF;
	
	       IF #"Schleuse_geöffnet"
	          AND (#Dyn.Status.Weiche_geschaltet OR #"Kein_Weichenbereich +1")
	          AND (#Antrieb_plus_aktiv OR NOT #Schleuse.Parameter_allg.Antrieb_Plus_vorhanden) THEN
	           #Antrieb_Schleuse_vor := TRUE;   // Antrieb einschalten
	       END_IF;
	
	       // Trolley ist in Schleuse und wartet -> Energiesparen nach ca. 3s
	       IF (#Status2.Trolley_an_Schleuse AND NOT #"Schleuse_geöffnet"
	           AND (NOT #B_VorSchleuse OR #Dyn.Error.Err_Stau_Einfahrt)
	           AND NOT #Dyn.Status.Kein_Stop_mehr)
	          OR (#"Schleuse_geöffnet"
	              AND #Schleuse.Parameter_allg.Antrieb_Plus_vorhanden
	              AND NOT #Antrieb_plus_aktiv) THEN
	           IF #Dyn.WarteZeit_PS < 3 THEN   // ca. 3s rum?
	               IF "1s-Impuls" THEN
	                   #Dyn.WarteZeit_PS := #Dyn.WarteZeit_PS + 1;
	               END_IF;
	           ELSE
	               #Antrieb_Schleuse_PS := TRUE;   // Antrieb in Energiesparen schalten
	           END_IF;
	       ELSE
	           #Dyn.WarteZeit_PS := 0;
	       END_IF;
	   END_REGION
	
	   REGION NW11: Einfahrzeit lernen
	       #Einfahrzeit_nicht_bekannt := (#Schleuse.EinfahrZeit = 0) OR #Status2.Einfahrzeit_lernen;
	
	       IF #Einfahrzeit_nicht_bekannt AND #B_VorSchleuse AND #Antrieb_Schleuse_aktiv
	          AND NOT #B_InSchleuse AND NOT #"Schleuse_geöffnet" THEN
	           #Status2.Einfahrzeit_lernen := TRUE;
	       END_IF;
	
	       IF #B_InSchleuse AND NOT #"Schleuse_geöffnet" THEN
	           #Status2.Einfahrzeit_lernen := FALSE;
	       END_IF;
	
	       IF #Status2.Einfahrzeit_lernen THEN
	           #Antrieb_Schleuse_vor := TRUE;   // Antrieb einschalten
	       END_IF;
	
	       IF #Status2.Einfahrzeit_lernen AND #Antrieb_Schleuse_aktiv AND "1s-Impuls" THEN
	           #Schleuse.EinfahrZeit := #Schleuse.EinfahrZeit + 1;
	       END_IF;
	   END_REGION
	
	   REGION NW12: PS deaktivieren, da Trolley einfaehrt
	       IF NOT #Einfahrzeit_nicht_bekannt THEN   // also bekannt
	           IF #B_VorSchleuse THEN   // Neuer Trolley faehrt ein
	               #Dyn.Restzeit_bis_Schleuse := #Schleuse.EinfahrZeit;
	           END_IF;
	
	           // Restzeit zurueckzaehlen:
	           IF #Antrieb_Schleuse_aktiv AND NOT #"Schleuse_geöffnet" AND "1s-Impuls" THEN
	               #Dyn.Restzeit_bis_Schleuse := #Dyn.Restzeit_bis_Schleuse - 1;
	               IF #Dyn.Restzeit_bis_Schleuse <= 0 THEN
	                   #Dyn.Restzeit_bis_Schleuse := 0;   // Minimum uebergeben
	               END_IF;
	           END_IF;
	
	           // Trolley faehrt noch ein:
	           IF (#Dyn.Restzeit_bis_Schleuse > 0) AND NOT #B_InSchleuse AND NOT #"Schleuse_geöffnet" THEN
	               #Antrieb_Schleuse_vor := TRUE;   // dadurch wird PS-Modus deaktiviert
	           END_IF;
	       END_IF;
	   END_REGION
	
	   REGION NW13: Ausfahrzeit lernen
	       IF #Status2.Ausfahrzeit_lernen AND #Antrieb_Schleuse_aktiv AND "1s-Impuls" THEN
	           #Schleuse.AusfahrZeit := #Schleuse.AusfahrZeit + 1;
	       END_IF;
	   END_REGION
	
	   REGION NW14: Spezial-FCs vorhanden?
	       #LeserFC := #Schleuse.Leser_FC;
	       #LeserFC_vorhanden := (#LeserFC > 0);
	
	       #ZielFC := #Schleuse.Ziel_FC;
	       #ZielFC_vorhanden := (#ZielFC > 0);
	
	       #DraussenFC := #Schleuse.Draussen_FC;
	       #DraussenFC_vorhanden := (#DraussenFC > 0);
	   END_REGION
	
	   REGION NW15: Error: Stau Bereich-Eingang
	       // TrolleyID zum Einfahren gemeldet / Trolley faehrt in Bereich:
	       #"TrolleyID_Bereich-1" := (#Dyn.TrolleyID_Eingefahren <> 0);
	       IF #"TrolleyID_Bereich-1" OR #B_VorSchleuse THEN
	           #Dyn.Status."Trolley_fährt_in_Schleuse" := TRUE;
	       END_IF;
	
	       // Antrieb einschalten:
	       IF #B_VorSchleuse AND NOT #B_InSchleuse AND NOT #"Schleuse_geöffnet" THEN
	           #Antrieb_Schleuse_vor := TRUE;
	       END_IF;
	       IF #B_VorSchleuse THEN
	           #Antrieb_Schleuse_start := TRUE;
	       END_IF;
	
	       // Sensor bei Bereichs-Einfahrt bleibt belegt?
	       IF NOT #B_VorSchleuse OR #"Schleuse_geöffnet" THEN
	           #Dyn.Error.Err_Stau_Einfahrt := FALSE;
	           #Dyn.Stau_Zeit := 0;   // StauZeit neu aufziehen
	       ELSIF "1s-Impuls"
	             AND NOT (#Schleuse.Parameter_allg.Antrieb_vorhanden AND NOT #Antrieb_Schleuse_aktiv)
	             AND NOT #Dyn.Error.Err_Stau_Einfahrt THEN
	           #Dyn.Stau_Zeit := #Dyn.Stau_Zeit + 1;   // Sensor B_VorSep ist belegt [1s]
	           IF #Dyn.Stau_Zeit >= 20 THEN   // Stau-Zeit erreicht?
	               #Dyn.Error.Err_Stau_Einfahrt := TRUE;   // Stau bei Einfahrt
	               #Dyn.Stau_Zeit := 0;
	           END_IF;
	       END_IF;
	   END_REGION
	
	   REGION NW16: Schleuse Mindestzeit geoeffnet/frei
	       IF (#Dyn.Sk.Akt_Schritt < 3) OR (#Dyn.Sk.Akt_Schritt > 6) OR NOT #"Schleuse_geöffnet" THEN
	           #Dyn.Status.MindestZeit_ok := FALSE;
	           #Dyn.Mindest_Zeit := 0;   // FreiZeit neu aufziehen
	       ELSIF NOT ((#Schleuse.Parameter_allg.Antrieb_vorhanden AND NOT #Antrieb_Schleuse_aktiv)
	                  OR (#Schleuse.Parameter_allg.Antrieb_Plus_vorhanden AND NOT #Antrieb_plus_aktiv)
	                  OR #Dyn.Status.MindestZeit_ok
	                  OR NOT "1s-Impuls") THEN
	           #Dyn.Mindest_Zeit := #Dyn.Mindest_Zeit + 1;
	           IF #Dyn.Mindest_Zeit >= #Schleuse.Mindeszeit_Schleuse_geoeffnet THEN   // Mindest-Zeit erreicht?
	               #Dyn.Status.MindestZeit_ok := TRUE;
	               #Dyn.Mindest_Zeit := 0;
	           END_IF;
	       END_IF;
	   END_REGION
	
	   REGION NW17: Schleuse: Trolley ist draussen (Sensor/Weiche)
	       IF (#Dyn.Sk.Akt_Schritt < 5) OR (#Dyn.Sk.Akt_Schritt > 6) OR NOT #"Schleuse_geöffnet" THEN
	           #Status2.Trolley_ist_draussen := FALSE;
	           #Status2.Ausfahrzeit_lernen := FALSE;
	       ELSE
	           // Trolley ist draussen sofort (Rueckmeldung von Sensor/Weiche):
	           IF (#B_AusSchleuse AND #Schleuse.Parameter_allg.B_AusSep_vorhanden)
	              OR (#Dyn.Status."Trolley ausserhalb Weiche" AND NOT #"Kein_Weichenbereich +1") THEN
	               #Status2.Trolley_ist_draussen := TRUE;
	           END_IF;
	       END_IF;
	   END_REGION
	
	   REGION NW18: Einsprung Leser ermitteln
	       IF #Dyn.SAVE2.Leser_DB > 0 THEN   // Einsprung-Zeiger bekannt
	           #Leser_Zugriff := TRUE;
	       ELSIF WORD_TO_INT(#Schleuse.Leser_ID) <> 0 THEN   // Leser angegeben?
	           #tSuchInt := WORD_TO_INT(#Schleuse.Leser_ID);   // Search-Daten
	           "DatenOut"(SSDB := #Para.Leser_DL_DB,
	                      SSDW := 0,
	                      PARA := WORD#16#0000,
	                      SEARCHDATEN := #tSuchInt,
	                      RE_VAL => #tReVal,
	                      Position => #tPosition,
	                      OUTDATEN := #tOutDaten);
	
	           #Dyn.Rueckmld.RET_VAL_DL_Leser := #tReVal;
	
	           IF #tReVal.%X7 THEN   // AWL: JBI W_OkL
	               #Dyn.SAVE2.Leser_DB := WORD_TO_INT(#tOutDaten[1]);   // (AWL: MW222)
	               IF #Dyn.SAVE2.Leser_DB <= 0 THEN   // sinnvoller Wert?
	                   #Dyn.Error.Err_Leser_nicht_bereit := TRUE;   // undefinierter Leser
	               ELSE
	                   // (AWL: MD224)
	                   #Dyn.SAVE2.Leser_DD := DWORD_TO_DINT(
	                       SHL(IN := WORD_TO_DWORD(#tOutDaten[2]), N := 16) OR WORD_TO_DWORD(#tOutDaten[3]));
	                   #Dyn.Error.Err_Leser_nicht_bereit := FALSE;
	                   #Leser_Zugriff := TRUE;   // Leser-Zugriff vorhanden
	               END_IF;
	           ELSE
	               #Dyn.Error.Err_Leser_nicht_bereit := TRUE;   // Leser-Datenliste fehlerhaft
	           END_IF;
	       END_IF;
	   END_REGION
	
	   REGION NW19: Reservierung bei Weiche plus noch aktiv?
	       IF #"Kein_Weichenbereich +1" THEN
	           #"Reservierung_Weiche+1_aktiv" := FALSE;
	       ELSE
	           #tWeichDb := INT_TO_DINT(#SAVE.Weichen_DB);
	           #tWeichBase := INT_TO_DINT(#SAVE.Weichen_DW);
	
	           // Schleuse -1 (DBW 78) mit dieser Schleuse belegt?
	           #"Reservierung_Weiche+1_aktiv" :=
	               (WORD_TO_INT(PEEK_WORD(area := 16#84, dbNumber := #tWeichDb,
	                                      byteOffset := #tWeichBase + 78)) = #Schleusen_Nr);
	
	           // Mindestzeit nachtriggern (DBX 71.3):
	           IF #"Schleuse_geöffnet" AND #B_InSchleuse THEN
	               POKE_BOOL(area := 16#84, dbNumber := #tWeichDb,
	                         byteOffset := #tWeichBase + 71, bitOffset := 3, value := TRUE);
	           END_IF;
	       END_IF;
	   END_REGION
	
	   REGION NW20: Leser-Einheit managen (Inputs holen)
	       IF NOT #Leser_Zugriff OR NOT #Schleuse.Parameter_allg.Leser_eingebaut THEN
	           #Dyn.Status.Leser_triggern := FALSE;   // fuer Status-Anzeige
	       ELSE
	           #tLeserDb := INT_TO_DINT(#Dyn.SAVE2.Leser_DB);
	           #tLeserBase := #Dyn.SAVE2.Leser_DD;
	
	           // Offset 10:
	           #tByte := PEEK(area := 16#84, dbNumber := #tLeserDb, byteOffset := #tLeserBase + 10);
	           #Dyn.Leser."IN".xOutReadingDone := #tByte.%X0;
	           #Dyn.Leser."IN".xOutReadyForNewScan := #tByte.%X1;
	
	           // Offset 274:
	           #tByte := PEEK(area := 16#84, dbNumber := #tLeserDb, byteOffset := #tLeserBase + 274);
	           #Dyn.Leser."IN".xOutCodeGood := #tByte.%X0;
	           #Dyn.Leser."IN".xOutCodeBad := #tByte.%X1;
	
	           // Offset 12:
	           #Dyn.Leser."IN".nOutBarcode := DWORD_TO_DINT(
	               PEEK_DWORD(area := 16#84, dbNumber := #tLeserDb, byteOffset := #tLeserBase + 12));
	       END_IF;
	   END_REGION
	
	   // NW21 "Schrittkette anhalten": im AWL-Original durch CLR + JU dauerhaft
	   // deaktiviert (toter Code) -> entfaellt.
	
	   REGION NW22: Trolley wurde zurueckgezogen
	       IF NOT ((#Dyn.Sk.Akt_Schritt < 10) OR (#Dyn.Sk.Akt_Schritt > 12)
	               OR #Status2.Trolley_an_Schleuse OR #"Schleuse_geöffnet") THEN
	           #Antrieb_Schleuse_start := TRUE;
	           #Dyn.Leser."OUT".xInReset := TRUE;
	
	           #Dyn.Sk.Akt_Schritt := 0;   // Neubeginn
	
	           IF #Schleuse.Parameter_allg.Leser_eingebaut THEN   // sonst Daten behalten
	               #Dyn.Trolley_ZwischenZiel := 16#0000;
	               #Dyn.TrolleyID_Schleuse := 0;
	           END_IF;
	       END_IF;
	   END_REGION
	
	   REGION NW23: Sprungverteiler
	       IF #Dyn.Sk.Neu_Schritt <> -1 THEN   // Schritt fuer naechsten Zyklus angegeben?
	           #Dyn.Sk.Akt_Schritt := #Dyn.Sk.Neu_Schritt;   // Neuen Schritt uebergeben
	           #Dyn.Sk.Neu_Schritt := -1;   // Urzustand
	       END_IF;
	   END_REGION
	
	mNEU:
	   #Warte_neu := FALSE;   // Wartezeit neutriggern
	   #Warte_stop := FALSE;   // Wartezeit stoppen
	
	   CASE #Dyn.Sk.Akt_Schritt OF
	       0:   // NW25 Schritt 0: Warten auf Trolley
	           #Weiter := #B_InSchleuse AND #Dyn.Sk.Auto_akt AND #Dyn.Sk.Bereich_ok;
	
	           // Trolley-Schleusendaten loeschen:
	           #Dyn.TrolleyID_Schleuse := 0;
	           #Dyn.Trolley_ShopGroup := 0;
	           #Dyn.Trolley_EndZiel := 16#0000;
	           #Dyn.Weichen_Ziel := 16#0000;
	           #Dyn.HMI.TrolleyID_Input := 0;   // HMI-Zeug
	
	           IF #Dyn.Sk.Reset_Akt THEN   // Reset ist aktiv
	               #tNeuSchritt := 20;
	               GOTO mNeuMig;
	           END_IF;
	
	           #Dyn.Error.Err_Leser_nicht_bereit := FALSE;
	           #Dyn.Error.Err_Kein_LeseErgebnis := FALSE;
	           #Dyn.Status.SF_angefordert := FALSE;
	           #Status2."TrolleyPos_übergeben" := FALSE;
	           #Status2.Telegramm_gesendet := FALSE;
	
	           IF #Weiter THEN   // Weiterschaltbedingung ist erfuellt
	               #Dyn.Sk.Err_Uebzeit := FALSE;   // Sofort weiter!
	               #tWartezeit := 50;   // Angabe der Wartezeit (*10ms)
	               GOTO mPlus;
	           END_IF;
	
	           #Dyn.Stop_Ursache := 16#B001;
	
	           IF #Dyn.Status."Trolley_fährt_in_Schleuse" AND NOT #B_InSchleuse THEN
	               #Antrieb_Schleuse_vor := TRUE;   // Antrieb einschalten
	               // S000A: Ueberwachungszeit starten
	               #Ueb_akt := #Dyn.Status."Trolley_fährt_in_Schleuse" AND NOT #B_InSchleuse
	                           AND (#Antrieb_Schleuse_aktiv OR NOT #Schleuse.Parameter_allg.Antrieb_vorhanden);
	               IF #Dyn.Sk.Err_Uebzeit THEN
	                   #Dyn.Sk.Err_Uebzeit := FALSE;
	                   #Dyn.Error.Err_Trolley_nicht_in_Schleuse := TRUE;
	                   #Dyn.Status."Trolley_fährt_in_Schleuse" := FALSE;
	               END_IF;
	               #tUebzeit := #Schleuse."Übzeit_in_Schleuse";
	               GOTO mTueb;
	           END_IF;
	
	           #Dyn.Sk.Err_Uebzeit := FALSE;
	           #Dyn.Stop_Ursache := 16#B000;
	           GOTO mRET;
	
	       1:   // NW26 Schritt 1: Trolley in Schleuse / Leser? / Daten vorhanden?
	           IF #B_InSchleuse THEN
	               #Status2.Trolley_an_Schleuse := TRUE;
	           END_IF;
	
	           IF NOT #Status2.Trolley_an_Schleuse AND #Schleuse.Parameter_allg.Leser_eingebaut THEN
	               #tNeuSchritt := 0;   // Weiter mit Schritt 0
	               GOTO mNeuMig;
	           END_IF;
	
	           // Zwischen-Ziel von Bereich -1 vorhanden?
	           IF (#Dyn.ZwischenZiel_eingefahren <> 16#0000)
	              AND NOT #Schleuse.Parameter_allg.Leser_eingebaut THEN
	               // Daten von Bereich -1 uebergeben:
	               #Dyn.Trolley_ZwischenZiel := #Dyn.ZwischenZiel_eingefahren;
	               #Dyn.ZwischenZiel_eingefahren := 16#0000;
	               #Dyn.TrolleyID_Schleuse := #Dyn.TrolleyID_Eingefahren;
	               #Dyn.TrolleyID_Eingefahren := 0;
	               #tNeuSchritt := 12;   // Weiter mit Schritt 12
	               GOTO mNeuMig;
	           END_IF;
	
	           // X001:
	           #Dyn.Trolley_ZwischenZiel := 16#0000;
	
	           IF #Schleuse.Parameter_allg.Leser_eingebaut THEN   // Leser vorhanden
	               #Dyn.Error.Err_Kein_LeseErgebnis := FALSE;
	               #tNeuSchritt := 9;   // Weiter mit Schritt 9 (Leser bereit)
	               GOTO mNeuMig;
	           END_IF;
	
	           // Trolleydaten vorhanden? (Uebergabe von Bereich -1)
	           #Dyn.TrolleyID_Schleuse := #Dyn.TrolleyID_Eingefahren;
	           IF #Dyn.TrolleyID_Eingefahren <> 0 THEN
	               #tNeuSchritt := 11;   // Weiter mit Schritt 11 (Trolleydaten lesen)
	               GOTO mNeuMig;
	           END_IF;
	
	           IF #ZielFC_vorhanden THEN
	               #tNeuSchritt := 12;   // Weiter mit Schritt 12 (Ziel-FC)
	               GOTO mNeuMig;
	           END_IF;
	
	           #tNeuSchritt := 14;   // Weiter mit Schritt 14 (Weichenbereich +1 vorhanden)
	           GOTO mNeuMig;
	
	       2:   // NW27 Schritt 2: Ausfahren ok?
	           IF NOT #Status2.Trolley_an_Schleuse AND #Schleuse.Parameter_allg.Leser_eingebaut THEN
	               #tNeuSchritt := 0;   // Weiter mit Schritt 0
	               GOTO mNeuMig;
	           END_IF;
	
	           // Anlage aus oder Stoerung:
	           #Dyn.Stop_Ursache := 16#B021;
	           IF NOT #Dyn.Sk.Auto_akt OR NOT #Dyn.Sk.Bereich_ok THEN
	               GOTO mRET;
	           END_IF;
	
	           // Starten erlaubt?
	           #Dyn.Stop_Ursache := 16#B022;
	           IF NOT #Start_Ok THEN
	               GOTO mRET;
	           END_IF;
	
	           // Stau im Bereich +1:
	           #Dyn.Stop_Ursache := 16#B023;
	           #Dyn.Status."Trolley_wartet_Bereich+1" := TRUE;
	           IF #B_Stau_raus THEN   // Sensor Stau im Bereich rausfahren
	               GOTO mRET;
	           END_IF;
	
	           // B_Aus_Schleuse aktiv:
	           #Dyn.Stop_Ursache := 16#B024;
	           #Dyn.Error.Err_Raus_Sensor := #Schleuse.Parameter_allg.B_AusSep_vorhanden AND #B_AusSchleuse;
	           IF #Dyn.Error.Err_Raus_Sensor THEN
	               GOTO mRET;
	           END_IF;
	
	           // Restzeit zum Ausfahren ausreichend?
	           #Dyn.Stop_Ursache := 16#B025;
	           IF ((#RestZeit_Bereich_plus < #Schleuse.AusfahrZeit) OR (#Schleuse.AusfahrZeit = 0))
	              AND (#RestZeit_Bereich_plus <> 999) THEN
	               RETURN;   // AWL: BEC (Baustein sofort beenden, NW50 entfaellt)
	           END_IF;
	
	           // Antriebe aktivieren / aktiv?
	           IF #Schleuse.Parameter_allg.Antrieb_Plus_vorhanden THEN
	               #Antrieb_plus_vor := TRUE;
	           END_IF;
	           IF #Antrieb_plus_aktiv OR NOT #Schleuse.Parameter_allg.Antrieb_Plus_vorhanden THEN
	               #Antrieb_Schleuse_vor := TRUE;
	           END_IF;
	
	           #Dyn.Stop_Ursache := 16#B026;
	           IF NOT #Antrieb_plus_aktiv AND #Schleuse.Parameter_allg.Antrieb_Plus_vorhanden THEN
	               GOTO mRET;
	           END_IF;
	
	           #Dyn.Status.Kein_Stop_mehr := NOT #Antrieb_Schleuse_aktiv
	                                         AND #Schleuse.Parameter_allg.Antrieb_vorhanden;
	           IF #Dyn.Status.Kein_Stop_mehr THEN
	               GOTO mRET;
	           END_IF;
	
	           #Status2."Warten_3.V" := FALSE;
	
	           IF NOT #Schleuse.Parameter_allg."2.V_bei_Ausfahrt_checken" THEN
	               #tNeuSchritt := 5;   // Nur 1 langes Signal!
	           ELSE
	               #tNeuSchritt := 3;   // 2.V bei Ausfahrt checken
	           END_IF;
	           GOTO mNeuMig;
	
	       3:   // NW28 Schritt 3: Trolley faehrt aus / 1.V ausgefahren?
	           #Weiter := NOT #B_InSchleuse;
	
	           #Y_Schleuse_Auf := TRUE;   // Schleuse oeffnen
	           #Dyn.Status."Trolley_fährt_aus" := TRUE;
	
	           IF #Weiter THEN
	               #Dyn.Sk.Err_Uebzeit := FALSE;   // Sofort weiter!
	               #Dyn.Error.Err_Trolley_raus := FALSE;
	               #tWartezeit := 30;   // Angabe der Wartezeit (*10ms)
	               GOTO mPlus;
	           END_IF;
	
	           IF NOT #"Kein_Weichenbereich +1" AND NOT #"Reservierung_Weiche+1_aktiv" THEN
	               #Dyn.Sk.Err_Uebzeit := FALSE;   // Weiche nicht mehr angemeldet
	               #tNeuSchritt := 0;   // Weiter mit Schritt 0
	               GOTO mNeuMig;
	           END_IF;
	
	           IF #Dyn.Sk.Err_Uebzeit THEN
	               #Dyn.Error.Err_Trolley_raus := TRUE;   // Trolley faehrt nicht aus
	           END_IF;
	
	           #Dyn.Stop_Ursache := 16#B031;
	           #Ueb_akt := #Antrieb_Schleuse_aktiv OR NOT #Schleuse.Parameter_allg.Antrieb_vorhanden;
	           #tUebzeit := #Schleuse."Übzeit_aus_Schleuse";
	           GOTO mTueb;
	
	       4:   // NW29 Schritt 4: Trolley faehrt aus / Warten auf 2.V
	           #Weiter := #B_InSchleuse OR #Dyn.Status."Trolley ausserhalb Weiche";
	
	           // Bei Raus-Sensor nicht zaehlen:
	           IF #Schleuse.Parameter_allg.B_AusSep_vorhanden AND #B_AusSchleuse THEN
	               #Dyn.Sk.Err_Uebzeit := FALSE;
	               #Dyn.Error.Err_Trolley_raus := FALSE;
	               #tNeuSchritt := 5;   // Zaehlen ueberspringen
	               GOTO mNeuMig;
	           END_IF;
	
	           #Y_Schleuse_Auf := TRUE;   // Schleuse oeffnen
	           #Dyn.Status."Trolley_fährt_aus" := TRUE;
	
	           IF #Weiter THEN
	               #Dyn.Sk.Err_Uebzeit := FALSE;
	               #Dyn.Error.Err_Trolley_raus := FALSE;
	               #tWartezeit := 0;
	               GOTO mPlus;
	           END_IF;
	
	           IF NOT #"Kein_Weichenbereich +1" AND NOT #"Reservierung_Weiche+1_aktiv" THEN
	               #Dyn.Sk.Err_Uebzeit := FALSE;
	               #tNeuSchritt := 0;
	               GOTO mNeuMig;
	           END_IF;
	
	           IF #Dyn.Sk.Err_Uebzeit THEN
	               #Dyn.Error.Err_Trolley_raus := TRUE;
	           END_IF;
	
	           #Dyn.Stop_Ursache := 16#B041;
	           #Ueb_akt := #Antrieb_Schleuse_aktiv OR NOT #Schleuse.Parameter_allg.Antrieb_vorhanden;
	           #tUebzeit := #Schleuse."Übzeit_aus_Schleuse";
	           GOTO mTueb;
	
	       5:   // NW30 Schritt 5: Trolley faehrt aus?
	           #Weiter := NOT #B_InSchleuse
	                      AND (#Antrieb_Schleuse_aktiv OR NOT #Schleuse.Parameter_allg.Antrieb_vorhanden)
	                      AND (#Antrieb_plus_aktiv OR NOT #Schleuse.Parameter_allg.Antrieb_Plus_vorhanden);
	
	           // Ausfahrzeit lernen:
	           IF NOT #Schleuse.Parameter_allg.B_AusSep_vorhanden THEN
	               #Schleuse.AusfahrZeit := #Schleuse."Übzeit_aus_Schleuse";   // ohne Sensor: Ueb.Zeit uebergeben
	           END_IF;
	           IF (#Schleuse.AusfahrZeit = 0) AND #Schleuse.Parameter_allg.B_AusSep_vorhanden THEN
	               #Status2.Ausfahrzeit_lernen := TRUE;
	           END_IF;
	
	           #Y_Schleuse_Auf := TRUE;   // Schleuse oeffnen
	           #Dyn.Status."Trolley_fährt_aus" := TRUE;
	
	           IF #B_InSchleuse THEN   // B in Schleuse aktiv
	               #Dyn.Sk.Tok_Zelle := 0;
	           END_IF;
	
	           // Trolley ist draussen mit Verzoegerung:
	           IF #Weiter THEN
	               #Dyn.Sk.Err_Uebzeit := FALSE;
	               #Dyn.Error.Err_Trolley_raus := FALSE;
	               #tWartezeit := 300;
	               GOTO mPlus;
	           END_IF;
	
	           // Trolley faehrt nicht raus!
	           IF #Dyn.Sk.Err_Uebzeit THEN
	               #Dyn.Error.Err_Trolley_raus := TRUE;
	           END_IF;
	
	           #Dyn.Stop_Ursache := 16#B051;
	           #Ueb_akt := #Antrieb_Schleuse_aktiv OR NOT #Schleuse.Parameter_allg.Antrieb_vorhanden;
	           #tUebzeit := #Schleuse."Übzeit_aus_Schleuse";
	           GOTO mTueb;
	
	       6:   // NW31 Schritt 6: Schleuse Mindestzeit geoeffnet / Trolley draussen?
	           #Weiter := #Dyn.Status.MindestZeit_ok AND NOT #B_InSchleuse
	                      AND ((NOT #Schleuse.Parameter_allg.B_AusSep_vorhanden AND #"Kein_Weichenbereich +1")
	                           OR #Status2.Trolley_ist_draussen);
	           IF #Weiter THEN
	               #Dyn.Sk.Err_Uebzeit := FALSE;   // Sofort weiter!
	               #Dyn.Error.Err_Trolley_raus := FALSE;
	           END_IF;
	
	           #Y_Schleuse_Auf := TRUE;   // Schleuse oeffnen
	           #Dyn.Status."Trolley_fährt_aus" := TRUE;
	
	           // Erneutes Signal von B in Schleuse?
	           IF #B_InSchleuse THEN
	               #Dyn.Sk.Neu_Schritt := 5;
	               #Dyn.Mindest_Zeit := 0;   // Mindest-Zeit neu starten
	               #Dyn.Status.MindestZeit_ok := FALSE;
	               GOTO mRET;
	           END_IF;
	
	           IF NOT #Weiter THEN   // X060
	               #Dyn.Stop_Ursache := 16#B061;
	
	               // Trolley faehrt nicht raus!
	               IF #Dyn.Sk.Err_Uebzeit THEN
	                   #Dyn.Error.Err_Trolley_raus := TRUE;
	               END_IF;
	               IF #Dyn.Error.Err_Trolley_raus AND NOT #Status2.Trolley_ist_draussen
	                  AND #Schleuse.Parameter_allg.B_AusSep_vorhanden THEN
	                   #Dyn.Error.Err_Trolley_raus := FALSE;
	                   #Dyn.Error.Err_Raus_Sensor := TRUE;   // Raus-Sensor wird nicht erreicht!
	               END_IF;
	
	               #Ueb_akt := #Antrieb_Schleuse_aktiv OR NOT #Schleuse.Parameter_allg.Antrieb_vorhanden;
	               #tUebzeit := #Schleuse."Übzeit_aus_Schleuse";
	               GOTO mTueb;
	           END_IF;
	
	           // X006: Trolley hat Schleuse verlassen
	           #Dyn.Status.Trolley_draussen := TRUE;   // 1 Zyklus
	           #Dyn.Status."Trolley_fährt_in_Schleuse" := FALSE;
	           #Status2.Telegramm_gesendet := FALSE;
	
	           #Dyn.Vereinzelungstakte := #Dyn.Vereinzelungstakte + 1;
	
	           // Draussen-FC?
	           IF #DraussenFC_vorhanden THEN
	               "MW190" := INT_TO_WORD(#Schleusen_Nr);   // Schleusen-Nr uebergeben
	               "MD182" := DINT_TO_DWORD(#Dyn.Trolley_ShopGroup);   // Shop-Gruppe
	               "MW198" := #Dyn.Weichen_Ziel;   // Weichenziel
	
	               CASE #DraussenFC OF   // AWL: UC FC[#DraussenFC]
	                   1182: "Arbeitsplatz_Draussen_FC"();
	                   ELSE ;   // unbekannter Draussen-FC
	               END_CASE;
	           END_IF;
	
	           #tNeuSchritt := 7;   // Weiter mit Schritt 7
	           GOTO mNeuMig;
	
	       7:   // NW32 Schritt 7: Trolley ausserhalb der Weiche
	           #Weiter := (NOT #"Kein_Weichenbereich +1" AND NOT #"Reservierung_Weiche+1_aktiv")
	                      OR #Dyn.Status."Trolley ausserhalb Weiche"
	                      OR #"Kein_Weichenbereich +1";
	
	           #Y_Schleuse_Auf := TRUE;   // Schleuse oeffnen
	           #Dyn.Status."Trolley_fährt_aus" := TRUE;
	           IF #Dyn.Status.Weiche_geschaltet OR #"Kein_Weichenbereich +1" THEN
	               #Antrieb_Schleuse_vor := TRUE;
	               #Antrieb_plus_vor := TRUE;
	           END_IF;
	
	           IF NOT #Weiter THEN
	               #Dyn.Stop_Ursache := 16#B071;
	               GOTO mRET;
	           END_IF;
	
	           // X007: Trolley ist ausserhalb der Weiche?
	           IF #"Kein_Weichenbereich +1" THEN
	               GOTO mEndeMig;
	           END_IF;
	
	           // Weichen-Rueckmeldungen loeschen:
	           #Dyn.Status.Weiche_geschaltet := FALSE;
	           #Dyn.Status."Trolley ausserhalb Weiche" := FALSE;
	
	           // Weichen-Reservierung loeschen:
	           #tWeichDb := INT_TO_DINT(#SAVE.Weichen_DB);
	           #tWeichBase := INT_TO_DINT(#SAVE.Weichen_DW);
	           IF WORD_TO_INT(PEEK_WORD(area := 16#84, dbNumber := #tWeichDb,
	                                    byteOffset := #tWeichBase + 78)) <> #Schleusen_Nr THEN
	               GOTO mEndeMig;   // nicht diese Schleuse
	           END_IF;
	
	           POKE(area := 16#84, dbNumber := #tWeichDb, byteOffset := #tWeichBase + 78,
	                value := WORD#16#0000);   // Schleuse -1 (DBW 78) loeschen
	           #SAVE."Weiche+1" := 0;   // Hier wurde reserviert
	
	           #tWartezeit := 0;
	           GOTO mPlus;   // Naechsten Schritt starten (Schritt 8)
	
	       8:   // NW33 Schritt 8: Weichen-Rueckmeldungen = 0?
	           IF NOT #Dyn.Status.Weiche_geschaltet AND NOT #Dyn.Status."Trolley ausserhalb Weiche" THEN
	               GOTO mEndeMig;
	           END_IF;
	           #Dyn.Stop_Ursache := 16#B080;
	           GOTO mRET;
	
	       9:   // NW34 Schritt 9: Lese-Einheit bereit?
	           #Weiter := (#Dyn.Leser."IN".nOutBarcode = 0)
	                      AND #Dyn.Leser."IN".xOutReadyForNewScan
	                      AND NOT #Dyn.Leser."IN".xOutReadingDone
	                      AND NOT #Dyn.Leser."IN".xOutCodeGood
	                      AND NOT #Dyn.Leser."IN".xOutCodeBad;
	           IF #Weiter THEN
	               #Dyn.Error.Err_Leser_nicht_bereit := FALSE;
	           END_IF;
	
	           IF NOT #Status2.Trolley_an_Schleuse AND #Schleuse.Parameter_allg.Leser_eingebaut THEN
	               #Dyn.Error.Err_Leser_nicht_bereit := FALSE;
	               #tNeuSchritt := 0;   // Weiter mit Schritt 0
	               GOTO mNeuMig;
	           END_IF;
	
	           #Dyn.Leser."OUT".xInStartReading := #Weiter;   // Leser triggern
	           IF #Weiter THEN
	               #tWartezeit := 0;
	               GOTO mPlus;
	           END_IF;
	
	           // Leser nicht bereit:
	           IF #Dyn.Leser."IN".xOutReadingDone OR #Dyn.Leser."IN".xOutCodeGood
	              OR #Dyn.Leser."IN".xOutCodeBad THEN
	               #Dyn.Leser."OUT".xInHandshakeDone := TRUE;   // Falls altes Handshake noch gewollt
	           END_IF;
	
	           IF #Dyn.Sk.Err_Uebzeit THEN
	               #Dyn.Sk.Err_Uebzeit := FALSE;   // Sofort weiter!
	               #Dyn.Error.Err_Leser_nicht_bereit := TRUE;
	               #Dyn.Leser."OUT".xInErrQuit := TRUE;   // Vielleicht hilft es
	           END_IF;
	
	           IF #Dyn.Error.Err_Leser_nicht_bereit AND #ErrQuit THEN
	               #Dyn.Leser."OUT".xInReset := TRUE;   // Mit Quittierung zusaetzlich reset!
	           END_IF;
	
	           // HMI-TrolleyID bei Leser nicht bereit:
	           IF (#Dyn.HMI.TrolleyID_Input <> 0) AND #Dyn.Error.Err_Leser_nicht_bereit THEN
	               #tWartezeit := 0;
	               GOTO mPlus;
	           END_IF;
	
	           #Ueb_akt := TRUE;
	           #tUebzeit := 5;   // Angabe der Ueberwachungszeit (*1s)
	           GOTO mTueb;
	
	       10:   // NW35 Schritt 10: Warten auf Leseeinheit
	           #Weiter := #Dyn.Leser."IN".xOutReadingDone
	                      AND #Dyn.Leser."IN".xOutCodeGood
	                      AND NOT #Dyn.Leser."IN".xOutCodeBad;
	           IF #Weiter THEN
	               #Dyn.Error.Err_Kein_LeseErgebnis := FALSE;
	           END_IF;
	
	           IF NOT #Status2.Trolley_an_Schleuse AND #Schleuse.Parameter_allg.Leser_eingebaut THEN
	               #Dyn.Error.Err_Kein_LeseErgebnis := FALSE;
	               #tNeuSchritt := 0;   // Weiter mit Schritt 0
	               GOTO mNeuMig;
	           END_IF;
	
	           #Dyn.Leser."OUT".xInStartReading := FALSE;   // Leseeinheit triggern
	
	           IF #Weiter THEN
	               // X010: Leserdaten uebergeben
	               #Dyn.Leser."OUT".xInHandshakeDone := TRUE;
	               #Dyn.Sk.Err_Uebzeit := FALSE;   // Sofort weiter!
	
	               #Dyn.TrolleyID_Schleuse := #Dyn.Leser."IN".nOutBarcode;
	               IF (#Dyn.Leser."IN".nOutBarcode = 0) OR (#Dyn.Leser."IN".nOutBarcode = -1) THEN
	                   #Dyn.Error.Err_Kein_LeseErgebnis := TRUE;   // Unbekannt / Fehl-Lesung
	                   #tNeuSchritt := 9;   // Weiter mit Schritt 9 (Leser bereit)
	                   GOTO mNeuMig;
	               END_IF;
	               #tNeuSchritt := 11;   // Weiter mit Schritt 11
	               GOTO mNeuMig;
	           END_IF;
	
	           #Dyn.Status.Trolley_wartet_Lesung := TRUE;
	
	           IF NOT #Dyn.Error.Err_Leser_nicht_bereit THEN   // von Schritt 9
	               IF #Dyn.Sk.Err_Uebzeit OR #Dyn.Leser."IN".xOutCodeBad THEN
	                   #Dyn.Leser."OUT".xInHandshakeDone := TRUE;
	                   // L2: Erst bei 3.Fehllesung Error!
	                   IF NOT #Status2."2.Lesung_aktiv" THEN
	                       #Status2."2.Lesung_aktiv" := TRUE;
	                       #Dyn.Sk.Err_Uebzeit := FALSE;   // Sofort weiter!
	                       #Dyn.Sk.Neu_Schritt := 9;
	                       GOTO mRET;
	                   END_IF;
	                   // L3:
	                   IF NOT #Status2."3.Lesung_aktiv" THEN
	                       #Status2."3.Lesung_aktiv" := TRUE;
	                       #Dyn.Sk.Err_Uebzeit := FALSE;   // Sofort weiter!
	                       #Dyn.Sk.Neu_Schritt := 9;
	                       GOTO mRET;
	                   END_IF;
	                   // LX: Nach 3.Fehl-Lesung erst Leserfehler!
	                   #Dyn.Sk.Err_Uebzeit := FALSE;
	                   #Dyn.Error.Err_Kein_LeseErgebnis := TRUE;
	               ELSE
	                   #Dyn.Stop_Ursache := 16#B101;
	                   #Ueb_akt := TRUE;
	                   #tUebzeit := 10;   // Angabe der Ueberwachungszeit (*1s)
	                   GOTO mTueb;
	               END_IF;
	           ELSE
	               // LX (direkt von Schritt-9-Fehler):
	               #Dyn.Sk.Err_Uebzeit := FALSE;
	               #Dyn.Error.Err_Kein_LeseErgebnis := TRUE;
	           END_IF;
	
	           // NoLesung: HMI-Eingabe?
	           #Dyn.TrolleyID_Schleuse := #Dyn.HMI.TrolleyID_Input;
	           IF #Dyn.HMI.TrolleyID_Input <> 0 THEN   // ACHTUNG: AWL verglich mit undefiniertem Akku!
	               #Dyn.Error.Err_Kein_LeseErgebnis := FALSE;
	               #Dyn.Error.Err_Leser_nicht_bereit := FALSE;   // von Schritt 9
	               #tWartezeit := 0;
	               GOTO mPlus;
	           END_IF;
	
	           // No_HMIa: Leser-FC aufrufen:
	           IF #LeserFC_vorhanden THEN
	               "MW190" := INT_TO_WORD(#Schleusen_Nr);   // Schleusen-Nr uebergeben
	               "MW196" := #Dyn.Trolley_ZwischenZiel;
	               "M180.0" := #Dyn.Error.Err_Kein_LeseErgebnis;
	               "M180.1" := FALSE;
	
	               CASE #LeserFC OF   // AWL: UC FC[#LeserFC] (Beeinflussung der Fehllesung)
	                   1180: "Arbeitsplatz_Leser_FC"();
	                   ELSE ;   // unbekannter Leser-FC
	               END_CASE;
	
	               #Dyn.Stop_Ursache := 16#B102;
	
	               #Dyn.Trolley_ZwischenZiel := "MW196";   // Zwischenziel uebergeben
	               IF "MW196" <> 16#0000 THEN
	                   #Dyn.Error.Err_Kein_LeseErgebnis := FALSE;
	                   #tNeuSchritt := 12;   // Weiter mit Schritt 12
	                   GOTO mNeuMig;
	               END_IF;
	           END_IF;
	
	           // NoLFC:
	           #Dyn.Sk.Neu_Schritt := 9;
	           GOTO mRET;
	
	       11:   // NW36 Schritt 11: Trolleydaten aus DL lesen
	           #Dyn.TrolleyID_Eingefahren := 0;   // Eintrag von Weiche -1
	
	           #tSuchID := #Dyn.TrolleyID_Schleuse;   // Search-Daten (AWL: MD220)
	           "DatenOut"(SSDB := #Schleuse.Gesamt_Trolley_DL,
	                      SSDW := 0,
	                      PARA := WORD#16#0000,
	                      SEARCHDATEN := #tSuchID,
	                      RE_VAL => #tReVal,
	                      Position => #tPosition,
	                      OUTDATEN := "TrolleyDL_OutDaten".OUTDaten);   // Eintrag lesen (AWL: DB1011.DBX0.0)
	
	           #Dyn.Stop_Ursache := 16#B111;
	
	           #Dyn.Error.Barcode_nicht_bekannt := NOT #tReVal.%X7;
	           IF NOT #Dyn.Error.Barcode_nicht_bekannt THEN
	               // Relevante Trolleydaten auslesen:
	               #Dyn.Trolley_EndZiel := "TrolleyDL_OutDaten".OUTDaten.EndZiel;
	
	               IF #Dyn.Trolley_ZwischenZiel = 16#0000 THEN   // ZwischenZiel nicht ueberschreiben
	                   #Dyn.Trolley_ZwischenZiel := "TrolleyDL_OutDaten".OUTDaten.ZwischenZiel;
	               END_IF;
	
	               #Dyn.Trolley_ShopGroup := "TrolleyDL_OutDaten".OUTDaten.ShopGroup;
	
	               #tWartezeit := 0;
	               GOTO mPlus;   // Naechsten Schritt starten
	           END_IF;
	
	           // UnbekanntBC / Nix_HMI: Leser-FC aufrufen:
	           IF #LeserFC_vorhanden THEN
	               "MW190" := INT_TO_WORD(#Schleusen_Nr);
	               "MD192" := DINT_TO_DWORD(#Dyn.TrolleyID_Schleuse);
	               "MW196" := #Dyn.Trolley_ZwischenZiel;
	               "M180.1" := #Dyn.Error.Barcode_nicht_bekannt;
	               "M180.0" := FALSE;
	
	               CASE #LeserFC OF   // AWL: UC FC[#LeserFC] (Weiterfahrt bei nicht bekanntem Trolley)
	                   1180: "Arbeitsplatz_Leser_FC"();
	                   ELSE ;
	               END_CASE;
	
	               #Dyn.Trolley_ZwischenZiel := "MW196";   // ZwischenZiel uebergeben
	               IF "MW196" <> 16#0000 THEN
	                   #Dyn.Error.Err_Kein_LeseErgebnis := FALSE;
	                   #tNeuSchritt := 12;   // Weiter mit Schritt 12
	                   GOTO mNeuMig;
	               END_IF;
	           END_IF;
	
	           // Nix_LFC:
	           GOTO mRET;
	
	       12:   // NW37 Schritt 12: Ziel-FC
	           IF NOT #Status2.Trolley_an_Schleuse AND #Schleuse.Parameter_allg.Leser_eingebaut
	              AND NOT #"Schleuse_geöffnet" THEN
	               #tNeuSchritt := 0;   // Weiter mit Schritt 0
	               GOTO mNeuMig;
	           END_IF;
	
	           #Dyn.Status."Trolley_wartet_auf_Ziel-FC" := TRUE;
	
	           IF NOT #ZielFC_vorhanden THEN
	               #Dyn.Status."Trolley_wartet_auf_Ziel-FC" := FALSE;
	               #tNeuSchritt := 13;   // Weiter mit Schritt 13
	               GOTO mNeuMig;
	           END_IF;
	
	           "M180.6" := FALSE;   // Rueckmeldungen erst mal resetten
	           "MW190" := INT_TO_WORD(#Schleusen_Nr);   // Schleusen-Nr uebergeben
	           "MD182" := DINT_TO_DWORD(#Dyn.Trolley_ShopGroup);   // Shop-Gruppe
	           "MW194" := #Dyn.Trolley_EndZiel;   // End-Ziel
	           "MW196" := #Dyn.Trolley_ZwischenZiel;
	           "MW198" := 16#0000;   // Weichenziel erst mal nullen
	
	           CASE #ZielFC OF   // AWL: UC FC[#ZielFC] (Beeinflussung der Weiterfahrt)
	               181:  "HWtoAMRZielFC"();
	               1181: "Arbeitsplatz_Ziel_FC"();
	               2181: "HWtoOB_Ziel_FC"();
	               ELSE ;   // unbekannter Ziel-FC
	           END_CASE;
	
	           #Dyn.Stop_Ursache := 16#B122;
	
	           // Spezial-Fall bei Uebergabe an Sorter / Turm (M180.6 wird nie im Ziel-FC gesetzt!)
	           // aber anderer Partner hat Schleuse extern geoeffnet:
	           IF #"Schleuse_geöffnet" AND NOT "M180.6" AND NOT #Status2."TrolleyPos_übergeben" THEN
	               #Status2."TrolleyPos_übergeben" := TRUE;   // Nur einmalig
	
	               #Dyn.Vereinzelungstakte := #Dyn.Vereinzelungstakte + 1;
	
	               "Trolley_DL_Neue_Pos"(Gesamt_Trolley_DL := #Schleuse.Gesamt_Trolley_DL,
	                                     TrolleyID := #Dyn.TrolleyID_Schleuse,
	                                     Position := #Schleuse.Leser_ID,
	                                     ShopGroup := DINT#0,
	                                     Err => "M199.0");
	
	               // Draussen-FC?
	               IF NOT #DraussenFC_vorhanden THEN
	                   GOTO mRET;
	               END_IF;
	
	               "MW190" := INT_TO_WORD(#Schleusen_Nr);
	               CASE #DraussenFC OF   // AWL: UC FC[#DraussenFC] (z.B. Daten anpassen)
	                   1182: "Arbeitsplatz_Draussen_FC"();
	                   ELSE ;
	               END_CASE;
	               GOTO mRET;
	           END_IF;
	
	           // Normal:
	           IF "M180.6" THEN   // Weiterfahrt von Ziel-FC erlaubt
	               // X012:
	               #Dyn.Trolley_ZwischenZiel := "MW196";   // zurueckschreiben, falls veraendert
	               #Dyn.Weichen_Ziel := "MW198";   // Weichenziel uebergeben
	               #tNeuSchritt := 13;   // Weiter mit Schritt 13
	               GOTO mNeuMig;
	           END_IF;
	
	           IF NOT #Schleuse.Parameter_allg.Leser_eingebaut THEN
	               GOTO mRET;
	           END_IF;
	
	           #Dyn.Sk.Neu_Schritt := 11;
	           GOTO mRET;
	
	       13:   // NW38 Schritt 13: Schleusen-Position zurueckschreiben
	           #Status2."Weichen-Schritt" := TRUE;
	
	           // Neue Position an Gesamt-Trolley-DL uebergeben:
	           "Trolley_DL_Neue_Pos"(Gesamt_Trolley_DL := #Schleuse.Gesamt_Trolley_DL,
	                                 TrolleyID := #Dyn.TrolleyID_Schleuse,
	                                 Position := #Schleuse.Leser_ID,
	                                 ShopGroup := DINT#0,
	                                 Err => "M199.0");
	
	           #tWartezeit := 0;
	           GOTO mPlus;   // Naechsten Schritt starten
	
	       14:   // NW39 Schritt 14: Weichenbereich +1 vorhanden
	           IF #"Kein_Weichenbereich +1" THEN
	               #tNeuSchritt := 2;   // Weiter mit Schritt 2 (Ausfahren ok?)
	               GOTO mNeuMig;
	           END_IF;
	
	           #Status2."Weichen-Schritt" := TRUE;
	           #Dyn.Status.Weiche_geschaltet := FALSE;
	           #Dyn.Status."Trolley ausserhalb Weiche" := FALSE;
	
	           #tWartezeit := 0;
	           GOTO mPlus;
	
	       15:   // NW40 Schritt 15: Weichenbereich raus bereit?
	           #Status2."Weichen-Schritt" := TRUE;
	
	           IF #Dyn.Weichen_Ziel = 16#0000 THEN   // Weichenziel bekannt?
	               #Dyn.Sk.Neu_Schritt := 12;   // Ziel-FC
	               #Dyn.Stop_Ursache := 16#B154;
	               GOTO mRET;
	           END_IF;
	
	           // X15A:
	           #Dyn.Status."Trolley_wartet_auf_Weiche+1" := TRUE;
	           #Dyn.Stop_Ursache := 16#B155;
	
	           IF #SAVE.Weichen_DB <= 0 THEN   // Einsprung-Zeiger bekannt?
	               #Dyn.Stop_Ursache := 16#B150;
	               GOTO mRET;
	           END_IF;
	
	           // S015A: Weichendaten auslesen
	           #tWeichDb := INT_TO_DINT(#SAVE.Weichen_DB);
	           #tWeichBase := INT_TO_DINT(#SAVE.Weichen_DW);
	
	           #Dyn.Stop_Ursache := 16#B152;
	
	           IF NOT (NOT PEEK_BOOL(area := 16#84, dbNumber := #tWeichDb,
	                                 byteOffset := #tWeichBase + 70, bitOffset := 0)   // Weichenbereich frei? (DBX70.0)
	                   OR #Dyn.Status.Weiche_geschaltet
	                   OR #Dyn.Status."Trolley ausserhalb Weiche") THEN
	               #tNeuSchritt := 16;   // Weiter mit Schritt 16 (Daten an Weiche uebergeben)
	               GOTO mNeuMig;
	           END_IF;
	
	           // S015B: Reservierung schon erfolgt?
	           #Dyn.Status.Weiche_geschaltet := FALSE;
	           #Dyn.Status."Trolley ausserhalb Weiche" := FALSE;
	
	           IF WORD_TO_INT(PEEK_WORD(area := 16#84, dbNumber := #tWeichDb,
	                                    byteOffset := #tWeichBase + 78)) = #Schleusen_Nr THEN
	               // Reservierung loeschen:
	               POKE(area := 16#84, dbNumber := #tWeichDb, byteOffset := #tWeichBase + 78,
	                    value := WORD#16#0000);   // Schleuse -1 (DBW 78)
	           END_IF;
	           GOTO mRET;
	
	       16:   // NW41 Schritt 16: Daten an Rausweiche uebergeben
	           #Status2."Weichen-Schritt" := TRUE;
	
	           #tWeichDb := INT_TO_DINT(#SAVE.Weichen_DB);
	           #tWeichBase := INT_TO_DINT(#SAVE.Weichen_DW);
	
	           // Trolley-ID (DBD 72):
	           POKE(area := 16#84, dbNumber := #tWeichDb, byteOffset := #tWeichBase + 72,
	                value := DINT_TO_DWORD(#Dyn.TrolleyID_Schleuse));
	
	           // Weichenziel (DBW 76):
	           POKE(area := 16#84, dbNumber := #tWeichDb, byteOffset := #tWeichBase + 76,
	                value := #Dyn.Weichen_Ziel);
	
	           // Zwischenziel (DBW 80):
	           POKE(area := 16#84, dbNumber := #tWeichDb, byteOffset := #tWeichBase + 80,
	                value := #Dyn.Trolley_ZwischenZiel);
	
	           // Schleuse -1 (DBW 78):
	           POKE(area := 16#84, dbNumber := #tWeichDb, byteOffset := #tWeichBase + 78,
	                value := INT_TO_WORD(#Schleusen_Nr));
	
	           #"Reservierung_Weiche+1_aktiv" := TRUE;   // (da erst im naechsten Zyklus gelesen)
	
	           #SAVE."Weiche+1" := #Schleuse.RausWeichen_Nr;   // Hier wurde reserviert
	
	           #tNeuSchritt := 17;   // Weiter mit Schritt 17 (Hat Weiche geschaltet?)
	           GOTO mNeuMig;
	
	       17:   // NW42 Schritt 17: Hat Rausweiche geschaltet?
	           #Status2."Weichen-Schritt" := TRUE;
	
	           // Weiche +1 noch mit dieser Schleuse aktiv?
	           IF NOT #"Reservierung_Weiche+1_aktiv" THEN
	               #tNeuSchritt := 14;   // Weiter mit Schritt 14
	               GOTO mNeuMig;
	           END_IF;
	
	           #Dyn.Status."Trolley_wartet_auf_Weiche+1" := TRUE;
	           #Dyn.Stop_Ursache := 16#B170;
	
	           IF #Dyn.Status."Trolley ausserhalb Weiche" THEN   // Rueckmeldung von Weiche +1
	               GOTO mRET;
	           END_IF;
	
	           IF #Dyn.Status.Weiche_geschaltet THEN   // Rueckmeldung von Weiche +1
	               #tNeuSchritt := 2;   // Weiter mit Schritt 2 (Ausfahren ok?)
	               GOTO mNeuMig;
	           END_IF;
	
	           #Dyn.Stop_Ursache := 16#B171;
	           GOTO mRET;
	
	       20:   // NW43 Schritt 20: Schleuse resetten (Wartezeit)
	           #Weiter := #B_InSchleuse;
	
	           // ELS in Grundstellung fahren:
	           #Antrieb_Schleuse_vor := TRUE;
	           #Antrieb_Schleuse_start := TRUE;
	
	           IF #Weiter OR #Dyn.Sk.Err_Uebzeit THEN
	               #Dyn.Sk.Err_Uebzeit := FALSE;   // Sofort weiter!
	               #tNeuSchritt := 21;   // Weiter mit Schritt 21
	               GOTO mNeuMig;
	           END_IF;
	
	           #Dyn.Stop_Ursache := 16#B201;
	           #Ueb_akt := TRUE;
	           #tUebzeit := 60;   // AWL: L Wartezeit_bis_leer; L 60 -> 60 wirksam
	           GOTO mTueb;
	
	       21:   // NW44 Schritt 21: Reset ist zu Ende
	           #Dyn.Sk.Reset_Akt := FALSE;   // Reset ist aktiv
	           #Status2."Warten_3.V" := FALSE;
	           #Status2."TrolleyPos_übergeben" := FALSE;
	           #Dyn.Error.Err_Trolley_nicht_in_Schleuse := FALSE;
	           #Dyn.Error.Err_Uebzeit := FALSE;
	           #Dyn.Error.Err_Stau_Einfahrt := FALSE;
	           #Dyn.Error.Err_Trolley_raus := FALSE;
	           #Dyn.Status."Trolley_fährt_in_Schleuse" := FALSE;
	
	           #SAVE.Weichen_DB := 0;
	           #SAVE.Weichen_DW := 0;
	           #SAVE."Weiche+1" := 0;   // Dadurch wird in Weiche Reservierung geloescht
	           #Schleuse.Schleusen_Nr := 0;   // Damit stat. Daten neu geholt werden!
	
	           #Dyn.Status.Trolley_draussen := TRUE;
	
	           GOTO mEndeMig;   // Neubeginn
	
	       ELSE   // Schritte 18/19/22..30 und ungueltige Werte
	           GOTO mEnde;   // Undefinierter Schritt
	   END_CASE;
	
	   GOTO mEnde;   // (nicht erreichbar; alle Zweige enden mit GOTO)
	
	   REGION Schrittketten-Verwaltung (AWL: Ende / Neu_Mig / ENDE_Mig / Plus / tueb / RET)
	mEnde:  // NW23 Ende: Undefinierter Schritt
	       #Dyn.Sk.Err_Schritt := TRUE;
	       #Dyn.Stop_Ursache := 16#A131;
	       GOTO mRET;
	
	mNeuMig:   // Neu_Mig: neuen Schritt sofort (im selben Zyklus) aktivieren
	       IF #Dyn.Sk.Err_Uebzeit THEN   // Stoerung noch nicht quittiert
	           #Dyn.Stop_Ursache := 16#A132;
	           GOTO mRET;
	       END_IF;
	       #Dyn.Sk.Akt_Schritt := #tNeuSchritt;
	       #Dyn.Sk.Terr_Zelle := 0;   // Zeitwerte loeschen
	       #Dyn.Sk.Tok_Zelle := 0;
	       GOTO mNEU;   // zurueck zum Sprungverteiler
	
	mEndeMig:   // NW45: Schrittkette beenden
	       #Dyn.Sk.Akt_Schritt := 0;   // Schritt 0: Warten
	       #Dyn.Sk.Terr_Zelle := 0;   // Zeitwert loeschen
	       #Dyn.Sk.Tok_Zelle := 0;
	       #Dyn.ZwischenZiel_eingefahren := 16#0000;
	
	       #Dyn.TrolleyID_Eingefahren := 0;   // Eintrag von Weiche -1
	       #Dyn.TrolleyID_Schleuse := 0;
	       #Dyn.Trolley_ZwischenZiel := 16#0000;
	       #Dyn.Trolley_EndZiel := 16#0000;
	       #Dyn.Weichen_Ziel := 16#0000;
	
	       #Dyn.Sk.Err_Uebzeit := FALSE;
	       #Dyn.Status.Weiche_geschaltet := FALSE;
	       #Dyn.Status."Trolley ausserhalb Weiche" := FALSE;
	       #Dyn.Status."Trolley_fährt_rückwärts" := FALSE;
	       #Status2."Warten_3.V" := FALSE;
	       #Dyn.Error.Err_Kein_LeseErgebnis := FALSE;
	       #Status2."2.Lesung_aktiv" := FALSE;
	       #Status2."3.Lesung_aktiv" := FALSE;
	       #Status2."TrolleyPos_übergeben" := FALSE;
	       #Status2.Telegramm_gesendet := FALSE;
	
	       #Dyn.HMI.TrolleyID_Input := 0;   // HMI-Zeug
	       GOTO mRET;
	
	mPlus:   // NW46: Naechsten Schritt aktivieren (nach Wartezeit #tWartezeit *10ms)
	       #Dyn.Sk.T_ok := #tWartezeit;   // Wartezeit uebergeben
	
	       IF #Dyn.Sk.Err_Uebzeit THEN   // Stoerung noch nicht quittiert
	           GOTO mRET;
	       END_IF;
	
	       IF #tWartezeit <> 0 THEN   // sonst sofort weiter
	           IF #Warte_neu THEN   // Wartezeit neutriggern
	               #Dyn.Sk.Tok_Zelle := 0;
	           END_IF;
	           IF #Warte_stop THEN   // Wartezeit stoppen
	               GOTO mRET;
	           END_IF;
	           #Dyn.Sk.Tok_Zelle := #Dyn.Sk.Tok_Zelle + WORD_TO_INT("MW4");   // Wartezeit +10ms
	           IF #Dyn.Sk.Tok_Zelle < #Dyn.Sk.T_ok THEN   // abgelaufen? Nein!
	               GOTO mRET;
	           END_IF;
	       END_IF;
	
	       #Dyn.Sk.Akt_Schritt := #Dyn.Sk.Akt_Schritt + 1;   // Schritt +1
	       #Dyn.Sk.Terr_Zelle := 0;   // Zeitwerte loeschen
	       #Dyn.Sk.Tok_Zelle := 0;
	       GOTO mRET;
	
	mTueb:   // NW47/48: Ueberwachungszeit kontrollieren (#tUebzeit *1s)
	       #Dyn.Sk.Ueb_akt := #Ueb_akt;   // Fuer Statuskontrolle
	       #Dyn.Sk.T_Err := #tUebzeit;   // Fuer Statuskontrolle
	
	       IF (#tUebzeit > #Dyn.Sk.Terr_Zelle) AND NOT #Dyn.Sk.Err_Uebzeit THEN
	           // NW48: Ueberwachungszeit +1
	           IF #Dyn.Sk.Ueb_akt AND "1s-Impuls" THEN
	               #Dyn.Sk.Terr_Zelle := #Dyn.Sk.Terr_Zelle + 1;   // Ueb.zeit +1s
	           END_IF;
	           GOTO mRET;
	       END_IF;
	
	       IF #Ueb_akt THEN   // Ueberwachungszeit aktiviert
	           #Dyn.Sk.Err_Uebzeit := TRUE;
	       END_IF;
	       #Dyn.Sk.Terr_Zelle := 0;   // Zeitwert loeschen
	       GOTO mRET;
	   END_REGION
	
	   REGION NW50: Leser-Einheit managen (Outputs schreiben)
	mRET:   IF #Leser_Zugriff AND #Schleuse.Parameter_allg.Leser_eingebaut THEN
	           #tLeserDb := INT_TO_DINT(#Dyn.SAVE2.Leser_DB);
	           #tLeserBase := #Dyn.SAVE2.Leser_DD;
	
	           // Offset 4: Aktuelle Werte holen, Bits setzen, zurueckschreiben
	           #tByte := PEEK(area := 16#84, dbNumber := #tLeserDb, byteOffset := #tLeserBase + 4);
	
	           #tByte.%X1 := #Dyn.Leser."OUT".xInStartReading;
	           #tByte.%X2 := #Dyn.Leser."OUT".xInHandshakeDone;
	           #Dyn.Leser."OUT".xInHandshakeDone := FALSE;
	           #tByte.%X4 := #Dyn.Leser."OUT".xInErrQuit;
	           #Dyn.Leser."OUT".xInErrQuit := FALSE;
	           #tByte.%X5 := #Dyn.Leser."OUT".xInReset;
	           #Dyn.Leser."OUT".xInReset := FALSE;
	
	           POKE(area := 16#84, dbNumber := #tLeserDb, byteOffset := #tLeserBase + 4,
	                value := #tByte);   // Veraenderte Werte zurueckschreiben
	       END_IF;
	   END_REGION
END_FUNCTION_BLOCK

