Client - Dynamic created DataSets (CreateDataSet, DeleteDataSet)

Dieses Beispiel zeigt die Verwendung der „CreateDataSetReq“- und „DeleteDataSet“-Methoden des Client-Funktionsbausteins.

Download TwinCAT XAE Project (*.zip): Sample17.zip

Das hier beschriebene Beispiel nutzt die Statemachine, welche in dem Kapitel „Allgemeine Client - Projektstruktur“ beschrieben ist. Die States: 0,1,11 und 100 sind identisch zu der dort beschriebenen Statemachine. Andere States wurden für das Beispiel modifiziert oder auch neue States hinzugefügt.

Allgemeine Information über die dynamischen DataSets

Die Instanzen der statischen, während der Laufzeit immer verfügbaren DataSets, werden in TwinCAT Telecontrol Configurator entweder vom Anwender konfiguriert oder aus einer ICD-Datei importiert. Die SPS-Projektgenerierung erstellt später den nötigen SPS-Code für die Instanziierung dieser DataSets. Dieser Code beinhaltet auch die Konfiguration der DataSet-Member und die Zuordnung des DataSets zu einem logischen Knoten im IEC 61850 Datenmodel. Die Konfiguration der statischen DataSets darf zur Laufzeit des SPS-Programms nicht verändert und die DataSets können auch nicht gelöscht werden.

Manchmal soll ein DataSet dynamisch erstellt und nur für eine kurze Zeit (z.B. solange die Kommunikationsverbindung steht) genutzt werden. In dieser Zeit ist es möglich, einige Messwerte mit Hilfe eines Reports zu überwachen. Wenn die Verbindung nicht mehr vorhanden ist soll dieser DataSet wieder aus dem Datenmodell entfernt/gelöscht werden.

Mit Hilfe der Client-Methoden: „CreateDataSetReq“ und „DeleteDataSetReq“ können DataSets dynamisch (zur Laufzeit) erstellt, konfiguriert und wieder gelöscht werden. Die dynamisch erstellten DataSets können entweder als „persistent“ oder „non-persistent“ DataSets konfiguriert werden. Die „non-persistent“ DataSets sind einer Client-Server-Verbindung fest zugeordnet und existieren nur maximal so lange, bis die Verbindung unterbrochen wurde. Die „non-persistent“ DataSets einer Client-Server-Verbindung sind für eine andere Client-Server-Verbindungen nicht sichtbar. D.h. ein Client kann die „non-persistent“ DataSets eines anderen Clients nicht sehen und auch nicht löschen. Ein „non-persistent“ DataSet kann nur von dem Client gelöscht werden, der ihn auch erstellt hat oder wird automatisch gelöscht, wenn die Verbindung dieses Clients unterbrochen wurde.

Die „persistent“ DataSets dagegen sind für alle Clients sichtbar und können auch zum späteren Zeitpunkt von einem anderen Client gelöscht werden. Allerdings ist davon abzuraten da der Ersteller-Client es vielleicht nicht mitbekommt und möglicherweise versucht, auf diesen DataSet weiterhin zuzugreifen. Die „persistent“ DataSets werden beim Verbindungsabbruch nicht automatisch gelöscht und verbleiben so im Datenmodell, bis sie explizit gelöscht werden.

Ein dynamisch erstelltes „persistent“ oder „non-persistent“ DataSet, dass z. B. von einem Report-Kontrollblock verwendet wird kann nicht gelöscht werden. D.h. solange der Kontrollblock Attribut: „DatSet“ diesen DataSet referenziert kann dieser DataSet nicht gelöscht werden. Wenn Sie einen solchen DataSet löschen wollen, dann muss das Attribut „DatSet“ einen anderen DataSet referenzieren oder die „DatSet“ Referenz muss gelöscht werden (ein Leerstring löscht z.B. die „DatSet“ Referenz).

Bei einem Client-Projekt und nach einem TwinCAT-Neustart oder einem Reset der TwinCAT-SPS werden alle „persistent“ und „non-persistent“ DataSets auf der Clientseite automatisch gelöscht. Auf der Serverseite verbleiben aber möglicherweise die „persistent“ DataSets erhalten da sie nicht explizit gelöscht werden konnten.

