FUNCTION "DatenOut" : Void
TITLE = Datensatz in Datenliste suchen / lesen / loeschen
{ S7_Optimized_Access := 'FALSE' }
AUTHOR : IBAE
FAMILY : Module
NAME : DatenOut
//SCL-Portierung des AWL-Bausteins FC86 "DatenOut" (verhaltensgleich).
//
//Datenlisten-Kopf im Datenlisten-DB ab Byte SSDW:
//  +0  Kopf (Byte, 16#DA = Datenliste, 16#DB = Sort-Datenliste)
//  +1  Datensatzlaenge (Byte, in Worten, 1..128)
//  +2  Listenlaenge (Int, max. Anzahl Datensaetze)
//  +4  Stammdaten (Int, Anzahl Suchworte 1..9)
//  +6  IndDB (Word, indizierter DB; nur bei Stammdaten=1)
//  +8  IndDB_Laenge (Int, Laenge indizierter DB in Eintraegen)
//  +10 IndDaten_FC (Int, Wandel-FC-Nummer fuer indizierte Suche)
//  +12 Suchzeiger / letzter Zugriff (Int, Byte-Adresse)
//  +16 AnzahlEintraege (Int)
//  +20 Datenbereich, dahinter Endekennung 16#DAEE bzw. 16#DBEE
//
//Aufrufparameter PARA (High-Byte = Para1, Low-Byte = Para2):
//  Para1: 00=suchen, E1=suchen+loeschen, F1=1.Datensatz holen,
//         FF=naechsten Datensatz holen, 02..80=Offset-Suche ab Wort X
//  Para2: 00=Stammdaten aus Kopf, sonst Anzahl Stammdaten (1..9)
//
//RE_VAL: Bit0=kein Datenlistenbereich, Bit1=Kopier-/SFC-Fehler, Bit2=Listenende,
//        Bit3=falscher Parameter, Bit4=undef. Suchdaten, Bit5=undef. OutDaten,
//        Bit6=Datensatz nicht vorhanden, Bit7=Daten vorhanden. Erfolg zusaetzlich via ENO/BR.
//
//ABWEICHUNGEN ZUM AWL-ORIGINAL:
//  - SEARCHDATEN/OUTDATEN sind VARIANT statt POINTER (S7-1500/SCL).
//    SEARCHDATEN muss mind. Stammdaten*2 Bytes referenzieren.
//    OUTDATEN sollte exakt Datensatzlaenge*2 Bytes gross sein (groessere Ziele
//    werden hinter dem Datensatz mit 0 aufgefuellt).
//  - Die DB-Laengenpruefung des Such-/Out-DB (AWL NW5/NW8) entfaellt, da der
//    Variant-Zugriff typsicher ist. Fehlerbit 5 (undef. OutDaten) wird nicht mehr erzeugt.
//  - Der indirekte Aufruf UC FC[#Wandel_FC] ist als CASE ausgefuehrt
//    (aktuell einziger Wandel-FC im Projekt: FC1000 "Wandel_FC_fuer_DB1000").
//  - Position wird mit 0 initialisiert (AWL: undefiniert, wenn nicht gefunden).
   VAR_INPUT
      SSDB : Int;   // Datenlisten-DB
      SSDW : Int;   // Datenlisten-1.DW (Byte-Offset des Kopfs)
      PARA : Word;   // Aufrufparameter (Auftrag / Anzahl Stammdaten)
      SEARCHDATEN : Variant;   // Such-Daten-Schnittstelle (Stammdaten Worte)
   END_VAR

   VAR_OUTPUT
      RE_VAL : Byte;   // Rueckmeldung (Fehler-/Statusbits)
      Position : Int;   // Daten stehen an angegebener Position in Datenliste
   END_VAR

   VAR_IN_OUT
      OUTDATEN : Variant;   // OutDaten-Schnittstelle (Datensatzlaenge Worte)
   END_VAR

   VAR_TEMP
      Kopf : Byte;   // Datenliste-Kennung (DA/DB)
      Datensatzlaenge : Int;   // Datensatzlaenge in Word (1..128)
      Listenlaenge : Int;   // Laenge der Datenliste (max. Anzahl Datensaetze)
      Stammdaten : Int;   // Stammdatenlaenge in Word (1..9)
      IndDB : Word;   // Indizierter DB (nur bei Stammdaten = 1 erlaubt !!!)
      IndDB_Laenge : Int;   // Laenge des indizierten DB in Eintraegen
      IndDaten_FC : Int;   // FC zum Wandeln der indizierten Daten
      Suchzeiger : Int;   // Speicherung des letzten Zugriffs / Suchzeiger (Byte-Adresse)
      Para1 : Byte;   // 1.Aufrufparameter
      Para2 : Byte;   // 2.Aufrufparameter
      OffsetDaten_1 : Int;   // Stammdaten beginnen ab hier (Byte-Offset)
      SFC_RET_VAL : Int;   // Rueckmeldung SFC-/Serialize-Aufruf
      SFC_DB_LENGTH : Word;   // Rueckmeldung TEST_DB-Aufruf
      SFC_WRITE_PROT : Bool;   // Rueckmeldung TEST_DB-Aufruf (letzter Aufruf!)
      DB_Laenge : Int;   // DB-Laenge nach BCD-Wandlung (wie AWL)
      Datenlisten_Ende : Int;   // Ende der Datenliste (Byte-Offset Endekennung)
      Datenblock_inBytes : Int;   // Datenblocklaenge in Bytes
      Daten_1 : Word;   // 1.Datenwort der Suchdaten
      Daten_2 : DWord;   // 1.+2.Datenwort der Suchdaten (fuer Wandel-FC)
      Wandel_FC : Int;   // Wandel-FC-Nummer
      Suchstelle : Int;   // Bei angegebenem Datensatz suchen (Position)
      LoeschPos : Int;   // Loesch-Position
      Indok : Bool;   // Indizierung moeglich
      IndZeiger_ok : Bool;   // Indizier-Zeiger angegeben
      Weitersuchen : Bool;   // Weitersuchen ist aktiv (Para1 F1/FF)
      Offsetsuchen : Bool;   // Offsetsuchen ist aktiv
      Sortliste : Bool;   // Sortliste wird durchsucht
      tRE_VAL : Byte;   // Rueckmeldung (Zwischenwert)
      tVKE : Bool;   // Ergebnis fuer ENO (BR im AWL)
      tGefunden : Bool;   // Vergleichs-/Suchergebnis
      tDbList : DInt;   // Datenlisten-DB-Nummer fuer PEEK/POKE
      tDbInd : DInt;   // Indizierter DB fuer PEEK/POKE
      tIndex : Int;   // Indexwert fuer indizierte Suche
      IndByteOfs : Int;   // Byte-Offset des Index-Eintrags im IndDB
      tWort : Word;   // Wort-Zwischenwert
      tAnz : Int;   // Anzahl-Zwischenwert
      tAnzBytes : Int;   // Anzahl zu verschiebender Bytes
      tPos : DInt;   // Serialize-/Deserialize-Position
      i : Int;   // Schleifenzaehler
      tSuchPuffer : Array[0..257] of Byte;   // Zwischenpuffer SEARCHDATEN
      tRecPuffer : Array[0..257] of Byte;   // Zwischenpuffer Datensatz -> OUTDATEN
   END_VAR

