Client - Read/Write DataSet Values (GetDataSetValues, SetDataSetValues)

This sample shows the use of the "GetDataSetValuesReq" and "SetDataSetValuesReq" methods of the client function block.

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

The example described here uses the state machine that is described in the "General Client project structure" chapter. The States 0, 1, 11 and 100 are identical to the state machine described there. Other states were modified for the example or new states were also added.

General information about IEC 61850 DataSets

A DataSet is a list of data attributes or data that can be transmitted together (usually in a report or GOOSE message). The individual list entries of a DataSet are called DataSet members. The DataSet members are configured in the TwinCAT Telecontrol Configurator. The PLC code of the DataSets and DataSet members is automatically generated by the configurator during TwinCAT project generation. With a DataSet several data or data attributes can be read or written at the same time. The client method "GetDataSetValuesReq" can read all DataSet members defined in the DataSet together (the values are transferred from the server to the client). The client method "SetDataSetValuesReq" can be used to write to all DataSet members defined in the DataSet (the values are transferred from the client to the server).

Preferably the DataSets are found in the IEC 61850 data model below the logical node LLN0. However, a DataSet can theoretically be assigned to (linked to) any other logical node.

The following figure shows the DataSet function blocks created during project generation in the TwinCAT project tree:

Client - Read/Write DataSet Values (GetDataSetValues, SetDataSetValues) 1:

The DataSet function blocks shown belong to LLN0 and for this reason they are also instantiated in the declaration part of LLN0. The instances of the DataSets: "DS1" to "DS8" and the link to the logical node were also generated automatically.

Client - Read/Write DataSet Values (GetDataSetValues, SetDataSetValues) 2:

The PLC code for the configuration of the DataSet members is also automatically generated like the DataSets themselves. This code is located in the OnInit method of the respective DataSet function block (see figure below).

Client - Read/Write DataSet Values (GetDataSetValues, SetDataSetValues) 3:

Static DataSets vs. dynamic DataSets

The TwinCAT project generation creates static, persistent DataSets. I.e. these DataSets are always available in the data model and cannot and should not be deleted. However, there are also dynamic DataSets that can be created during communication. The dynamically created DataSets can be deleted again. They are deleted either automatically, when the connection is terminated (dynamically created non-persistent data-sets) or at a later time, also by another client (dynamically created persistent data-sets).

Sample project

In the zip archive there is an ICD configuration file. This file can be used, for example, to simulate a server using third-party software or to create a new or modified TwinCAT project with TwinCAT Telecontrol Configurator.

If you plan to use a DataSet to write multiple data or data attributes at the same time, then you still need to consider the following: all configured DataSet members must also allow write access, otherwise the write access will fail. This depends mainly on the functional group (FC) of the DataSet member. In this sample, for the purpose of demonstrating write access, the DataSet "DS8" has been configured so that all DataSet members can be written to (functional group: "DC"). In our client sample project, of course, write access to all DataSet members must be possible on the server side.

Several Boolean variables are defined in the FB_IEDClient function block. A rising edge at one of these variables enables the method: "GetDataSetValuesReq" or "SetDataSetValuesReq" with the respective DataSet as input parameter. As an example: a rising edge at the variable "bGetDataSetValues_LLN0_DS1" enables the command for reading the DataSet: "DS1" and a rising edge at "bSetDataSetValues_LLN0_DS8" enables the command for writing the DataSet: "DS8".


bGetDataSetValues_LLN0_DS1 : BOOL := TRUE;
bGetDataSetValues_LLN0_DS2 : BOOL := TRUE;
bGetDataSetValues_LLN0_DS3 : BOOL := TRUE;
bGetDataSetValues_LLN0_DS4 : BOOL := TRUE;
bGetDataSetValues_LLN0_DS5 : BOOL := TRUE;
bGetDataSetValues_LLN0_DS6 : BOOL := TRUE;
bGetDataSetValues_LLN0_DS7 : BOOL := TRUE;
bGetDataSetValues_LLN0_DS8 : BOOL := TRUE;
bSetDataSetValues_LLN0_DS8 : BOOL := TRUE;