Die statischen DataSets sind im Grunde auch „persistent“ DataSets mit dem Unterschied zu den dynamisch erzeugten DataSets, dass sie nicht gelöscht werden können.

Für jeden DataSet, den Sie zum späteren Zeitpunkt (zur Laufzeit) dynamisch erstellen wollen, benötigen Sie eine Instanz des Funktionsbausteins: „FB_AcsiCommonDataSetClass“. Diese Instanzen werden während der SPS-Programmierung manuell dem SPS-Projekt bereits vorher hinzugefügt. Sie sind aber noch nicht mit dem Client-Datenmodel verknüpft. Die SPS-Applikation kann dann später zur Laufzeit diese Instanzen zur Erstellung der dynamischen DataSets auf der Serverseite verwenden. Erst dann werden diese Instanzen auch mit dem Datenmodel auf der Clientseite verknüpft. Die DataSet-Member können ebenfalls bereits im Voraus vorkonfiguriert werden. Die Methode „CreateDataSetReq“ benötigt als ersten Parameter: „ipDataSet“ einen Schnittstellenzeiger auf ein solches, vorkonfiguriertes DataSet Objekt. Der zweite Parameter: „ipLogicalNode“ bestimmt, ob ein „persistent“ oder „non-persistent“ DataSet erstellt werden soll. Nur die „persistent“ DataSets werden mit einem logischen Knoten verknüpft. In diesem Fall muss dieser Parameter gültig sein. Bei einem „non-persistent“ DataSet ist dieser Parameter Null. Beim Erfolg wird auf der Serverseite ein dynamisches DataSet erstellt und die vorkonfigurierte DataSet-Instanz mit dem Datenmodel auf der Clientseite verknüpft. Die Methode „DeleteDataSetReq“ benötigt als ersten Parameter: „ipDataSet“ einen Schnittstellenzeiger auf ein DataSet Objekt (welches bereits vorher dem Datenmodell hinzugefügt wurde). Beim Erfolg wird dann das DataSet auf der Serverseite aus dem Datenmodell gelöscht und auf der Clientseite die Verknüpfung des DataSets mit dem Datenmodell ebenfalls gelöscht.

Beispielprojekt

In dem zip-Archiv befindet sich eine ICD-Konfigurationsdatei. Diese Datei kann verwendet werden, um z.B. einen Server mit Hilfe einer Drittherstellersoftware zu simulieren oder mit TwinCAT Telecontrol Configurator ein neues oder modifiziertes TwinCAT Projekt zu erzeugen.

Im Funktionsbaustein FB_IEDClient und State 10 sind mehrere IF-Anweisungen aufgeführt, welche Befehle (Methodenaufrufe) des Client-Bausteins aktivieren. Jeder Befehl in der IF-Anweisung wird durch eine steigende Flanke an einer der booleschen Variablen aktiviert. Die booleschen Variablen sind im Deklarationsteil des Funktionsbausteins FB_IEDClient definiert. Zu Testzwecken kann der Benutzer in der Online-Ansicht die Werte der booleschen Variablen auf „TRUE“ setzen und die Befehlsabarbeitung auf diese Weise aktivieren. Danach wird zum State 11 gewechselt, wo in weiteren SPS-Zyklen die Methode „ipResult.Execute()“ so lange aufgerufen wird, bis die Befehlsabarbeitung abgeschlossen wurde. Dies ist dann der Fall, wenn „ipResult.IsBusy() FALSE zurück liefert.

Nach der erfolgreichen Abarbeitung eines Befehls wird die Statemachine in den State 0 versetzt. Falls mehrere der booleschen Variablen auf „TRUE“ gesetzt sind, dann wird die oberste IF-Anweisung mit dem jeweiligen Befehl zuerst abgearbeitet. In der folgenden Tabelle sind einige der booleschen Variablen aufgelistet. Zudem sind die Methodennamen und eine Beschreibung der Funktionalität enthalten.

