FUNCTION "LP_Ziel_FC" : Void
TITLE = Ziel-FC: LeerPuffer_OmniFahren
{ S7_Optimized_Access := 'FALSE' }
AUTHOR : AE
FAMILY : Module
NAME : Ziel
//SCL-Portierung des AWL-Bausteins FC5181 "LP_Ziel_FC" (verhaltensgleich).
//
//Der Baustein hatte im AWL-Original die Bausteineigenschaft "Parameterversorgung
//ueber Register" (ParameterPassing) aktiv und wurde per "UC FC[..]" indirekt aus
//AWL aufgerufen -> aus SCL nicht compilierbar. Er liest ausschliesslich globale
//Merker (MW190 = Schleusen-Nr) sowie den Bool-Merker "MB3305" und ruft die
//Zielbausteine voll qualifiziert auf -> keine echte Registerabhaengigkeit.
//Als SCL-Baustein entfaellt die Option und er ist direkt aus SCL aufrufbar
//(CASE 5181 in MHMOmniSchleuse).
//
//Der indirekte Dispatch (AWL: "L MW190 / L 3305 / NE_I / JC X3305E") ist als CASE
//ueber die Schleusen-Nr (MW190) ausgefuehrt. Es existiert nur der Zweig 3305; ein
//AWL-BEU/BEC im getroffenen Zweig ist als RETURN bzw. "IF <RLO> THEN RETURN;"
//umgesetzt (verhaltensgleich, da nach dem Dispatch nur noch das Bausteinende folgt).
//Die Merker-Schnittstelle (MW190 vom Aufrufer, M180.6 = Weiterfahrt-Freigabe,
//MB199 = DatenOut-Rueckmeldung) bleibt erhalten.
//
//ABWEICHUNGEN ZUM AWL-ORIGINAL (bei Inbetriebnahme pruefen!):
//  - DatenOut: der Merker-Scratch-Bereich M220 (Such-/OutDaten-Pointer P#M220.0)
//    ist durch den lokalen Puffer #DatenPuffer ersetzt (SEARCHDATEN/OUTDATEN sind
//    VARIANT statt POINTER). MW220/MW224/MW226 werden dadurch NICHT mehr als
//    Merker beschrieben/gelesen (Ergebnis identisch, keine Merker-Nebenwirkung).
//    Lager-DB = Datensatz-Wort 2 (=M224), Lager-DW = Wort 3 (=M226).
//  - BTI (BCD-Wort -> Int, "Damit Int 1-10 als Ziel") ist ueber den Projekt-FC
//    "BCD (4stellig)_to_INT" ausgefuehrt; Fehlerverhalten bei ungueltiger BCD kann
//    abweichen (BTI setzt BIE).
//  - Indirekter DB-Zugriff (AWL: OPEN_DB DB[Lager_DB] / A DBX[AR1Zeiger] mit
//    Pointer-Arithmetik ADD DINT#70 / SLD 3 / OD 7) ist durch PEEK_BOOL
//    (area 16#84, byteOffset = Lager_DW+70, bitOffset = 7 -> Bit 7: Inilauf)
//    ersetzt. Die Temp "AR1Zeiger" wird dadurch nicht mehr benoetigt.
//  - AWL "CLR / S M180.6": die Set-Operation steht unter RLO=0 (CLR) und wird
//    daher NICHT ausgefuehrt (bewusst deaktiviert; Weiterfahrt wird ueber
//    MSorterRein FB5423/5 gestartet). M180.6 bleibt an dieser Stelle unveraendert.
//  - "MB3305" wird (wie im AWL: A / BEC) als Bool-Symbol behandelt.
//  - Word-Vergleiche direkt (z.B. (Ziel_hex AND W#16#F000) = W#16#A000);
//    MW190 wird fuer den CASE ueber WORD_TO_INT in Int gewandelt.
//  - Zusaetzliche Temp "DatenPuffer" (Array[0..15] of Word, nicht im XML-Interface)
//    als DatenOut-Puffer eingefuehrt. TypedConstants DINT#70/DINT#1/DINT#0 1:1.
//  - "Default_Ziel"/"Rec_DEST_Ziel" werden als Int beschrieben (AWL: 16-Bit-T von
//    Ziel_int); falls die DB-Member als Word deklariert sind -> INT_TO_WORD noetig.
   VAR_TEMP
      Ziel_hex : Word;
      Ziel_int : Int;
      Zielebene : Word;
      Error : Byte;
      Position : Int;
      Lager_DB : Int;
      Lager_DW : Int;
      AR1Zeiger : DWord;   // Statt AR1 (ging nur bis DB-Länge <= 8191 Bytes)
      AR1Start : DInt;   // Startwert mit Offset 0
      SSDW : Int;
      EndZiel : Word;
      Variante : Int;
      AbrufID : DInt;
      Fahrlisten_TrolleyID : DInt;
      Fahrlisten_AbrufID : DInt;
      Fahrlisten_Lager : Int;
      Trolley_unbekannt : Bool;   // Trolley ist nicht in DL
      Express_Abruf : Bool;
      DatenPuffer : Array[0..15] of Word;   // Puffer fuer DatenOut (ersetzt Merker-Scratch M220)
   END_VAR