The following is an excerpt from the sample code for reading the DataSet: "DS8". First, the method call "GetDataSetValuesReq" enables the transfer of data from the server to the client. After that, in further PLC cycles the method "ipResult.Execute()" must be called until the transfer is completed. "ipResult.IsBusy()" returns FALSE in this case. The received data values or attribute values of the DataSet members are automatically copied (mapped) to the client data model upon success.


ELSIF bGetDataSetValues_LLN0_DS8 THEN
    bGetDataSetValues_LLN0_DS8:= FALSE;
    bSuccess:= fbConnection.GetDataSetValuesReq(ipDataSet:=fbIED.IEDLD1.LLN0.DS8, hUser:=0, ipSink:=0, nInvokeID=>nInvokeID, ipResult=>ipResult);
    state:= SEL(bSuccess, 100, 11);

In the sample code for writing the DataSet: "DS8", the data to be written to the DataSet: "DS8" is modified each time for demonstration purposes. First, new data values or attribute values are assigned to DataSet members in the client data model. After that the method call "SetDataSetValuesReq" activates the transfer of the data to the server. In further PLC cycles, the method "ipResult.Execute()" must be called analogously as already described above until the transfer has been completed. The new data values or attribute values are copied (mapped) into the server data model on the server side.


ELSIF bSetDataSetValues_LLN0_DS8 THEN
    bSetDataSetValues_LLN0_DS8:= FALSE;
    (* As example we modify some description data values *)
    sConfigRev:= TO_STRING(nRev:=nRev+1);
    sHwRev:= TO_STRING(TO_REAL(nRev));
    sSwRev:= TO_STRING(TO_REAL(nRev));

    fbIED.IEDLD1.LPHD1.PhyNam.Vendor.sValue:= sVendor;
    fbIED.IEDLD1.LPHD1.PhyNam.hwRev.sValue:= sHwRev;
    fbIED.IEDLD1.LPHD1.PhyNam.swRev.sValue:= sSwRev;
    fbIED.IEDLD1.LPHD1.PhyNam.serNum.sValue:= sSerNum;
    fbIED.IEDLD1.LPHD1.PhyNam.model.sValue:= sModel;
    fbIED.IEDLD1.LPHD1.PhyNam.location.sValue:= sLocation;

    fbIED.IEDLD1.LLN0.NamPlt.vendor.sValue:= sVendor;
    fbIED.IEDLD1.LLN0.NamPlt.swRev.sValue:= sSwRev;
    fbIED.IEDLD1.LLN0.NamPlt.d.sValue:= 'LLN0 demo node';
    fbIED.IEDLD1.LLN0.NamPlt.configRev.sValue:= sConfigRev;

    fbIED.IEDLD1.MMXU1.NamPlt.vendor.sValue:= sVendor;
    fbIED.IEDLD1.MMXU1.NamPlt.swRev.sValue:= sSwRev;
    fbIED.IEDLD1.MMXU1.NamPlt.d.sValue:= 'MMXU1 demo node';
    fbIED.IEDLD1.MMXU1.NamPlt.configRev.sValue:= sConfigRev;

    fbIED.IEDLD1.XCBR1.NamPlt.vendor.sValue:= sVendor;
    fbIED.IEDLD1.XCBR1.NamPlt.swRev.sValue:= sSwRev;
    fbIED.IEDLD1.XCBR1.NamPlt.d.sValue:= 'XCBR1 demo node';
    fbIED.IEDLD1.XCBR1.NamPlt.configRev.sValue:= sConfigRev;

    fbIED.IEDLD1.CSWI1.NamPlt.vendor.sValue:= sVendor;
    fbIED.IEDLD1.CSWI1.NamPlt.swRev.sValue:= sSwRev;
    fbIED.IEDLD1.CSWI1.NamPlt.d.sValue:= 'CSWI1 demo node';
    fbIED.IEDLD1.CSWI1.NamPlt.configRev.sValue:= sConfigRev;

    fbIED.IEDLD1.LEDGGIO1.NamPlt.vendor.sValue:= sVendor;
    fbIED.IEDLD1.LEDGGIO1.NamPlt.swRev.sValue:= sSwRev;
    fbIED.IEDLD1.LEDGGIO1.NamPlt.d.sValue:= 'LEDGGIO1 demo node';

    fbIED.IEDLD1.LEDGGIO2.NamPlt.vendor.sValue:= sVendor;
    fbIED.IEDLD1.LEDGGIO2.NamPlt.swRev.sValue:= sSwRev;
    fbIED.IEDLD1.LEDGGIO2.NamPlt.d.sValue:= 'LEDGGIO2 demo node';

    fbIED.IEDLD1.LEDGGIO3.NamPlt.vendor.sValue:= sVendor;
    fbIED.IEDLD1.LEDGGIO3.NamPlt.swRev.sValue:= sSwRev;
    fbIED.IEDLD1.LEDGGIO3.NamPlt.d.sValue:= 'LEDGGIO3 demo node';

    fbIED.IEDLD1.LEDGGIO4.NamPlt.vendor.sValue:= sVendor;
    fbIED.IEDLD1.LEDGGIO4.NamPlt.swRev.sValue:= sSwRev;
    fbIED.IEDLD1.LEDGGIO4.NamPlt.d.sValue:= 'LEDGGIO4 demo node';

    fbIED.IEDLD1.LEDGGIO5.NamPlt.vendor.sValue:= sVendor;
    fbIED.IEDLD1.LEDGGIO5.NamPlt.swRev.sValue:= sSwRev;
    fbIED.IEDLD1.LEDGGIO5.NamPlt.d.sValue:= 'LEDGGIO5 demo node';

    fbIED.IEDLD1.LEDGGIO6.NamPlt.vendor.sValue:= sVendor;
    fbIED.IEDLD1.LEDGGIO6.NamPlt.swRev.sValue:= sSwRev;
    fbIED.IEDLD1.LEDGGIO6.NamPlt.d.sValue:= 'LEDGGIO6 demo node';

    fbIED.IEDLD1.LEDGGIO7.NamPlt.vendor.sValue:= sVendor;
    fbIED.IEDLD1.LEDGGIO7.NamPlt.swRev.sValue:= sSwRev;
    fbIED.IEDLD1.LEDGGIO7.NamPlt.d.sValue:= 'LEDGGIO7 demo node';

    fbIED.IEDLD1.LEDGGIO8.NamPlt.vendor.sValue:= sVendor;
    fbIED.IEDLD1.LEDGGIO8.NamPlt.swRev.sValue:= sSwRev;
    fbIED.IEDLD1.LEDGGIO8.NamPlt.d.sValue:= 'LEDGGIO8 demo node';

    fbIED.IEDLD1.ATCC1.NamPlt.vendor.sValue:= sVendor;
    fbIED.IEDLD1.ATCC1.NamPlt.swRev.sValue:= sSwRev;
    fbIED.IEDLD1.ATCC1.NamPlt.d.sValue:= 'ATCC1 demo node';
    fbIED.IEDLD1.ATCC1.NamPlt.configRev.sValue:= sConfigRev;

    bSuccess:= fbConnection.SetDataSetValuesReq(ipDataSet:=fbIED.IEDLD1.LLN0.DS8, hUser:=0, ipSink:=0, nInvokeID=>nInvokeID, ipResult=>ipResult);
    state:= SEL(bSuccess, 100, 11);

CASE state OF

    11:
        IF ipResult <> 0 THEN
            ipResult.Execute();
            IF NOT (bBusy:=ipResult.IsBusy()) THEN
                state:= SEL(ipResult.IsCompleted(), 100(* failed or aborted *), 0(* succeeded *));
            END_IF
        END_IF

END_CASE