Files
HundM_awl/SCL-Export/=A01+UH07-KF00/DatenOut.scl
T

461 lines
21 KiB
Plaintext

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