BEGIN
   // NW1: Rueckmeldung - Rueckmeldungen erst mal resetten
   "M180.6" := FALSE;   // Weiterfahrt von Ziel-FC erlaubt

   // NW2: Schleuse 3305: Weiterfahren erlaubt ? (Sorter LP)
   // AWL: L MW190 / L 3305 / NE_I / JC X3305E  (Aufruf von Schleuse 3305?)
   CASE WORD_TO_INT("MW190") OF

      3305:
         IF "MB3305" THEN
            RETURN;   // AWL: A MB3305 / BEC
         END_IF;

         // Leer-Puffer ermitteln:
         "Leerpuffer to Rein-Lager ermitteln"(Puffer => "Ziel_hex");

         // Ziel = Leer-Lager?
         IF ("Ziel_hex" AND W#16#F000) <> W#16#A000 THEN   // (AWL: AW F000 / EQ_I A000 / JC LagerOk / BEU)
            RETURN;   // Kein Lager frei!
         END_IF;

         // AWL: L Ziel_hex / L W#16#FF / AW / BTI / T Ziel_int  (Damit Int 1-10 als Ziel!)
         "BCD (4stellig)_to_INT"(BCD_Wert := ("Ziel_hex" AND W#16#00FF),
                                 Int_Wert => "Ziel_int");

         // Check, ob Ziel-Lager Inilauf aktiv hat:
         #DatenPuffer[0] := INT_TO_WORD("Ziel_int");   // Suchschluessel (AWL: T MW220)
         "DatenOut"(SSDB        := 275,
                    SSDW        := 0,
                    PARA        := W#16#0000,   // Eintrag lesen
                    SEARCHDATEN := #DatenPuffer,
                    RE_VAL      => "MB199",
                    Position    => #Position,
                    OUTDATEN    := #DatenPuffer);

         // AWL: L MB199 / L 2#1111111 / AW / L 0 / NE_I / JC Egal  (Bit 7 ausblenden; Fehler vorhanden?)
         IF BYTE_TO_INT("MB199" AND B#16#7F) = 0 THEN   // kein Fehler -> Inilauf pruefen
            "Lager_DB" := WORD_TO_INT(#DatenPuffer[2]);   // AWL: L MW224 / T Lager_DB
            "Lager_DW" := WORD_TO_INT(#DatenPuffer[3]);   // AWL: L MW226 / T Lager_DW
            "AR1Start" := INT_TO_DINT("Lager_DW");        // Startwert mit Offset 0
            // AWL: ADD DINT#70 / SLD 3 / OD 7 -> Bit-Pointer auf DBX(Lager_DW+70).7 (Bit 7: Inilauf)
            IF PEEK_BOOL(area       := 16#84,
                         dbNumber   := INT_TO_DINT("Lager_DB"),   // Lager-DB
                         byteOffset := "AR1Start" + DINT#70,      // Offset Status
                         bitOffset  := 7) THEN                    // Lager hat Inilauf aktiv
               RETURN;   // Sonst kann der Inilauf nie beendet werden!
            END_IF;
         END_IF;

         // Egal:
         "DLP_Sorter".Sorter_MB3305.Separator.Default_Ziel := "Ziel_int";
         "DLP_Sorter".Sorter_MB3305.Dyn.Scanner.Rec_DEST_Ziel := "Ziel_int";

         // Pseudo-IDX uebergeben:
         // AWL: L Rec_IDX / L DINT#0 / NE_D / BEC  (Daten schon erzeugt? Ja!)
         IF "DLP_Sorter".Sorter_MB3305.Dyn.Scanner.Rec_IDX <> DINT#0 THEN
            RETURN;
         END_IF;
         "DLP_Sorter".Pseudo_IDX := "DLP_Sorter".Pseudo_IDX + DINT#1;   // Da kein Leser verbaut
         "DLP_Sorter".Sorter_MB3305.Dyn.Scanner.Rec_IDX := "DLP_Sorter".Pseudo_IDX;   // IDX

         // AWL: CLR / S M180.6 -> Set steht unter RLO=0 (CLR) und wird NICHT ausgefuehrt.
         // Weiterfahrt wird ueber MSorterRein (FB5423/5) gestartet -> M180.6 bleibt unveraendert.
         // AWL: BEU -> Bausteinende

      ELSE
         ;   // andere Schleusen-Nr -> nichts tun (AWL: X3305E / NOP 0)
   END_CASE;

   // NW3: Ende (AWL: BE)
END_FUNCTION