Das Beispiel verwendet zwei vorkonfigurierte Instanzen des „FB_AcsiCommonDataSetClass“-Funktionsbausteins. Die Instanz: „fbNonPersistent“ um einen „non-persistent“ und die Instanz: „fbPersistent“ um einen „persistent“ DataSet zu erzeugen. Die Namen der DataSets wurden bereits im Deklarationsteil mit Hilfe der Eigenschaft „sObjectName“ auf „NonPersistentDataSet“ und „PersistentDataSet“ vorkonfiguriert.


fbNonPersistent: FB_AcsiCommonDataSetClass:=(sObjectName:='NonPersistentDataSet');
fbPersistent: FB_AcsiCommonDataSetClass:=(sObjectName:='PersistentDataSet');

In der IF-Anweisung, kurz vor der Aktivierung der „CreateDataSetReq“-Methode und wenn bereits noch nicht geschehen, werden die DataSet-Member den DataSets hinzugefügt. Dies kann aber auch in eine separate Routine ausgelagert werden die z.B. einmalig beim Programmstart aufgerufen wird.


ELSIF bCreateDataSet_NonPersistent THEN
    bCreateDataSet_NonPersistent:= FALSE;
    IF fbNonPersistent.nMembers = 0 THEN
        bSuccess:= fbNonPersistent.AddMember(ipData:=fbIED.IEDLD1.XCBR1.Pos.stVal, eFc:=E_AcsiFc.ST_);
        bSuccess:= fbNonPersistent.AddMember(ipData:=fbIED.IEDLD1.LLN0.Mod_.stVal, eFc:=E_AcsiFc.ST_);
    END_IF
    bSuccess:= fbConnection.CreateDataSetReq(ipDataSet:=fbNonPersistent, ipLogicalNode:=0, hUser:=0, ipSink:=0, nInvokeID=>nInvokeID, ipResult=>ipResult);
    state:= SEL(bSuccess, 100, 11);
ELSIF bCreateDataSet_Persistent THEN
    bCreateDataSet_Persistent:= FALSE;
    IF fbPersistent.nMembers = 0 THEN
        bSuccess:= fbPersistent.AddMember(ipData:=fbIED.IEDLD1.MMXU1.TotW.mag.f, eFc:=E_AcsiFc.MX);
        bSuccess:= fbPersistent.AddMember(ipData:=fbIED.IEDLD1.LLN0.Beh.stVal, eFc:=E_AcsiFc.ST_);
    END_IF
    bSuccess:= fbConnection.CreateDataSetReq(ipDataSet:=fbPersistent, ipLogicalNode:=fbIED.IEDLD1.LLN0, hUser:=0, ipSink:=0, nInvokeID=>nInvokeID, ipResult=>ipResult);
    state:= SEL(bSuccess, 100, 11);

Variablenname

Methodenname

Beschreibung

bCreateDataSet_NonPersistent

CreateDataSetReq

Eine steigende Flanke an dieser Variablen aktiviert den Befehl zur Erstellung eines dynamischen „non-persistent“ DataSets mit dem Namen: „NonPersistentDataSet“ (Objektreferenz: '@NonPersistent').

bCreateDataSet_Persistent

CreateDataSetReq

Eine steigende Flanke an dieser Variablen aktiviert den Befehl zur Erstellung eines dynamischen „persistent“ DataSets mit dem Namen: „PersistentDataSet“ (Objektreferenz: 'IEDLD1/LLN0.PersistentDataSet'). Beim Erfolg wird der neue DataSet mit dem logischen Knoten „LLN0“ verknüpft.

bDeleteDataSet_NonPersistent

DeleteDataSetReq

Eine steigende Flanke an dieser Variablen aktiviert den Befehl zum Löschen eines dynamischen „non-persistent“ DataSets mit dem Namen: „NonPersistentDataSet“.

bDeleteDataSet_Persistent

DeleteDataSetReq

Eine steigende Flanke an dieser Variablen aktiviert den Befehl zum Löschen eines dynamischen „persistent“ DataSets mit dem Namen: „PersistentDataSet“.

bEnable_urcb101_NonPersistent

urcb101.Client.EnableReq

Eine steigende Flanke an dieser Variablen aktiviert die Berichtssteuerblockinstanz für ungepufferte Reports: „urcb101“. Die Reports sollen die DataSet-Member des zuvor dynamisch erstellten „non-persistent“ DataSets:„fbNonPersistent“ übertragen. Intern wird vorher noch das Attribut: „DatSet“ des Berichtssteuerblocks entsprechend gesetzt (der String referenziert den dynamisch erstellten DataSet).

