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

304 lines
13 KiB
Plaintext

FUNCTION "FifoIn" : Void
TITLE = Datensatz in FIFO-DB eintragen
{ S7_Optimized_Access := 'FALSE' }
AUTHOR : IBAE
FAMILY : Module
NAME : FifoIn
//SCL-Portierung des AWL-Bausteins FC80 "FifoIn" (verhaltensgleich).
//
//FIFO-Kopf im Schnittstellen-DB ab Byte SSDW:
// +0 Kopf (Byte, 16#FF = FIFO-Kennung)
// +1 Datensatzlaenge (Byte, in Worten, 1..128)
// +2 FifoLaenge (Int, max. Anzahl Datensaetze)
// +4 Bringzeiger (Int, Byte-Adresse im DB)
// +6 Holzeiger (Int, Byte-Adresse im DB)
// +8 Anzahl (Int, eingetragene Datensaetze)
// +10 Status (Word)
// +12 Zusatzdaten (4 Worte)
// +40 Datenbereich, dahinter Endekennung 16#FFEE
//
//ABWEICHUNG ZUM AWL-ORIGINAL:
// - INDATEN ist jetzt VARIANT statt POINTER (S7-1500/SCL). AWL-/SCL-Aufrufer
// uebergeben weiterhin einen Bereich (z.B. P#M220.0 WORD 6 bzw. ein Symbol).
// - Registerindirekte DB-Zugriffe sind durch PEEK/POKE ersetzt (DB-Layout identisch).
// - Erfolg wird wie bisher ueber ENO/BR gemeldet (Aufrufer: JBI bzw. IF ENO).
VAR_INPUT
SSDB : Int; // Schnittstellen-DB
SSDW : Int; // Schnittstellen-1.DW (Byte-Offset des FIFO-Kopfs)
PARA : Word; // Aufrufparameter (Auftrag / Anzahl Zusatzdaten)
INDATEN : Variant; // InDaten-Schnittstelle (Datensatz, Datensatzlaenge Worte)
END_VAR
VAR_OUTPUT
RE_VAL : Byte; // Rueckmeldung (Fehlerbits)
END_VAR
VAR_TEMP
Kopf : Byte; // Fifo-Kennung (FF)
Datensatzlaenge : Byte; // Datensatzlaenge in Word (1 - 128)
FifoLaenge : Int; // Laenge des Fifo (maximale Anzahl der Datensaetze)
Bringzeiger : Int; // Zeiger, wohin naechster Eintrag gespeichert wird
Holzeiger : Int; // Zeiger, woher naechste Daten geholt werden
Anzahl : Int; // Anzahl der Datensaetze (eingetragene)
Status : Word; // Status des Fifo
Err : Byte; // Fehlerbits
Para1 : Byte; // 1.Aufrufparameter
Para2 : Byte; // 2.Aufrufparameter
Para21 : Byte; // 2.Aufrufparameter 1.Stelle
Para22 : Byte; // 2.Aufrufparameter 2.Stelle
MinBringzeiger : Int; // Minimum Bringzeiger
MaxBringzeiger : Int; // Maximum Bringzeiger
SFC_RET_VAL : Int; // Rueckmeldung TEST_DB-/Serialize-Aufruf
SFC_DB_LENGTH : Word; // DB-Laenge in Bytes
Fifo_Ende : Int; // Ende des Fifo (Byte-Offset Endekennung)
Offset : Int; // Offset 1. zu speicherndes Zusatzwort (Bytes)
SFC_WRITE_PROT : Bool; // DB ist schreibgeschuetzt
NixSave : Bool; // Status nicht speichern
tVKE : Bool; // Ergebnis fuer ENO (BR im AWL)
tDbNo : DInt; // DB-Nummer fuer PEEK/POKE
tAnzWorte : Int; // Anzahl zu kopierender Worte
tPos : DInt; // Serialize-Position
i : Int; // Schleifenzaehler
tPuffer : Array[0..257] of Byte; // Zwischenpuffer fuer INDATEN
END_VAR
BEGIN
REGION NW1: Schnittstellen-DB sinnvoll ?
#tDbNo := 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);
#NixSave := (#SFC_RET_VAL <> 0) OR #SFC_WRITE_PROT; // Status nicht speichern
IF #NixSave THEN
#Err := 16#01; // kein Fifobereich (AWL: Err0)
GOTO mErr;
END_IF;
END_REGION
REGION NW2: FIFO-Kopf holen (AWL: Quelle-Pointer + BLKMOV)
IF #SSDW < 0 OR (#SSDW + 12) > WORD_TO_INT(#SFC_DB_LENGTH) THEN
#Err.%X1 := TRUE; // Kopf liegt nicht im DB (AWL: SFC20-Fehler, Err1)
GOTO mErr;
END_IF;
#Kopf := PEEK(area := 16#84, dbNumber := #tDbNo, byteOffset := INT_TO_DINT(#SSDW));
#Datensatzlaenge := PEEK(area := 16#84, dbNumber := #tDbNo, byteOffset := INT_TO_DINT(#SSDW + 1));
#FifoLaenge := WORD_TO_INT(PEEK_WORD(area := 16#84, dbNumber := #tDbNo, byteOffset := INT_TO_DINT(#SSDW + 2)));
#Bringzeiger := WORD_TO_INT(PEEK_WORD(area := 16#84, dbNumber := #tDbNo, byteOffset := INT_TO_DINT(#SSDW + 4)));
#Holzeiger := WORD_TO_INT(PEEK_WORD(area := 16#84, dbNumber := #tDbNo, byteOffset := INT_TO_DINT(#SSDW + 6)));
#Anzahl := WORD_TO_INT(PEEK_WORD(area := 16#84, dbNumber := #tDbNo, byteOffset := INT_TO_DINT(#SSDW + 8)));
#Status := PEEK_WORD(area := 16#84, dbNumber := #tDbNo, byteOffset := INT_TO_DINT(#SSDW + 10));
#Err := WORD_TO_BYTE(#Status AND 16#00E0); // Kapitalfehler aus frueheren Aufrufen?
IF #Err <> 16#00 THEN
GOTO mErr;
END_IF;
END_REGION
REGION NW3: Zeigerueberpruefung
IF #Kopf <> 16#FF THEN // keine Fifokennung
#NixSave := TRUE;
#Err := 16#01; // kein Fifobereich
GOTO mErr;
END_IF;
IF BYTE_TO_INT(#Datensatzlaenge) < 1 OR BYTE_TO_INT(#Datensatzlaenge) > 128 THEN
#Err := 16#01; // kein Fifobereich
GOTO mErr;
END_IF;
IF #FifoLaenge < 1 THEN
#Err := 16#01; // kein Fifobereich
GOTO mErr;
END_IF;
#MinBringzeiger := #SSDW + 40; // Speichern ab 20.DW
#MaxBringzeiger := (#FifoLaenge - 1) * BYTE_TO_INT(#Datensatzlaenge) * 2 + 40 + #SSDW;
#Fifo_Ende := BYTE_TO_INT(#Datensatzlaenge) * 2 + #MaxBringzeiger; // Zeiger Endekennung
IF #Fifo_Ende > WORD_TO_INT(#SFC_DB_LENGTH) THEN // Fifo-DB ist zu kurz!
#Err := 16#01; // kein Fifo-Bereich
GOTO mErr;
END_IF;
IF PEEK_WORD(area := 16#84, dbNumber := #tDbNo, byteOffset := INT_TO_DINT(#Fifo_Ende)) <> 16#FFEE THEN
#Err := 16#01; // kein Fifobereich (Endekennung fehlt)
GOTO mErr;
END_IF;
IF #MinBringzeiger > #Bringzeiger THEN
// Nur zulaessig, wenn alles in Grundstellung: dann initialisieren
IF #Bringzeiger <> 0 OR #Holzeiger <> 0 OR #Anzahl <> 0 THEN
#Err.%X5 := TRUE; // Bringzeiger ist ausserhalb
GOTO mErr;
END_IF;
#Bringzeiger := #MinBringzeiger;
#Holzeiger := #MinBringzeiger;
END_IF;
IF #Bringzeiger > #MaxBringzeiger THEN
#Err.%X5 := TRUE; // Bringzeiger ist ausserhalb
GOTO mErr;
END_IF;
IF (#Bringzeiger = #Holzeiger) AND (#FifoLaenge <> #Anzahl) AND (#Anzahl <> 0) THEN
#Err.%X7 := TRUE; // Versatz Bring-/Holzeiger
GOTO mErr;
END_IF;
IF (#Bringzeiger <> #Holzeiger) AND ((#FifoLaenge = #Anzahl) OR (#Anzahl = 0)) THEN
#Err.%X7 := TRUE; // Versatz Bring-/Holzeiger
GOTO mErr;
END_IF;
END_REGION
REGION NW4: Nur Zusatzdaten / als 1.Datensatz speichern ?
#Para1 := WORD_TO_BYTE(SHR(IN := #PARA, N := 8)); // 1.Aufrufparameter
#Para2 := WORD_TO_BYTE(#PARA); // 2.Aufrufparameter
IF #Para1 = 16#02 THEN // Nur Zusatzdaten speichern
IF #Para2 = 16#00 THEN
#Err.%X3 := TRUE; // Falscher Aufrufparameter
GOTO mErr;
END_IF;
GOTO mNw06; // Zusatzdaten speichern
END_IF;
IF #Para1 = 16#01 THEN // Als 1.Datensatz speichern
#Bringzeiger := #MinBringzeiger;
#Holzeiger := #MinBringzeiger;
#Anzahl := 0;
GOTO mNw06; // Zusatz-Daten speichern?
END_IF;
END_REGION
REGION NW5: Hat Fifo Platz / Datenbereich leer ?
IF #Anzahl >= #FifoLaenge THEN
IF #Anzahl = #FifoLaenge THEN
#Err.%X2 := TRUE; // Fifo ist voll
ELSE
#Err.%X7 := TRUE; // Versatz Bring-/Holzeiger
END_IF;
GOTO mErr;
END_IF;
// Ziel-Speicherzellen muessen leer (0) sein
FOR #i := 0 TO BYTE_TO_INT(#Datensatzlaenge) - 1 DO
IF PEEK_WORD(area := 16#84, dbNumber := #tDbNo,
byteOffset := INT_TO_DINT(#Bringzeiger + #i * 2)) <> 16#0000 THEN
#Err.%X4 := TRUE; // Speicherzelle ist belegt
GOTO mErr;
END_IF;
END_FOR;
END_REGION
REGION NW6: Zusatzdaten schreiben (Quelle: Merker ab MB240)
mNw06: IF #Para2 <> 16#00 THEN
#Para21 := SHR(IN := #Para2 AND 16#F0, N := 4); // 1.Stelle isolieren (von)
#Para22 := #Para2 AND 16#0F; // 2.Stelle isolieren (bis)
IF (#Para21 > #Para22) // 1.Stelle > 2.Stelle !
OR (#Para22 > 16#04) // 2.Stelle > 4 !
OR (#Para21 = 16#00) THEN // 1.Stelle = 0 !
#Err.%X3 := TRUE; // Falscher Aufrufparameter
GOTO mErr;
END_IF;
#tAnzWorte := BYTE_TO_INT(#Para22) - BYTE_TO_INT(#Para21) + 1;
#Offset := (BYTE_TO_INT(#Para21) - 1) * 2; // Offset 1. zu speicherndes Zusatzwort
// Quelle: MB240+Offset -> Ziel: DB ab SSDW+12+Offset (ab 6.DW)
FOR #i := 0 TO #tAnzWorte * 2 - 1 DO
POKE(area := 16#84, dbNumber := #tDbNo,
byteOffset := INT_TO_DINT(#SSDW + 12 + #Offset + #i),
value := PEEK(area := 16#83, dbNumber := 0,
byteOffset := INT_TO_DINT(240 + #Offset + #i)));
END_FOR;
END_IF;
END_REGION
REGION NW7: Fifodaten schreiben
IF #Para1 = 16#FF THEN // Testsendung: Zeiger nur testweise veraendern
GOTO mNw08;
END_IF;
IF #Para1 = 16#02 THEN // Nur Zusatzdaten speichern: fertig!
GOTO mEnde;
END_IF;
// INDATEN in Zwischenpuffer holen (AWL: BLKMOV ueber uebergebenen Pointer)
#tPos := 0;
#SFC_RET_VAL := Serialize(SRC_VARIANT := #INDATEN, DEST_ARRAY := #tPuffer, POS := #tPos);
IF (#SFC_RET_VAL <> 0) OR (#tPos < BYTE_TO_INT(#Datensatzlaenge) * 2) THEN
#Err.%X1 := TRUE; // Kopier-Fehler (AWL: SFC20-Aufruf mit Fehler)
GOTO mErr;
END_IF;
// Datensatz ab Bringzeiger in FIFO-DB schreiben
FOR #i := 0 TO BYTE_TO_INT(#Datensatzlaenge) * 2 - 1 DO
POKE(area := 16#84, dbNumber := #tDbNo,
byteOffset := INT_TO_DINT(#Bringzeiger + #i),
value := #tPuffer[#i]);
END_FOR;
END_REGION
REGION NW8: Bringzeiger, Anzahl erhoehen
mNw08: #Bringzeiger := BYTE_TO_INT(#Datensatzlaenge) * 2 + #Bringzeiger;
IF #Bringzeiger > #MaxBringzeiger THEN // Maximum erreicht?
#Bringzeiger := #MinBringzeiger;
END_IF;
#Anzahl := #Anzahl + 1;
END_REGION
REGION NW9: Versatz Bring-/Holzeiger
IF (#Bringzeiger = #Holzeiger) AND (#FifoLaenge <> #Anzahl) THEN
#Err.%X7 := TRUE; // Versatz Bring-/Holzeiger
GOTO mErr;
END_IF;
IF (#Bringzeiger <> #Holzeiger) AND (#FifoLaenge = #Anzahl) THEN
#Err.%X7 := TRUE; // Versatz Bring-/Holzeiger
GOTO mErr;
END_IF;
END_REGION
REGION NW10: Fehlerausgabe / RET_VAL
mEnde: #tVKE := TRUE; // VKE = 1 ohne Fehler !!!
GOTO mOk;
mErr: #tVKE := FALSE; // VKE = 0 bei Fehler !!!
mOk: #RE_VAL := #Err;
END_REGION
#Status := #Status OR BYTE_TO_WORD(#Err);
REGION NW11: Fifokopfdaten speichern
IF #Err.%X0 AND #NixSave THEN // kein gueltiger Fifobereich: nichts speichern
ENO := #tVKE;
RETURN;
END_IF;
"MW254" := INT_TO_WORD(#Anzahl - 1); // Uebergabe an FC+1 (da vorher zum Test erhoeht wurde)
IF #Para1 = 16#FF THEN // Testsendung: Zeiger wurden nur testweise geaendert!
ENO := #tVKE;
RETURN;
END_IF;
// Bringzeiger, Holzeiger, Anzahl, Status in FIFO-Kopf zuruecksichern (ab SSDW+4)
POKE(area := 16#84, dbNumber := #tDbNo, byteOffset := INT_TO_DINT(#SSDW + 4), value := INT_TO_WORD(#Bringzeiger));
POKE(area := 16#84, dbNumber := #tDbNo, byteOffset := INT_TO_DINT(#SSDW + 6), value := INT_TO_WORD(#Holzeiger));
POKE(area := 16#84, dbNumber := #tDbNo, byteOffset := INT_TO_DINT(#SSDW + 8), value := INT_TO_WORD(#Anzahl));
POKE(area := 16#84, dbNumber := #tDbNo, byteOffset := INT_TO_DINT(#SSDW + 10), value := #Status);
"MW248" := INT_TO_WORD(#FifoLaenge); // Uebergabe an FC+1 (fuer Durchlaufspeicher)
"MW250" := INT_TO_WORD(#Bringzeiger); // Uebergabe an FC+1 (fuer Durchlaufspeicher)
"MW252" := INT_TO_WORD(#Holzeiger); // Uebergabe an FC+1 (fuer Durchlaufspeicher)
"MW254" := INT_TO_WORD(#Anzahl); // Uebergabe an FC+1 (fuer Durchlaufspeicher)
END_REGION
ENO := #tVKE; // AWL: SAVE (BR-Bit fuer JBI beim Aufrufer)
END_FUNCTION