BEGIN
    #tRE_VAL := 16#00;
    #Suchstelle := 0;
    #Position := 0;

    REGION NW1: Schnittstellen-DB sinnvoll ?
        #tDbList := INT_TO_DINT(#SSDB);

        "TEST_DB_TO_ATTR_DB"(DB_Number := INT_TO_WORD(#SSDB),
                             RetVal => #SFC_RET_VAL,
                             DB_Length => #SFC_DB_LENGTH,
                             Write_Prot => #SFC_WRITE_PROT);
        "BCD (4stellig)_to_INT"(BCD_Wert := #SFC_DB_LENGTH, Int_Wert => #DB_Laenge);

        IF (#SFC_RET_VAL <> 0) OR #SFC_WRITE_PROT THEN   // schreibgeschuetzt
            GOTO mErr0;   // kein Datenlisten-Bereich
        END_IF;
    END_REGION

    REGION NW2: Datenlisten-Kopf holen (AWL: Quelle-Pointer + BLKMOV, 10 Worte)
        IF #SSDW < 0 OR (#SSDW + 20) > #DB_Laenge THEN
            GOTO mErr1;   // Kopf liegt nicht im DB (AWL: SFC20-Fehler)
        END_IF;

        #Kopf            := PEEK(area := 16#84, dbNumber := #tDbList, byteOffset := INT_TO_DINT(#SSDW));
        #Datensatzlaenge := BYTE_TO_INT(PEEK(area := 16#84, dbNumber := #tDbList, byteOffset := INT_TO_DINT(#SSDW + 1)));
        #Listenlaenge := WORD_TO_INT(PEEK_WORD(area := 16#84, dbNumber := #tDbList, byteOffset := INT_TO_DINT(#SSDW + 2)));
        #Stammdaten   := WORD_TO_INT(PEEK_WORD(area := 16#84, dbNumber := #tDbList, byteOffset := INT_TO_DINT(#SSDW + 4)));
        #IndDB        := PEEK_WORD(area := 16#84, dbNumber := #tDbList, byteOffset := INT_TO_DINT(#SSDW + 6));
        #IndDB_Laenge := WORD_TO_INT(PEEK_WORD(area := 16#84, dbNumber := #tDbList, byteOffset := INT_TO_DINT(#SSDW + 8)));
        #IndDaten_FC  := WORD_TO_INT(PEEK_WORD(area := 16#84, dbNumber := #tDbList, byteOffset := INT_TO_DINT(#SSDW + 10)));
        #Suchzeiger   := WORD_TO_INT(PEEK_WORD(area := 16#84, dbNumber := #tDbList, byteOffset := INT_TO_DINT(#SSDW + 12)));
    END_REGION

    REGION NW3: Zeigerueberpruefung
        #Sortliste := (#Kopf = 16#DB);   // Sort-Datenlistenkennung ?
        IF NOT #Sortliste AND (#Kopf <> 16#DA) THEN   // Datenlistenkennung ?
            GOTO mErr0;   // kein Datenlistenbereich
        END_IF;

        IF (#Datensatzlaenge < 1) OR (#Datensatzlaenge > 128)
           OR (#Listenlaenge < 1)
           OR (#Stammdaten < 1) OR (#Stammdaten > 9)
           OR (#Stammdaten > #Datensatzlaenge) THEN
            GOTO mErr0;   // kein Datenlistenbereich
        END_IF;

        #Datenlisten_Ende := #Listenlaenge * #Datensatzlaenge * 2 + 20 + #SSDW;

        IF #Datenlisten_Ende > #DB_Laenge THEN   // Datenlisten-DB ist zu kurz!
            GOTO mErr0;   // kein Datenlisten-Bereich
        END_IF;

        #tWort := PEEK_WORD(area := 16#84, dbNumber := #tDbList, byteOffset := INT_TO_DINT(#Datenlisten_Ende));
        IF (#tWort <> 16#DAEE) AND (#tWort <> 16#DBEE) THEN   // Endekennung ?
            GOTO mErr0;   // kein Datenlisten-Bereich
        END_IF;

        #Datenblock_inBytes := #Datensatzlaenge * 2;
    END_REGION

    REGION NW4: Auftrag kontrollieren
        #Indok := FALSE;
        #IndZeiger_ok := FALSE;
        #Weitersuchen := FALSE;
        #Offsetsuchen := FALSE;
        #OffsetDaten_1 := 0;   // Vorerst kein Offset

        #Para1 := WORD_TO_BYTE(SHR(IN := #PARA, N := 8));
        #Para2 := WORD_TO_BYTE(#PARA);

        IF #Para1 = 16#00 THEN   // Normale Suche
            GOTO mW401;
        END_IF;

        IF #Para1 = 16#E1 THEN   // Suchen + loeschen
            IF #Sortliste THEN
                GOTO mErr3;   // Austragen aus Sortliste nicht erlaubt !
            END_IF;
            GOTO mW401;
        END_IF;

        IF #Para1 = 16#F1 THEN   // 1.Datensatz holen
            IF (#Para2 <> 16#00) OR #Sortliste THEN
                GOTO mErr3;   // Falscher Aufrufparameter
            END_IF;
            #Weitersuchen := TRUE;
            #Suchzeiger := #SSDW + 20;
            GOTO mNw08;   // OutDaten ok ?
        END_IF;

        IF #Para1 = 16#FF THEN   // Naechsten Datensatz holen
            IF (#Para2 <> 16#00) OR #Sortliste THEN
                GOTO mErr3;   // Falscher Aufrufparameter
            END_IF;
            #Weitersuchen := TRUE;
            #Suchzeiger := #Suchzeiger + #Datenblock_inBytes;   // Naechsten Datensatz suchen
            IF (#Datenblock_inBytes * #Listenlaenge + #SSDW + 20) > #Suchzeiger THEN
                GOTO mNw08;   // Noch nicht am Ende
            END_IF;
            GOTO mErr2;   // Listenende erreicht
        END_IF;

        // Offset-Suche: Para1 = Offset des 1.Stammdatenworts (2..128)
        IF (BYTE_TO_INT(#Para1) < 2)
           OR (BYTE_TO_INT(#Para1) > 128)
           OR (BYTE_TO_INT(#Para1) > #Datensatzlaenge) THEN
            GOTO mErr3;   // Falscher Aufrufparameter
        END_IF;
        #OffsetDaten_1 := (BYTE_TO_INT(#Para1) - 1) * 2;   // Richtiger Offset der 1.Stammdaten
        #Suchzeiger := 0;   // Suche ab Anfang
        #Offsetsuchen := TRUE;

mW401:  IF #Para2 <> 16#00 THEN
            #Stammdaten := BYTE_TO_INT(#Para2);   // Anzahl der Stammdaten aus Aufruf
            IF (#Stammdaten > #Datensatzlaenge)
               OR (#Stammdaten < 1)
               OR (#Stammdaten > 9) THEN
                GOTO mErr3;   // Falscher Aufrufparameter
            END_IF;
        END_IF;

        IF #Offsetsuchen THEN
            IF (BYTE_TO_INT(#Para1) - 1 + #Stammdaten) > #Datensatzlaenge THEN   // Letzte Stammdaten zu gross ?
                GOTO mErr3;   // Falscher Aufrufparameter
            END_IF;
        END_IF;
    END_REGION

    REGION NW5: Such-Daten uebernehmen (AWL: Pointer-Parsing)
        #Suchzeiger := 0;

        #tPos := 0;
        #SFC_RET_VAL := Serialize(SRC_VARIANT := #SEARCHDATEN, DEST_ARRAY := #tSuchPuffer, POS := #tPos);
        IF (#SFC_RET_VAL <> 0) OR (#tPos < INT_TO_DINT(#Stammdaten * 2)) THEN
            GOTO mErr4;   // Undefinierte Suchdaten
        END_IF;

        #Daten_1 := SHL(IN := BYTE_TO_WORD(#tSuchPuffer[0]), N := 8) OR BYTE_TO_WORD(#tSuchPuffer[1]);
        #Daten_2 := SHL(IN := BYTE_TO_DWORD(#tSuchPuffer[0]), N := 24)
                    OR SHL(IN := BYTE_TO_DWORD(#tSuchPuffer[1]), N := 16)
                    OR SHL(IN := BYTE_TO_DWORD(#tSuchPuffer[2]), N := 8)
                    OR BYTE_TO_DWORD(#tSuchPuffer[3]);

        // Mindestens ein Suchwort <> 0 ?
        #tGefunden := FALSE;
        FOR #i := 0 TO #Stammdaten - 1 DO
            IF (#tSuchPuffer[#i * 2] <> 16#00) OR (#tSuchPuffer[#i * 2 + 1] <> 16#00) THEN
                #tGefunden := TRUE;
                EXIT;
            END_IF;
        END_FOR;
        IF NOT #tGefunden THEN
            GOTO mErr4;   // Undefinierte Stammdaten
        END_IF;
    END_REGION

    REGION NW6: Indiziert suchen ?
        IF (#IndDB <> 16#0000) AND NOT #Offsetsuchen AND NOT #Sortliste THEN
            "TEST_DB_TO_ATTR_DB"(DB_Number := #IndDB,
                                 RetVal => #SFC_RET_VAL,
                                 DB_Length => #SFC_DB_LENGTH,
                                 Write_Prot => #SFC_WRITE_PROT);
            "BCD (4stellig)_to_INT"(BCD_Wert := #SFC_DB_LENGTH, Int_Wert => #DB_Laenge);

            IF (#SFC_RET_VAL = 0) AND NOT #SFC_WRITE_PROT              // Indizier-DB vorhanden
               AND NOT (#IndDB_Laenge * 2 > #DB_Laenge)                // Indizier-DB lang genug
               AND (#Stammdaten < 3) THEN                              // nicht zu viele Stammdaten
                #Wandel_FC := #IndDaten_FC;
                IF #Wandel_FC > 0 THEN
                    "MW90" := #Daten_1;   // Stammdaten (1.DW) uebergeben
                    "MD94" := #Daten_2;   // Stammdaten (1.+2.DW) uebergeben
                    CASE #Wandel_FC OF   // AWL: UC FC[#Wandel_FC]
                        1000:
                            "Wandel_FC_für_DB1000"();
                        ELSE
                            ;   // unbekannter Wandel-FC: MW92 bleibt unveraendert
                    END_CASE;
                    #tIndex := WORD_TO_INT("MW92");   // Rueckwert vom FC
                ELSE
                    #tIndex := WORD_TO_INT(#Daten_1);   // Stammdaten direkt als Index
                END_IF;

                IF (#tIndex >= 0) AND (#tIndex < #IndDB_Laenge) THEN   // Zeiger im Ind.DB ?
                    #IndByteOfs := #tIndex * 2;   // DB byteorientiert
                    #tDbInd := INT_TO_DINT(WORD_TO_INT(#IndDB));
                    #Suchzeiger := WORD_TO_INT(PEEK_WORD(area := 16#84, dbNumber := #tDbInd,
                                                         byteOffset := INT_TO_DINT(#IndByteOfs)));
                    #Indok := TRUE;   // Indizierung moeglich
                    #IndZeiger_ok := TRUE;   // Indizier-Zeiger angegeben
                END_IF;
            END_IF;
        END_IF;
    END_REGION

    REGION NW7: Kontrolle auf gleiche Stammdaten (Suchschleife)
        IF (#Suchzeiger = 0)
           OR (((#Suchzeiger - 20) MOD #Datenblock_inBytes) <> 0) THEN   // Suchzeiger nicht im Raster
            // Suche bei 1.Datensatz beginnen (AWL: W700)
            #Suchstelle := 1;
            #IndZeiger_ok := FALSE;
            #Suchzeiger := #SSDW + 20;
        ELSE
            #Suchstelle := 0;   // Bei angegebener Stelle suchen
        END_IF;

        REPEAT
            // Stammdaten vergleichen (AWL: W701/L700-Schleife)
            #tGefunden := TRUE;
            FOR #i := 0 TO #Stammdaten - 1 DO
                #tWort := SHL(IN := BYTE_TO_WORD(#tSuchPuffer[#i * 2]), N := 8)
                          OR BYTE_TO_WORD(#tSuchPuffer[#i * 2 + 1]);
                IF #tWort <> PEEK_WORD(area := 16#84, dbNumber := #tDbList,
                                       byteOffset := INT_TO_DINT(#Suchzeiger + #OffsetDaten_1 + #i * 2)) THEN
                    #tGefunden := FALSE;
                    EXIT;
                END_IF;
            END_FOR;

            IF #tGefunden THEN
                #tRE_VAL := 16#80;   // Daten sind vorhanden
                GOTO mNw08;   // Datensatz ist in Liste enthalten
            END_IF;

            // AWL: W703
            IF #Suchstelle = 0 THEN
                // Suche bei angegebener Stelle erfolglos: ab 1.Datensatz neu (AWL: W700)
                #Suchstelle := 1;
                #IndZeiger_ok := FALSE;
                #Suchzeiger := #SSDW + 20;
            ELSE
                #Suchstelle := #Suchstelle + 1;
                IF #Suchstelle > #Listenlaenge THEN   // Alle Datensaetze durchsucht
                    GOTO mErr6;   // Datensatz ist nicht vorhanden
                END_IF;
                #Suchzeiger := #Suchzeiger + #Datenblock_inBytes;   // AWL: W705
            END_IF;
        UNTIL FALSE END_REPEAT;
    END_REGION

    REGION NW8+NW9: Datensatz an OUTDATEN uebergeben
mNw08:  FILL_BLK(IN := BYTE#16#00, COUNT := 258, OUT => #tRecPuffer[0]);

        FOR #i := 0 TO #Datensatzlaenge * 2 - 1 DO
            #tRecPuffer[#i] := PEEK(area := 16#84, dbNumber := #tDbList,
                                    byteOffset := INT_TO_DINT(#Suchzeiger + #i));
        END_FOR;

        #tPos := 0;
        #SFC_RET_VAL := Deserialize(SRC_ARRAY := #tRecPuffer, DEST_VARIANT := #OUTDATEN, POS := #tPos);
        IF #SFC_RET_VAL <> 0 THEN
            GOTO mErr1;   // Kopier-Fehler (AWL: SFC20-Aufruf mit Fehler)
        END_IF;

        IF NOT #SFC_WRITE_PROT THEN   // Datenliste kann beschrieben werden
            // Speicherung letzter Zugriff
            POKE(area := 16#84, dbNumber := #tDbList, byteOffset := INT_TO_DINT(#SSDW + 12),
                 value := INT_TO_WORD(#Suchzeiger));
            #Position := #Suchstelle;   // Uebergabe nach aussen
        END_IF;
    END_REGION

    REGION NW10+NW11: Daten aus Datenliste loeschen ?
        IF (#Para1 = 16#E1) AND NOT #SFC_WRITE_PROT THEN   // Daten loeschen ?
            IF #Indok THEN
                // NW11: Bei ind. Zugriff nur loeschen, nicht verschieben, keine Anzahl!
                FOR #i := 0 TO #Datensatzlaenge - 1 DO
                    POKE(area := 16#84, dbNumber := #tDbList,
                         byteOffset := INT_TO_DINT(#Suchzeiger + #i * 2), value := WORD#16#0000);
                END_FOR;
                POKE(area := 16#84, dbNumber := #tDbList, byteOffset := INT_TO_DINT(#SSDW + 12),
                     value := WORD#16#0000);   // letzter Zugriff loeschen
                #Suchzeiger := 0;
                #IndZeiger_ok := FALSE;
            ELSE
                // NW10: loeschen + nachfolgende Datensaetze vorschieben
                #LoeschPos := (#Suchzeiger - 20 - #SSDW) / #Datenblock_inBytes + 1;   // Stelle, die geloescht wird
                IF #LoeschPos <> #Listenlaenge THEN   // nicht der letzte Eintrag
                    // Daten verschieben (AWL: BLKMOV; hier bytewise vorwaerts = sicher bei Ueberlappung)
                    #tAnzBytes := (#Listenlaenge - #LoeschPos) * #Datenblock_inBytes;
                    FOR #i := 0 TO #tAnzBytes - 1 DO
                        POKE(area := 16#84, dbNumber := #tDbList,
                             byteOffset := INT_TO_DINT(#Suchzeiger + #i),
                             value := PEEK(area := 16#84, dbNumber := #tDbList,
                                           byteOffset := INT_TO_DINT(#Suchzeiger + #Datenblock_inBytes + #i)));
                    END_FOR;
                END_IF;

                // Letzten Eintrag loeschen (AWL: Last)
                FOR #i := 0 TO #Datensatzlaenge - 1 DO
                    POKE(area := 16#84, dbNumber := #tDbList,
                         byteOffset := INT_TO_DINT(#Datenlisten_Ende - #Datenblock_inBytes + #i * 2),
                         value := WORD#16#0000);
                END_FOR;

                // Speicherung letzter Zugriff loeschen
                POKE(area := 16#84, dbNumber := #tDbList, byteOffset := INT_TO_DINT(#SSDW + 12),
                     value := WORD#16#0000);
                #Suchzeiger := 0;
                #IndZeiger_ok := FALSE;

                // Anzahl Eintraege -1 (Minimum 0)
                #tAnz := WORD_TO_INT(PEEK_WORD(area := 16#84, dbNumber := #tDbList,
                                               byteOffset := INT_TO_DINT(#SSDW + 16))) - 1;
                IF #tAnz < 0 THEN
                    #tAnz := 0;   // Minimum uebergeben
                END_IF;
                POKE(area := 16#84, dbNumber := #tDbList, byteOffset := INT_TO_DINT(#SSDW + 16),
                     value := INT_TO_WORD(#tAnz));
            END_IF;
        END_IF;
    END_REGION

    REGION NW12: Weitersuchen aktiv ? Datensatz vorhanden oder 0 ?
        IF #Weitersuchen THEN
            #tGefunden := FALSE;
            FOR #i := 0 TO #Datensatzlaenge - 1 DO
                IF (#tRecPuffer[#i * 2] <> 16#00) OR (#tRecPuffer[#i * 2 + 1] <> 16#00) THEN
                    #tGefunden := TRUE;   // Etwas angegeben
                    EXIT;
                END_IF;
            END_FOR;
            IF #tGefunden THEN
                #tRE_VAL := 16#80;   // Daten sind vorhanden
            ELSE
                #tRE_VAL := 16#40;   // Daten sind nicht vorhanden
            END_IF;
            GOTO mEnde;
        END_IF;
    END_REGION

    REGION NW13: Indizierung ok ?
        IF #Indok AND NOT #IndZeiger_ok THEN
            // Index-Eintrag im indizierten DB aktualisieren
            POKE(area := 16#84, dbNumber := #tDbInd, byteOffset := INT_TO_DINT(#IndByteOfs),
                 value := INT_TO_WORD(#Suchzeiger));
        END_IF;
    END_REGION

    REGION NW14+NW15: Fehlerausgabe / RET_VAL
mEnde:  #tVKE := TRUE;   // VKE = 1 ohne Fehler !!!
        GOTO mOk;

mErr0:  #tRE_VAL := 16#01;   // Kein Datenlistenbereich
        GOTO mErrX;
mErr1:  #tRE_VAL := 16#02;   // Kopier-/SFC-Fehler
        GOTO mErrX;
mErr2:  #tRE_VAL := 16#04;   // Listenende ist erreicht
        GOTO mErrX;
mErr3:  #tRE_VAL := 16#08;   // Falscher Parameter bei Aufruf
        GOTO mErrX;
mErr4:  #tRE_VAL := 16#10;   // Undefinierte Suchdaten
        GOTO mErrX;
mErr6:  #tRE_VAL := 16#40;   // Datensatz nicht vorhanden

mErrX:  #tVKE := FALSE;   // VKE = 0 bei Fehler !!!

mOk:    #RE_VAL := #tRE_VAL;
        ENO := #tVKE;   // AWL: SAVE (BR-Bit fuer JBI beim Aufrufer)
    END_REGION
END_FUNCTION
