|
|
|
@@ -0,0 +1,389 @@
|
|
|
|
|
FUNCTION_BLOCK "LGF_FIFO"
|
|
|
|
|
TITLE = LGF_FIFO
|
|
|
|
|
{ S7_Optimized_Access := 'TRUE' }
|
|
|
|
|
AUTHOR : Siemens_Industry_Support
|
|
|
|
|
FAMILY : LGF
|
|
|
|
|
NAME : LGF_FIFO
|
|
|
|
|
//FIFO (First-In First-Out / Queue / Ringspeicher)
|
|
|
|
|
//Diese Funktion speichert eingehende Daten und gibt die ältesten noch nicht abgearbeiteten Daten aus.
|
|
|
|
|
//
|
|
|
|
|
VAR_INPUT
|
|
|
|
|
enqueue : Bool := false; // Element einreihen in den Puffer (Enqueue)
|
|
|
|
|
dequeue : Bool := false; // Element aus dem Puffer löschen und an `item` zurückgeben (Dequeue)
|
|
|
|
|
reset : Bool; // Puffer initialisieren (Index und Zähler zurücksetzen)
|
|
|
|
|
clear : Bool; // Puffer leeren und mit Anfangswert `initialItem` initialisieren (Index und Zähler zurücksetzen).
|
|
|
|
|
initialItem : Variant; // Wert mit dem das Array des Puffer initialisiert wird (meistens: `0` / default wert)
|
|
|
|
|
maxElementCount : UInt; // Maximale Anzahl an Elementen im FIFO
|
|
|
|
|
END_VAR
|
|
|
|
|
|
|
|
|
|
VAR_OUTPUT
|
|
|
|
|
error { ExternalWritable := 'False'} : Bool; // FALSE: Kein Fehler TRUE: Während der Ausführung des FB ist ein Fehler aufgetreten
|
|
|
|
|
status { ExternalWritable := 'False'} : Word; // 16#0000-16#7FFF: Status des FB 16#8000-16#FFFF: Fehleridentifikation (siehe folgende Tabelle)
|
|
|
|
|
subFunctionStatus { ExternalWritable := 'False'} : Word; // Status oder Rückgabewert von aufgerufenen FB's / FC's und Systemfunktionen
|
|
|
|
|
END_VAR
|
|
|
|
|
VAR_OUTPUT RETAIN
|
|
|
|
|
elementCount { ExternalWritable := 'False'} : USInt := 0; // Anzahl der Elemente im Puffer
|
|
|
|
|
isEmpty { ExternalWritable := 'False'} : Bool := TRUE; // TRUE: Puffer ist leer
|
|
|
|
|
isFull : Bool;
|
|
|
|
|
END_VAR
|
|
|
|
|
VAR_OUTPUT
|
|
|
|
|
oldestElement : Int;
|
|
|
|
|
enqueueDone : Bool;
|
|
|
|
|
dequeueDone : Bool;
|
|
|
|
|
END_VAR
|
|
|
|
|
|
|
|
|
|
VAR_IN_OUT
|
|
|
|
|
itemIn : Variant; // Eintrag der aus dem Puffer zurückgegeben wird oder in den Puffer geschrieben werden soll
|
|
|
|
|
buffer : Variant; // Das ARRAY welches als Puffer genutzt wird. (Array of … )
|
|
|
|
|
itemOut : Variant;
|
|
|
|
|
END_VAR
|
|
|
|
|
|
|
|
|
|
VAR RETAIN
|
|
|
|
|
statEdgesMem { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Struct // Flanken speicher zum speichern des vorherigen Zustands und Flankendetektion
|
|
|
|
|
enqueue { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool; // enqueue Flanke
|
|
|
|
|
dequeue { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool; // dequeue Flanke
|
|
|
|
|
clear { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool; // clearing Flanke
|
|
|
|
|
END_STRUCT;
|
|
|
|
|
statFirstItemIndex { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int := -1; // Index des ältesten Eintrags im Puffer
|
|
|
|
|
statNextEmptyItemIndex { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int := 0; // Index für den nächsten freien Platz im Puffer
|
|
|
|
|
statElementCount { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : DInt; // Anzahl der Elemente im Puffer
|
|
|
|
|
END_VAR
|
|
|
|
|
|
|
|
|
|
VAR_TEMP
|
|
|
|
|
tempEdges : Struct // Flanken speicher zum speichern der Flanken
|
|
|
|
|
enqueue : Bool; // enqueue Flanke
|
|
|
|
|
dequeue : Bool; // dequeue Flanke
|
|
|
|
|
clear : Bool; // clearing Flanke
|
|
|
|
|
END_STRUCT;
|
|
|
|
|
tempInternalError : Int; // Fehler Information für interne Funktionsaufrufe und Rückgabewerte
|
|
|
|
|
tempNewFirstItemIndex : Int; // Variable Index
|
|
|
|
|
tempNewNextEmptyItemIndex : Int; // Variable Index
|
|
|
|
|
tempBufferSize : UDInt; // Anzahl der Elemente im Puffer Array / Puffer Größe
|
|
|
|
|
tempCounter : Int; // Zählvariable für die Iteration durch den Puffer
|
|
|
|
|
END_VAR
|
|
|
|
|
|
|
|
|
|
VAR CONSTANT
|
|
|
|
|
BUFFER_IS_EMPTY : Int := -1; // Puffer ist leer
|
|
|
|
|
NO_INTERNAL_ERROR : Int := 0; // Kein interner Fehler
|
|
|
|
|
BUFFER_INITIALIZED : Int := -1; // Puffer initialisieren
|
|
|
|
|
EMPTY_INITIALIZED : Int := 0; // Leeres Element Index = 0
|
|
|
|
|
INDEX_BEGINNING : Int := 0; // Startwert für die Indizierung des Arrays
|
|
|
|
|
COUNT_ELEMENTS : UDInt := 1; // Anzahl der zu kopierenden Elemente = 1
|
|
|
|
|
INCREMENT : Int := 1; // Inkrement Wert EINS
|
|
|
|
|
BUFFER_SIZE_CORRECTION : UDInt := 1; // Puffer Größen Korrekturfaktor (0-basierte Zählung)
|
|
|
|
|
COUNTER_LOWER_LIMIT : Int := 0; // Zähler untere Grenze
|
|
|
|
|
ZERO_ELEMENTS : DInt := 0; // Keine Elemente vorhanden
|
|
|
|
|
STATUS_NO_ERROR : Word := 16#0000; // Status: Abarbeitung ohne Fehler beendet
|
|
|
|
|
STATUS_NO_CURRENT_JOBS : Word := 16#7000; // Status: Keine aktuellen Aufträge, Initial State
|
|
|
|
|
ERR_BUFFER_EMPTY : Word := 16#8001; // Fehler: Der Puffer ist leer
|
|
|
|
|
ERR_BUFFER_FULL : Word := 16#8002; // Fehler: Der Puffer ist voll
|
|
|
|
|
ERR_NO_ARRAY : Word := 16#8200; // Fehler: Am Eingang `buffer` liegt kein Array an.
|
|
|
|
|
ERR_WRONG_TYPE_ITEM : Word := 16#8201; // Fehler: Der Datentyp des InOut-Parameters `item` entspricht nicht dem Datentyp der Array-Elemente von dem Eingang `buffer`.
|
|
|
|
|
ERR_WRONG_TYPE_INITIAL_ITEM : Word := 16#8202; // Fehler: Der Datentyp des Eingangs `initialItem` entspricht nicht dem Datentyp des InOut-Parameters `item`.
|
|
|
|
|
ERR_INDEX_IN_ARRAY_LIMITS_1 : Word := 16#8601; // Fehler: Die Variable `statNextEmptyItemIndex` liegt ausserhalb der Array Grenzen
|
|
|
|
|
ERR_INDEX_IN_ARRAY_LIMITS_2 : Word := 16#8602; // Fehler: Die Variable `statFirstItemIndex` liegt ausserhalb der Array Grenzen
|
|
|
|
|
ERR_CLEAR_BUFFER : Word := 16#8610; // Fehler: Während des Ablöschen des Puffer in Funktion `MOVE_BLK_VARIANT` - weitere Infos in `subFunctionStatus`
|
|
|
|
|
ERR_RETURN_FIRST_ENTRY : Word := 16#8611; // Fehler: Während der Rückgabe des ersten Elements aus dem Puffer in Funktion `MOVE_BLK_VARIANT` - weitere Infos in `subFunctionStatus`
|
|
|
|
|
ERR_REPLACE_ITEM_BY_INIT_VALUE : Word := 16#8612; // Fehler: Während des Überschreibens des Elements mit dem Initialwort in Funktion `MOVE_BLK_VARIANT` - weitere Infos in `subFunctionStatus
|
|
|
|
|
ERR_WRITE_ENTRY : Word := 16#8613; // Fehler: Während des Schreibens eines Elements in den Puffer in Funktion `MOVE_BLK_VARIANT` - weitere Infos in `subFunctionStatus`
|
|
|
|
|
END_VAR
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BEGIN
|
|
|
|
|
REGION Block info header
|
|
|
|
|
//===============================================================================
|
|
|
|
|
// SIEMENS AG / (c)Copyright 2019
|
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
|
// Title: LGF_FIFO
|
|
|
|
|
// Comment/Function: FIFO (First In First Out)
|
|
|
|
|
// Queue / ring buffer memory
|
|
|
|
|
// Library/Family: LGF (Library General Functions)
|
|
|
|
|
// Author: Siemens Digital Industry Support
|
|
|
|
|
// Tested with: CPU 1515F-2 PN FW:V2.6
|
|
|
|
|
// Engineering: TIA Portal V15.1 Update 2
|
|
|
|
|
// Restrictions: ENO disabled - error handling done with error and status
|
|
|
|
|
// Requirements: PLC (S7-1200 / S7-1500)
|
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
|
// Change log table:
|
|
|
|
|
// Version | Date | Expert in charge | Changes applied
|
|
|
|
|
//----------|------------|------------------------|------------------------------
|
|
|
|
|
// 01.00.00 19.08.2015 Siemens Industry Online Support
|
|
|
|
|
// First released version
|
|
|
|
|
// 01.00.01 16.11.2015 Siemens Industry Online Support
|
|
|
|
|
// Bug fix resetBuffer
|
|
|
|
|
// 01.00.02 02.01.2017 Siemens Industry Online Support
|
|
|
|
|
// Upgrade: TIA Portal V14 Update 1
|
|
|
|
|
// 01.00.03 17.08.2018 Siemens Industry Online Support
|
|
|
|
|
// Upgrade: TIA V15 Update 2
|
|
|
|
|
// 01.00.04 23.11.2018 Siemens Industry Online Support
|
|
|
|
|
// Upgrade: TIA V15.1
|
|
|
|
|
// 02.00.00 29.01.2019 Siemens Industry Online Support
|
|
|
|
|
// Output "done" removed (not necessary, because block works synchronous)
|
|
|
|
|
// 03.00.00 22.10.2019 Simatic Systems Support
|
|
|
|
|
// Code refactoring, comments added
|
|
|
|
|
// Interface change (enqueue, dequeue etc.)
|
|
|
|
|
// Set version to V3.0.0, harmonize the version of the whole library
|
|
|
|
|
// 03.00.01 15.02.2021 Simatic Systems Support
|
|
|
|
|
// Insert documentation
|
|
|
|
|
//=============================================================================
|
|
|
|
|
END_REGION Block info header
|
|
|
|
|
|
|
|
|
|
REGION DESCRIPTION
|
|
|
|
|
(/*
|
|
|
|
|
Hinweis
|
|
|
|
|
: In `subFunctionStatus` wird der Status von aufgerufenen Anweisungen ausgegeben. Der Ausgangswert in `status` gibt in diesem Fall an, welche Anweisung den Fehler verursacht hat. Holen Sie sich in diesem Fall die Informationen aus der TIA Portal Online Hilfe zu den jeweiligen Anweisungen.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
Hinweis
|
|
|
|
|
: Die Warteschlange (Queue) in der Informatik beruht ebenfalls auf dem FIFO-Prinzip.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
Mit dem Eingang `enqueue` wird ein neues Element vom InOut-Parameter `item` an der nächsten freien Stelle im Puffer gespeichert. Der Ausgang `elementCount` wird um eins inkrementiert.
|
|
|
|
|
|
|
|
|
|
Mit dem Eingang `dequeue` ausgegeben und dieses Feld im Puffer durch den Wert am Parameter `initialItem` ersetzt. Der Ausgang `elementCount` wird um eins dekrementiert.
|
|
|
|
|
|
|
|
|
|
Mit dem Eingang `reset` wird der Puffer initialisiert, Index und Zähler werden zurückgesetzt. Der Ausgang `elementCount` wird auf null und der Ausgang `isEmpty` wird auf TRUE gesetzt.
|
|
|
|
|
|
|
|
|
|
Mit dem Eingang `clear` wird der Puffer geleert und mit Anfangswert `initialItem` initialisiert. Index und Zähler werden zurückgesetzt. Der Ausgang `elementCount` wird auf null, der Ausgang `isEmpty` auf TRUE gesetzt.
|
|
|
|
|
*/)
|
|
|
|
|
END_REGION DESCRIPTION
|
|
|
|
|
|
|
|
|
|
REGION Block execution control
|
|
|
|
|
|
|
|
|
|
#enqueueDone := FALSE;
|
|
|
|
|
#dequeueDone := FALSE;
|
|
|
|
|
// collect edges
|
|
|
|
|
#tempEdges.dequeue := #dequeue AND NOT #statEdgesMem.dequeue;
|
|
|
|
|
#tempEdges.clear := #clear AND NOT #statEdgesMem.clear;
|
|
|
|
|
// store values for edge detection
|
|
|
|
|
IF NOT #dequeue THEN
|
|
|
|
|
#tempEdges.enqueue := #enqueue AND NOT #statEdgesMem.enqueue;
|
|
|
|
|
#statEdgesMem.enqueue := #enqueue;
|
|
|
|
|
END_IF;
|
|
|
|
|
#statEdgesMem.dequeue := #dequeue;
|
|
|
|
|
#statEdgesMem.clear := #clear;
|
|
|
|
|
|
|
|
|
|
// This program code section is only executed if no trigger input is active
|
|
|
|
|
IF NOT (#enqueue OR #dequeue OR #reset OR #clear) THEN
|
|
|
|
|
// If an error occurred during program execution,
|
|
|
|
|
// the status "No Current Job" is used 16#7000 afterwarts when the triggers are reseted
|
|
|
|
|
#error := false;
|
|
|
|
|
#status := #STATUS_NO_CURRENT_JOBS;
|
|
|
|
|
#subFunctionStatus := #STATUS_NO_ERROR;
|
|
|
|
|
// the program processing OF the FB is terminated
|
|
|
|
|
RETURN;
|
|
|
|
|
END_IF;
|
|
|
|
|
END_REGION
|
|
|
|
|
|
|
|
|
|
REGION Validation of inputs
|
|
|
|
|
// check whether the ring #buffer is an ARRAY.
|
|
|
|
|
// IF so, the number OF the ARRAY elements is read out.
|
|
|
|
|
// IF it is NOT an ARRAY, the program execution is terminated at this point
|
|
|
|
|
IF IS_ARRAY(#buffer) THEN
|
|
|
|
|
#tempBufferSize := CountOfElements(#buffer);
|
|
|
|
|
ELSE
|
|
|
|
|
#error := true;
|
|
|
|
|
#status := #ERR_NO_ARRAY;
|
|
|
|
|
#subFunctionStatus := #STATUS_NO_ERROR;
|
|
|
|
|
RETURN;
|
|
|
|
|
END_IF;
|
|
|
|
|
|
|
|
|
|
// check whether the data type OF the ARRAY elements matches
|
|
|
|
|
// the data type OF the entry (#item). IF the data types DO NOT match,
|
|
|
|
|
// the program execution is terminated at this point
|
|
|
|
|
IF (TypeOf(#itemIn) <> TypeOfElements(#buffer)) THEN
|
|
|
|
|
#error := true;
|
|
|
|
|
#status := #ERR_WRONG_TYPE_ITEM;
|
|
|
|
|
#subFunctionStatus := #STATUS_NO_ERROR;
|
|
|
|
|
RETURN;
|
|
|
|
|
END_IF;
|
|
|
|
|
|
|
|
|
|
// check whether the initial value OF the ring #buffer
|
|
|
|
|
// matches the entry (tag #item). IF the data types DO NOT match,
|
|
|
|
|
// the program execution is terminated at this point
|
|
|
|
|
IF (TypeOf(#itemIn) <> TypeOf(#initialItem)) THEN
|
|
|
|
|
#error := true;
|
|
|
|
|
#status := #ERR_WRONG_TYPE_INITIAL_ITEM;
|
|
|
|
|
#subFunctionStatus := #STATUS_NO_ERROR;
|
|
|
|
|
RETURN;
|
|
|
|
|
END_IF;
|
|
|
|
|
|
|
|
|
|
// check whether the variable indices are within the ARRAY limits.
|
|
|
|
|
// IF they are NOT, the program execution is terminated at this point
|
|
|
|
|
IF (#statNextEmptyItemIndex >= #tempBufferSize) THEN
|
|
|
|
|
#error := true;
|
|
|
|
|
#status := #ERR_INDEX_IN_ARRAY_LIMITS_1;
|
|
|
|
|
#subFunctionStatus := #STATUS_NO_ERROR;
|
|
|
|
|
RETURN;
|
|
|
|
|
ELSIF (#statFirstItemIndex >= #tempBufferSize) THEN
|
|
|
|
|
#error := true;
|
|
|
|
|
#status := #ERR_INDEX_IN_ARRAY_LIMITS_2;
|
|
|
|
|
#subFunctionStatus := #STATUS_NO_ERROR;
|
|
|
|
|
RETURN;
|
|
|
|
|
END_IF;
|
|
|
|
|
|
|
|
|
|
// If resetBuffer is "TRUE", the buffer counters are reset
|
|
|
|
|
IF #reset THEN
|
|
|
|
|
#statFirstItemIndex := #BUFFER_INITIALIZED;
|
|
|
|
|
#statNextEmptyItemIndex := #EMPTY_INITIALIZED;
|
|
|
|
|
#statElementCount := #EMPTY_INITIALIZED;
|
|
|
|
|
#elementCount := INT_TO_USINT(#EMPTY_INITIALIZED);
|
|
|
|
|
#isEmpty := true;
|
|
|
|
|
RETURN;
|
|
|
|
|
END_IF;
|
|
|
|
|
|
|
|
|
|
// If clearBuffer has rising edge, the buffer is initialized by initial values
|
|
|
|
|
IF #tempEdges.clear THEN
|
|
|
|
|
FOR #tempCounter := #COUNTER_LOWER_LIMIT TO UDINT_TO_INT(#tempBufferSize - #BUFFER_SIZE_CORRECTION) DO
|
|
|
|
|
|
|
|
|
|
#tempInternalError := MOVE_BLK_VARIANT(SRC := #initialItem,
|
|
|
|
|
COUNT := #COUNT_ELEMENTS,
|
|
|
|
|
SRC_INDEX := #INDEX_BEGINNING,
|
|
|
|
|
DEST_INDEX := #tempCounter,
|
|
|
|
|
DEST => #buffer);
|
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
|
|
// checks whether a local error has occurred.
|
|
|
|
|
IF (#tempInternalError <> #NO_INTERNAL_ERROR) THEN
|
|
|
|
|
#error := true;
|
|
|
|
|
#status := #ERR_CLEAR_BUFFER;
|
|
|
|
|
#subFunctionStatus := INT_TO_WORD(#tempInternalError);
|
|
|
|
|
END_IF;
|
|
|
|
|
|
|
|
|
|
// reset counters
|
|
|
|
|
#statFirstItemIndex := #BUFFER_INITIALIZED;
|
|
|
|
|
#statNextEmptyItemIndex := #EMPTY_INITIALIZED;
|
|
|
|
|
#statElementCount := #EMPTY_INITIALIZED;
|
|
|
|
|
#elementCount := INT_TO_USINT(#EMPTY_INITIALIZED);
|
|
|
|
|
#isEmpty := true;
|
|
|
|
|
RETURN;
|
|
|
|
|
END_IF;
|
|
|
|
|
END_REGION
|
|
|
|
|
|
|
|
|
|
REGION FIFO algorithm
|
|
|
|
|
IF #tempEdges.dequeue THEN
|
|
|
|
|
REGION dequeue
|
|
|
|
|
// check whether the ring #buffer is empty
|
|
|
|
|
// IF this is the CASE, program execution is terminated at this point
|
|
|
|
|
IF (#statFirstItemIndex = #BUFFER_IS_EMPTY) THEN
|
|
|
|
|
#error := true;
|
|
|
|
|
#status := #ERR_BUFFER_EMPTY;
|
|
|
|
|
#subFunctionStatus := #STATUS_NO_ERROR;
|
|
|
|
|
RETURN;
|
|
|
|
|
END_IF;
|
|
|
|
|
|
|
|
|
|
// return the first entry of the ring buffer
|
|
|
|
|
#tempInternalError := MOVE_BLK_VARIANT(SRC := #buffer,
|
|
|
|
|
COUNT := #COUNT_ELEMENTS,
|
|
|
|
|
SRC_INDEX := #statFirstItemIndex,
|
|
|
|
|
DEST_INDEX := #INDEX_BEGINNING,
|
|
|
|
|
DEST => #itemOut);
|
|
|
|
|
|
|
|
|
|
// check whether a local error has occurred
|
|
|
|
|
IF (#tempInternalError <> #NO_INTERNAL_ERROR) THEN
|
|
|
|
|
#error := true;
|
|
|
|
|
#status := #ERR_RETURN_FIRST_ENTRY;
|
|
|
|
|
#subFunctionStatus := INT_TO_WORD(#tempInternalError);
|
|
|
|
|
RETURN;
|
|
|
|
|
END_IF;
|
|
|
|
|
|
|
|
|
|
// check whether the ring #buffer contains ARRAY elements
|
|
|
|
|
// IF it does, the first entry is passed further on and the index is incremented BY 1
|
|
|
|
|
#tempInternalError := MOVE_BLK_VARIANT(SRC := #initialItem,
|
|
|
|
|
COUNT := #COUNT_ELEMENTS,
|
|
|
|
|
SRC_INDEX := #INDEX_BEGINNING,
|
|
|
|
|
DEST_INDEX := #statFirstItemIndex,
|
|
|
|
|
DEST => #buffer);
|
|
|
|
|
|
|
|
|
|
// check whether a local error has occurred
|
|
|
|
|
IF (#tempInternalError <> #NO_INTERNAL_ERROR) THEN
|
|
|
|
|
#error := true;
|
|
|
|
|
#status := #ERR_REPLACE_ITEM_BY_INIT_VALUE;
|
|
|
|
|
#subFunctionStatus := INT_TO_WORD(#tempInternalError);
|
|
|
|
|
RETURN;
|
|
|
|
|
END_IF;
|
|
|
|
|
|
|
|
|
|
// calculate the new index of the first entry
|
|
|
|
|
#tempNewFirstItemIndex := #statFirstItemIndex + #INCREMENT;
|
|
|
|
|
#tempNewFirstItemIndex := #tempNewFirstItemIndex MOD UDINT_TO_INT(#tempBufferSize);
|
|
|
|
|
|
|
|
|
|
// check whether the ring buffer is empty
|
|
|
|
|
IF (#statNextEmptyItemIndex = #tempNewFirstItemIndex) THEN
|
|
|
|
|
// If the ring buffer is empty, the index is set to 0
|
|
|
|
|
#statFirstItemIndex := #BUFFER_INITIALIZED;
|
|
|
|
|
#statNextEmptyItemIndex := #EMPTY_INITIALIZED;
|
|
|
|
|
ELSE
|
|
|
|
|
// The index of the first entry is changed
|
|
|
|
|
#statFirstItemIndex := #tempNewFirstItemIndex;
|
|
|
|
|
END_IF;
|
|
|
|
|
|
|
|
|
|
// Evaluation of the number of elements in the stack
|
|
|
|
|
#statElementCount -= #INCREMENT;
|
|
|
|
|
|
|
|
|
|
#dequeueDone := TRUE; // !!!!!!!!!!!
|
|
|
|
|
#statEdgesMem.dequeue := FALSE;
|
|
|
|
|
|
|
|
|
|
END_REGION dequeue
|
|
|
|
|
|
|
|
|
|
ELSIF #tempEdges.enqueue THEN
|
|
|
|
|
REGION enqueue
|
|
|
|
|
// check whether the ring #buffer is full
|
|
|
|
|
// IF this is the CASE, program execution is terminated at this point
|
|
|
|
|
IF (#statNextEmptyItemIndex = #statFirstItemIndex) THEN
|
|
|
|
|
#error := true;
|
|
|
|
|
#status := #ERR_BUFFER_FULL;
|
|
|
|
|
#subFunctionStatus := #STATUS_NO_ERROR;
|
|
|
|
|
RETURN;
|
|
|
|
|
END_IF;
|
|
|
|
|
|
|
|
|
|
// write the entry to the ring buffer
|
|
|
|
|
#tempInternalError := MOVE_BLK_VARIANT(SRC := #itemIn,
|
|
|
|
|
COUNT := #COUNT_ELEMENTS,
|
|
|
|
|
SRC_INDEX := #INDEX_BEGINNING,
|
|
|
|
|
DEST_INDEX := #statNextEmptyItemIndex,
|
|
|
|
|
DEST => #buffer);
|
|
|
|
|
|
|
|
|
|
// check whether a local error has occurred
|
|
|
|
|
IF (#tempInternalError <> #NO_INTERNAL_ERROR) THEN
|
|
|
|
|
#error := true;
|
|
|
|
|
#status := #ERR_WRITE_ENTRY;
|
|
|
|
|
#subFunctionStatus := INT_TO_WORD(#tempInternalError);
|
|
|
|
|
RETURN;
|
|
|
|
|
END_IF;
|
|
|
|
|
|
|
|
|
|
// increment the index by 1 and calculates the new empty entry index
|
|
|
|
|
#tempNewNextEmptyItemIndex := (#statNextEmptyItemIndex + #INCREMENT) MOD UDINT_TO_INT(#tempBufferSize);
|
|
|
|
|
#statNextEmptyItemIndex := #tempNewNextEmptyItemIndex;
|
|
|
|
|
|
|
|
|
|
// check which index the "#firstItemIndex" tag has
|
|
|
|
|
// IF the number = -1, the ring buffer is initialized
|
|
|
|
|
// AND the entry is written TO the ring #buffer
|
|
|
|
|
// Therefore, "0" must be assigned TO the tag
|
|
|
|
|
IF (#statFirstItemIndex = #BUFFER_INITIALIZED) THEN
|
|
|
|
|
#statFirstItemIndex := #INDEX_BEGINNING;
|
|
|
|
|
END_IF;
|
|
|
|
|
|
|
|
|
|
// Evaluation of the number of elements in the stack
|
|
|
|
|
#statElementCount += #INCREMENT;
|
|
|
|
|
#enqueueDone := TRUE;
|
|
|
|
|
#statEdgesMem.enqueue := FALSE;
|
|
|
|
|
END_REGION enqueue
|
|
|
|
|
END_IF;
|
|
|
|
|
END_REGION
|
|
|
|
|
|
|
|
|
|
REGION Writing to outputs
|
|
|
|
|
#oldestElement := #statFirstItemIndex; // HINZUGEFÜGT!!!
|
|
|
|
|
#elementCount := DINT_TO_USINT(#statElementCount);
|
|
|
|
|
#isEmpty := #statElementCount <= #ZERO_ELEMENTS;
|
|
|
|
|
#isFull := #statElementCount >= #maxElementCount;
|
|
|
|
|
|
|
|
|
|
#error := false;
|
|
|
|
|
#status := #STATUS_NO_ERROR;
|
|
|
|
|
#subFunctionStatus := #STATUS_NO_ERROR;
|
|
|
|
|
// no error handling by ENO needed
|
|
|
|
|
ENO := TRUE;
|
|
|
|
|
END_REGION
|
|
|
|
|
END_FUNCTION_BLOCK
|
|
|
|
|
|