bEnable_urcb101_Persistent

urcb101.Client.EnableReq

Eine steigende Flanke an dieser Variablen aktiviert die Berichtssteuerblockinstanz für ungepufferte Reports „urcb101“. Die Reports sollen die DataSet-Member des zuvor dynamisch erstellten „persistent“ DataSets:„fbPersistent“ übertragen. Intern wird vorher noch das Attribut: „DatSet“ des Berichtssteuerblocks entsprechend gesetzt (der String referenziert den dynamisch erstellten DataSet).

bEnable_urcb101_DS1

urcb101.Client.EnableReq

Eine steigende Flanke an dieser Variablen aktiviert die Berichtssteuerblockinstanz für ungepufferte Reports „urcb101“. Die Reports sollen die DataSet-Member des statischen DataSets: „DS1“ übertragen. Intern wird vorher noch das Attribut: „DatSet“ des Berichtssteuerblocks entsprechend gesetzt (der String referenziert den statischen DataSet).

bDisable_urcb101

urcb101.Client.DisableReq

Eine steigende Flanke an dieser Variablen deaktiviert die Berichtssteuerblockinstanz für ungepufferte Reports „urcb101“. Die Übertragung der Reports wird daraufhin gestoppt.

bSetDataValues_urcb101_DatSet

SetDataValuesReq

Solange „DatSet“ einen dynamisch erstellten DataSet referenziert, kann dieser DataSet nicht wieder gelöscht werden. Um einen dynamisch erstellten DataSet löschen zu können darf er von keinem Kontrollblock verwendet werden und auch von dem „DatSet“ nicht referenziert werden. Eine steigende Flanke an dieser Variablen beschreibt den Attributwert: „IEDLD1/LLN0.RP.urcb101.DatSet“ mit einem Leerstring.

bGetDataSetDirectory_NonPersistent

GetDataSetDirectoryReq

Eine steigende Flanke an dieser Variablen aktiviert den Befehl zum Lesen der DataSet-Member Konfiguration des zuvor dynamisch erstellten „non-persistent“ DataSets: „fbNonPersistent“. Die DataSet-Member werden dabei enumeriert.

bGetDataSetDirectory_Persistent

GetDataSetDirectoryReq

Eine steigende Flanke an dieser Variablen aktiviert den Befehl zum Lesen der DataSet-Member Konfiguration des zuvor dynamisch erstellten „persistent“ DataSets: „fbPersistent“. Die DataSet-Member werden dabei enumeriert.

bGetDataSetDirectory_DS1

GetDataSetDirectoryReq

Eine steigende Flanke an dieser Variablen aktiviert den Befehl zum Lesen der DataSet-Member Konfiguration des statischen DataSets: „DS1“. Die DataSet-Member werden dabei enumeriert.

Kleiner Test

Nach dem Programstart, wenn die Verbindung zum Server steht, schreiben sie zuerst den Wert TRUE in die boolesche Variable: „bCreateDataSet_NonPersistent“. Beim Erfolg wird ein neues dynamisches „non-persistent“ DataSet erstellt. Dieser DataSet kann dann von der Berichtssteuerblockinstanz für ungepufferte Reports verwendet werden. Wenn sie den Wert TRUE in die Variable „bEnable_urcb101_NonPersistent“ schreiben dann aktivieren Sie das Versenden der Reports mit den „non-persistent“ DataSet-Member Daten. Stoppen sie das Versenden der Reports, indem Sie den Wert TRUE in die Variable: „bDisable_urcb101“ schreiben. Der dynamische „non-persistent“ DataSet wird aber immer noch von dem Attribut: „DatSet“ der Berichtssteuerblockinstanz „urcb101“ verwendet und lässt sich noch nicht löschen. Schreiben Sie den Wert TRUE in die boolesche Variable „bSetDataValues_urcb101_DatSet“. Jetzt kann der dynamische „non-persistent“ DataSet gelöscht werden. Setzen sie dafür den Wert TRUE in die Variable: „bDeleteDataSet_NonPersistent“.