IEC 61850 client tutorial

The IEC 61850 client API contains functions to support model discovery, reading and writing data attributes, data set handling, configuration and reception of reports, file services and control operations. This client API is designed to be as close as possible to the IEC 61850 ACSI (abstract communication service interface) as defined in IEC 61850-7-2. But be aware that there are some points where there are some deviations from the ACSI due to practical reasons.

Create a connection to a server

Before you can connect to a server you have to create an IedConnection object. A connection will be established with the IedConnection_connect method. The first argument is the newly created IedConnection instance. The second argument provides a pointer to a variable where the client stack can store error informations. This is also the case with most other client API functions (IedConnection_…) where errors can occur. The third argument is a string containing the IP address or hostname of the server to connect. The last argument provides the TCP port of the server. The default TCP port of MMS is 102. So you should always select this port.

Practical examples on how to use the IEC 61850 client API can be found in the examples folder in the libiec61850 source distributions. These examples start with “iec61850_client”.

IedClientError error;

IedConnection con = IedConnection_create();

IedConnection_connect(con, &error, "192.168.1.2", 102);

if (error == IED_ERROR_OK) {
  // do some work

  IedConnection_close(con);
}

IedConnection_destroy(con);
...

The code snippet above will connect to a server with IP address 192.168.1.2 listening on port 102 (the default MMS port). If you finished your task you have to call IedConnection_close to properly close the connection to the server. After you closed the connection you should also call IedConnection_destroy to release all resources allocated by the client stack.

Control connection parameters

The IEC 61850/MMS protocol is a complex protocol consisting of a lot of OSI protocol layers. Most of them have their own parameters. Fortunately in most cases the default values of these parameters are sufficient to connect to a device. Some devices though have problems with default parameters and require a special treatment.

The IsoConnectionParameters object, that is associated with a MmsConnection can be used to set the lower layer parameters (below the MMS layer). It can also be used to set authentication values (e.g. a password) if the server requires authentication.

For more details on how to change these parameters please have a look at the examples and the API reference documentation.

Data model discovery

IEC 61850 provides a wide range of functions to discover the data model present at the server. These functions are especially interesting if you want to write a generic client. If you know the data model of the device you want to communicate to you don’t need these functions.

To request the logical device list from the server you can call the IedConnection_getLogicalDeviceList method.

LinkedList deviceList = IedConnection_getLogicalDeviceList(con, &error);

The resulting linked list contains the names of all logical devices of the server as a list of C strings.

The directory of a logical device can be retrieved by calling IedConnection_getLogicalDeviceDirectory with the name of the logical device as a parameter.

The following example iterates the list of logical devices and requests the logical node list for each logical device:

LinkedList device = LinkedList_getNext(deviceList);

while (device != NULL) {
    printf("LD: %s\n", (char*) device->data);

    LinkedList logicalNodes = IedConnection_getLogicalDeviceDirectory(con, &error,
        (char*) device->data);

    device = LinkedList_getNext(device);
}

Reading and writing data objects

You can read or write simple or complex data attributes/objects with the IedConnection_readObject and IedConnection_writeObject funtions. Before you can use these functions you have to establish a connection to a server as explained above. The parameter lists of both functions are similar. The first argument is the connection object of an established connection. The second argument is a pointer to an IedClientError variable. The third argument is the object reference of the data attribute/object you want to access. The fourth argument is the Functional Constraint (e.g. MX).

Note: You cannot access whole IEC 61850 data objects with these functions. For example a call to IedConnection_readObject will result in a single MMS read command. This is restricted to functional constraint data. So in order to read all values of an IEC 61850 data object you have to use multiple readObject calls for each functional constraint the data object has elements of. This seems as a restriction at the first but turns out to be very useful. E.g. you can read all measurement or status values (functional constraints MX or ST) of an IEC 61850 data object without reading configuration values or control variables (functional constraints CF or CO).

IedClientError error;

...

/* read an analog measurement value from server */
MmsValue* value = IedConnection_readObject(con, &error, 
     "simpleIOGenericIO/GGIO1.AnIn1.mag.f", MX);

if (value != NULL) {
    float fval = MmsValue_toFloat(value);
    printf("read float value: %f\n", fval);
    MmsValue_delete(value);
}

/* write a variable to the server */
value = MmsValue_newVisibleString("libiec61850.com");

IedConnection_writeObject(con, &error, 
   "simpleIOGenericIO/GGIO1.NamPlt.vendor", DC, value);

if (error != IED_ERROR_OK)
    printf("failed to write simpleIOGenericIO/GGIO1.NamPlt.vendor!\n");

The IedConnection_readObject and IedConnection_writeObject functions use instances of MmsValue as results or parameters. The benefit of these functions is that they are very flexible and can also be used to access complex (structured) data. Also the type of the result has not to be known in advance when using the readObject function. One other consequence is that for the read function the API user always have to free (by using MmsValue_delete) the data after processing. Also by using the writeObject functions you have to deal with MmsValue and its special setter functions. To avoid this the client API also contains some convenience functions that allow read and write with native data types as parameters. These functions are restricted to access simple (basic) data attributes. Also the type of the result has to be known in the read case.

An example for these functions is the IedConnection_readFloatValue function:

float magF = IedConnection_readFloatValue(con, &error, 
   "simpleIOGenericIO/GGIO1.AnIn1.mag.f", MX);

Handling data sets

Data sets are groups of data attributes (DA) or functional constraint data objects (FCDO). They are used to simplify access to functional related groups of variables. E.g. if you want to read the most important status values of a server you don’t have to ask the server for each individual variable. Instead you define a data set (or most probably use a predefined one) that contains all the required data and request them with a single read with the data set reference as an argument. Data sets are also intended to be used in relation with reports, GOOSE messages and logs (time series of data).

So far the IEC 61850 client API supports the following data set related services:

  • read data set values
  • define a new data set
  • delete an existing data set
  • read the directory (list of variables) of the data set

To represent a data set client side the library uses objects of type ClientDataSet. ClientDataSet can be considered as a container to store the values of a data set and consists of these functions:

void
ClientDataSet_destroy(ClientDataSet self);

MmsValue*
ClientDataSet_getValues(ClientDataSet self);

char*
ClientDataSet_getReference(ClientDataSet self);

int
ClientDataSet_getDataSetSize(ClientDataSet self);

The actual values of the data set are stored as MmsValue instance of type MMS_ARRAY. There is an array element for each member of the data set.

To access the data set related services these functions have to be used:

ClientDataSet
IedConnection_readDataSetValues(IedConnection self, IedClientError* error,
		char* dataSetReference, ClientDataSet dataSet);

void
IedConnection_createDataSet(IedConnection self, IedClientError* error,
		char* dataSetReference, LinkedList /* char* */ dataSetElements);

void
IedConnection_deleteDataSet(IedConnection self, IedClientError* error,
		char* dataSetReference);

LinkedList /* <char*> */
IedConnection_getDataSetDirectory(IedConnection self, IedClientError* error,
		char* dataSetReference, bool* isDeletable);

The IedConnection_readDataSetValues creates a new instance of ClientDataSet if the last parameter (dataSet) is NULL. A call to this function triggers a request to the server. If you call the function multiple times you can provide the formerly received ClientDataSet instance as dataSet parameter. In this way you can reuse the container.

This example shows how to read the values of a data set:

ClientDataSet dataSet = IedConnection_readDataSetValues(con, &error, 
    "simpleIOGenericIO/LLN0.Events", NULL);

if (error == IED_ERROR_OK) {
   printf("Read data set %s\n", ClientDataSet_getReference(dataSet));

   IedConnection_readDataSetValues(con, &error, "simpleIOGenericIO/LLN0.Events", dataSet);
}

To create a new data set you have to build a list containing the object references to the functional constraint data that should become the data set members. Please note that the FC has to be present in squared brackets as shown below:

LinkedList dataSetItems = LinkedList_create();

LinkedList_add(dataSetItems, "simpleIOGenericIO/GGIO1.SPCSO1.stVal[ST]");
LinkedList_add(dataSetItems, "simpleIOGenericIO/GGIO1.SPCSO1.t[ST]");
LinkedList_add(dataSetItems, "simpleIOGenericIO/GGIO1.SPCSO2.stVal[ST]");
LinkedList_add(dataSetItems, "simpleIOGenericIO/GGIO1.SPCSO2.t[ST]");

IedConnection_createDataSet(con, &error, "simpleIOGenericIO/LLN0.newDataSet", dataSetItems);

This example will create a new data set with the name simpleIOGenericIO/LLN0.newDataSet containing four different elements.

Receiving reports

Reports are used for event based message transmission. If you need to be updated with the states of certain variables reporting provides the means without forcing you to periodically send read requests to the server. This preserves network bandwidth especially in cases where values only change sporadically.

Reports are defined for data sets. A server typically contains preconfigured Report Control Blocks(RCB). A client has to reserve, configure and activate such a RCB prior to receiving report messages from the server.

To handle reports client side these data types are involved:

  • ClientReportControlBlock – is the data container to hold the RCB values client side
  • ClientReport – represents a received report
  • ClientDataSet – container for the data values of a received report
  • ReportCallbackFunction – callback function when a report is received
  • ReasonForInclusion – enumeration to indicate the reason for the inclusion of a data set member into the report

To get started with reports you need to configure and enable a RCB at the server. You can start by reading the values of the RCB with the IedConnection_getRCBValues function:

getRCBValues

You have to specify the RCB by a special reference as the third argument of the function. Please not the “RP” inserted between the LN name and the RCB name. This has to be used for unbuffered reports. If you want to enable a buffered report you have to use “BR” instead. The function reads all values of the RCB from the server and creates a new instance of ClientReportControlBlock. If you want to use an existing instance of ClientReportControlBlock you can specify the instance as the last argument of the function.

If you want to write to the RCB you can also create a new instance with the ClientReportControlBlock_create function. Set the values with the setter functions and use the IedConnection_setRCBValues function to write the changed or new values to the server:

setRCBValues

Please note that in contrast to the IedConnection_getRCBValues function that always reads all RCB values the setRCBValues only write the requested values. These values need to be specified by using the fourth argument of the function.

Prepare the client to receive reports:

In order to receive reports and access the report data you have to provide a callback function to the client API. A very simple callback function and the other required preparation steps can look like this:

static void
reportHandler (void* parameter, ClientReport report)
{
	printf("report received\n");
}

ClientDataSet dataSet = IedConnection_readDataSetValues(con, 
     &error, dataSetReference, NULL);

IedConnection_installReportHandler(con, "simpleIOGenericIO/LLN0.RP.EventsRCB", 
     reportHandler, NULL, dataSet);

First it is required to get a ClientDataSet instance that can be used by the report receiver part of the client stack to store the report data. The second step is to connect the report callback function and the data set representation to the RCB. This is done by calling the IedConnection_installReportHandler

Then reporting can be enabled by using the IedConnection_setRCBValues function:

ClientReportControlBlock_setRptEna(rcb, true);
IedConnection_setRCBValues(con, &error, rcb, RCB_ELEMENT_RPT_ENA, true);

If you no longer want to receive reports from a RCB you can use the IedConnection_setRCBValues function with rptEna set to false or the IedConnection_disableReporting function.

Controlling a device

Please have a look at the separate control tutorial.

Using file services

TBD

Access to the underlying MMS API

If you need to perform some advanced tasks that are not supported by the IEC 61850 client API you can also get access to the underlying MMS API. Be aware that by using this API it is not guaranteed that the resulting behavior is compliant with the IEC 61850 specification. It is in the responsibility of the application programmer to ensure that the resulting program is compliant with the specification if this is required. You can get the underlying MmsConnection object by calling the IedConnetion_getMmsConnection function.

Using authentication

Currently the client stack only supports basic password authentication. Work on certificate based authentication is in progress.

To use authentication it is required to access the MmsConnection object:

clientSideAuthentication

56 thoughts on “IEC 61850 client tutorial

  1. bikash

    Hi,

    I want to use authentication in the application which server example shall i run to create a server which requires validation frm the client, i tried with mms_client_example4, its not able to crete the server please help.

    Thanks
    Bikash

    Reply
    1. Michael Zillgith Post author

      The server_example4 uses password authentication. If you want to use some of the example clients (like iec61850_client_example5) you have to change the password to match the server.

      Reply
  2. bikash

    Hi,

    Please help on this, I am connecting with the actual device P14NB model, the client example is not able to connect gives an error ” Connection rejected by server”.

    Thanks,
    Bikash

    Reply
  3. bikash

    Hi,
    while establishing connection with the IED getting error in method static CotpIndication
    parseCotpMessage(CotpConnection* self), here tpduType returning as 128.

    Thanks in advance,
    Bikash

    Reply
      1. Michael Zillgith Post author

        Hi Bikash, Hi Jens,
        can you please send me a wireshark capture file (to the email at the contact page) of the connection attempt? I guess it is some problem with the connection parameters (maybe T selector).

        Reply
  4. Mladen

    Hello, I have trouble using the reporting with the C# API and ABB relay protections. I have followed the Reporting exmple and my code looks like this:

    string rc_ref = "AA1J1Q11LD0/LLN0.BR.rcb_StatUrg"; //Report is Buffered
    ReportControlBlock rcb = connection.GetReportControlBlock(rc_ref);
    rcb.GetRCBValues();

    The GetRCBValues(); function throws exception with code 99 after calling

    IedConnection_getRCBValues (connection, out error, objectReference, self);

    The RCB path in the protection is AA1J1Q11LD0/LLN0.rcb_StatUrg.
    I have tried calling GetBufTm(); GetIntgPd(); GetTrgOps(); GetDataSetReference(); they all return 0 or Null.

    Reply
      1. Chris

        Hey Mladen,

        I’m also working ABB protection equipment and I’m running into the same error you described, except I’m using the C api. How did you solve your error? My erroneous line looks like:

        ClientReportControlBlock rcb = IedConnection_getRCBValues(con, &error, “REL_90LD0/LLN0.RP.rcbMeasFlt”, NULL); // Unbuffered report

        I assume it is the reference string that is the issue but, if not, maybe how you solved it in C# could help me also.

        I’ve tried several variations of this reference string, with combinations of ‘$’, ‘/’, and ‘.’ as separators, but nothing seems to work. The best I’ve gotten is no error returned but rcb was returned as NULL, breaking any following code.

        Thanks,
        Chris

        Reply
        1. Michael Zillgith Post author

          Hi Chris,

          your reference string seems to be correct for me. Can you send me a wireshark capture file (e.g. by email) so I can see what the server answers? Then it should be easy to determine the problem.

          Regards,
          Michael

          Reply
  5. Manoj

    Hi,
    Please help me i stucked one error like Failed to create data set from the function in Client API C#.
    IedConnection_createDataSet(connection, out error, dataSetReference, linkedList);
    out error is giving= 20
    Thanks in advance,
    Manoj

    Reply
    1. Michael Zillgith Post author

      Some server devices don’t support the CreateDataSet service. Information about that can be found in the PICS document of the server. Anyway the error code is misleading. I will change this in the upcoming version.

      Reply
      1. Manoj

        HI..
        i unable to load the iec61850 Dll file when my applicaton run.. its not taking the module iec61850 i copied this in sys32 folder…

        Thnks in Advance

        Reply
  6. Ashwin

    Hi
    Any idea why this is failed?
    I am not able to write value to server using following:
    write fail due to IED_ERROR_ACCESS_DENIED = 21
    /* write a variable to the server */
    value = MmsValue_newVisibleString(“libiec61850.com”);
    IedConnection_writeObject(con, &error,
    “simpleIOGenericIO/GGIO1.NamPlt.vendor”, DC, value);

    if (error != IED_ERROR_OK)
    printf(“failed to write simpleIOGenericIO/GGIO1.NamPlt.vendor!\n”);

    Reply
    1. Michael Zillgith Post author

      Hi,
      if you are using this code with the server examples of libiec61850 then this is prevented by the default access rights. Per default access to variables with FC=DC and FC=CF is not allowed. To change this you have to add this code to the server:

      IedServer_setWriteAccessPolicy(iedServer, IEC61850_FC_DC, ACCESS_POLICY_ALLOW);

      Reply
  7. Methane

    Hi,
    Thank you for the interesting lib, all most I had been experienced all the examples and every thing was working fine within windows system. I tried the client example3 with the server example3 and writing value to change the SPCSO1, SPCSO3 and it was working fine, Please any idea if I want also to control the external device over the output from the header in to the beagle bone lets say GPIO 44? thank you for helping in advance

    Reply
  8. Serenella Ferri De Collibus

    Hi,
    I’m new on libiec61850. I’m trying to use the reports and I’m noticed the function ‘IedConnection_enableReporting’ is never implemented in the library ( in the example:

    IedConnection_enableReporting(con, &error, ”
    simpleIOGenericIO/LLN0.RP.EventsRCB”,
    clientDataSet,
    TRG_OPT_DATA_UPDATE | TRG_OPT_INTEGRITY,
    reportCallbackFunction,
    ClientDataSet_getDataSetValues(clientDataSet));).
    How can I set the trigger options and enable the reports?
    Thank you.

    Reply
    1. Michael Zillgith Post author

      Hi, the IedConnection_enableReporting function is outdated. For how to enable reporting you can find an example in examples/iec61850_client_example_reporting.

      Reply
  9. Andrew

    If, I want to subscribe more than one report.
    What can i do?
    I must use some threads or something else?
    Thanks for advice.

    Reply
  10. muneer

    sir,i have used IedConnection_getFile(…) to download a file from server,but i don’t understand where it is downloaded(location) .i got the response that the number of byte is recieved.

    Reply
    1. Michael Zillgith Post author

      You have to provide a callback function to receive the data of the file. It is up to you to store the data in a file locally when required. Please look at the example in the folder examples/iec61850_client_example_files.

      Reply
  11. said

    IEC 61850 client tutorial says that “This client API is designed to be as close as possible to the IEC 61850 ACSI (abstract communication service interface) as defined in IEC 61850-7-2. But be aware that there are some points where there are some deviations from the ACSI due to practical reasons.”
    can you tell me the deviations, please?

    Reply
    1. Michael Zillgith Post author

      Since the ACSI is actually not an API description but a description what the services are about to do this is not easy to tell. I have not an exhaustive list of such “deviations”. There are some differences in the scope of allowed parameters where the API is usually more close to the MMS mapping. Also in some services there is not a simple one to one mapping between ACSI services and MMS services. E.g. the data model discovery functions like GetLogicalNodeDirectory using the MMS GetNameList cannot be easily mapped one to one without a lot of redundant MMS requests. Here the GetNameList call is done only once for each logical device (MMS domain) and the results are cached in the client for later API calls. So not each API call will result in MMS request.

      Reply
      1. said

        Thank you for the explanation, Michael.
        If I want to connect/communicate this IEC 61850 client to IEDs from many vendors ( eg. siemens, ABB, alstom etc), whether there will be a problem/issue in the communication because of those “deviations” ?
        Best regards.

        Reply
        1. Michael Zillgith Post author

          No this doesn’t influence the standard compliance of the communication. It only affects the API and is intended to improve usability and efficiency.

          Reply
  12. Serenella Ferri De Collibus

    Hi,
    I’m using libiec61850 with OpenMUC. I use the server side in order to simulate the IED, in particular the server_example_5, and a bundle in OpenMUC attempts to write the DA ied1Inverter/ZINV1.OutWSet.setMag.f:SP on the server.
    The policy for FC=SP is set to ALLOW but the write operation from the OpenMUC bundle fails; the error is ‘object_access_denied’ coming from the openiec61850 java library used by OpenMUC. Any idea?
    Thanks.
    Serenella Ferri De Collibus

    Reply
  13. Jarkko

    I am trying code below with ABB relay but GetRCBValues() is returning error code 22 IED_ERROR_OBJECT_DOES_NOT_EXIST). RCB id should be correct, because I checked it with PCM600 tool.

    string rcbReference1 = “AA1J1Q01A1LD0/LLN0.BR.rcbMeasFlt”;
    ReportControlBlock rcb1 = con.GetReportControlBlock(rcbReference1);
    rcb1.GetRCBValues();

    Reply
    1. Jarkko

      Had to add indexes to RCB id:s

      string rcbReference1 = “AA1J1Q01A1LD0/LLN0.BR.rcbMeasFlt01”;
      string rcbReference2 = “AA1J1Q01A1LD0/LLN0.BR.rcbMeasReg01”;

      Reply
  14. said

    Hi Michael,
    How to get stval of GGIO1.SPCO1 from report when the dataset of the report for the GGIO1.SPCO1 contains not only stval, but contains q and t. for example the dataset is :
    -GGIO1.SPCO1
    — stval
    — q
    — t
    -GGIO1.SPCO2
    — stval
    — q
    — t
    …….
    Please tell me the source code to get stval of GGIO1.SPCO1, because in the example (client_example_reporting.c) the dataset of the server containts stval only,
    (-GGIO1.SPCO1.stval, -GGIO1.SPCO2.stval, -GGIO1.SPCO3.stval, -GGIO1.SPCO4.stval)
    thank you

    Reply
    1. rock61850

      hello
      i got this msg

      An unhandled exception of type ‘System.DllNotFoundException’ occurred in iec61850dotnet.dll

      Additional information: Unable to load DLL ‘iec61850’: The specified module could not be found. (Exception from HRESULT: 0x8007007E)

      please help

      Reply
  15. Alexandr Leonov

    Hi
    I’m testing the receiving of reports in Visual Studio 2013, following the example from the folder libiec61850-1.0.0 \ dotnet \ report_new_dataset \ inside the dotnet project assembly.
    Testing is performed on Windows7 using libiec61850-1.0.0 library.
    In the example, I changed the references to the dataset and the dataset within the dataset according to the device.
    When you start the application, the device generates a report and starts the report sending mechanism. Reports come to the PC – this can be viewed using Wireshark, but the reportHandler (Report report, object parameter) is not called.
    When checking by the debugger, even the internal report handler IInternalReportHandler (IntPtr parameter, IntPtr report) is not called.
    I assume that the native library iec61850.dll does not call the callback callback function.
    What could be the problem ?

    Reply
    1. Michael Zillgith Post author

      Hi,
      the reports are identified by the rptId string. If the rptId of the received report doesn’t match with the expected rptId the report will be ignored. When the RptId attribute is not explicitly set in the report control block the server has to send a default rptID with the report. This default rptID should reflect the full object reference of the report control block. Since it is not so clear from the IEC 61850 specification how the exact format of this object reference should be there are different ways that servers encode it (e.g. using “$” or “.” as component separator). This may cause the problem. There has also been a fix regarding this behavior (see github or the latest release 1.0.1). To be sure you can try to set the RptId manually before enabling the report:


      rcb.SetRptId("myreportid");
      rcb.SetRCBValues();

      Then the client should be able to identify the report.
      Please let me know if this doesn’t solve your problem.

      Reply
      1. Alexandr Leonov

        To solve this problem I was helped by a new implementation libiec61850-1.0.1
        When you create a report, you do not need to specify RptId.
        The server in the response sends the full RptId link in this format “IED_000000001CTRL / Q0GGIO1 $ RP $ urcbA01”
        Everything is working. Thank you

        Reply
  16. Alexandr Leonov

    Hi Michael,
    If you consider the object model of the device using MMS services, then the order of the attributes in the object is “IED_000000001CTRL / Q0GGIO1.SPCSO3”

    сtlModel [CF]
    Oper [CO]
    сdcNs [EX]
    сtlNum [ST]
    origin [ST]
    q [ST]
    stVal [ST]
    t [ST]

    And if you specify a dataset with this object as – IED_000000001CTRL / Q0GGIO1.SPCSO3 [ST],
    Then in the report comes a set of data with a different order of attributes
    origin [ST]
    ctlNum [ST]
    stVal [ST]
    q [ST]
    t [ST]
    In this case, the first three attributes are not present at all, but I understand it so because of FunctionalConstraint = ST
    What is the problem with the order of the attributes? Is there another way to specify a dataset?

    Reply
    1. Michael Zillgith Post author

      Hi Alexandr,
      if you got the first list with the MMS get name list service then the server has to return the list in alphabetical order (this is mandatory according to the MMS specification). But when you read the variables with the read services or got it from reports or by using the MMS get variable access attributes service you will receive the data attributes in the order they are defined in the data model (and this order is also specified in the IEC 61850 specification). So there is a discrepancy that is required by the different specification parts.

      Reply
  17. said

    Hi Michael,
    How to get stval of GGIO1.SPCO1 from report when the dataset of the report for the GGIO1.SPCO1 contains not only stval, but contains q and t. for example the dataset is :
    -GGIO1.SPCO1
    — stval
    — q
    — t
    -GGIO1.SPCO2
    — stval
    — q
    — t
    …….
    Please tell me the source code to get stval of GGIO1.SPCO1, because in the example (client_example_reporting.c) the dataset of the server containts stval only,
    (-GGIO1.SPCO1.stval, -GGIO1.SPCO2.stval, -GGIO1.SPCO3.stval, -GGIO1.SPCO4.stval)
    thank you

    Reply
    1. Michael Zillgith Post author

      Hi,
      in this case the MmsValue objects in the data set are structured values. You can excess the elements with the MmsValue_getElement function.

      Reply
      1. Richard Lee

        Hi Michael:
        Continue the question,when GGIO1.SPCO1 is like below:
        -GGIO1.SPCO1
        — stval
        — q
        — t
        And when i get the report mms value ,a structured values like:
        -0
        -0
        -2017-03-28 12:00:00 xxx
        My question is,when i get the values by using MmsValue_getElement function,how can i know the first 0 is stval,the second 0 is q ? How can i get the Data Attributes‘ names of the DO(or mms value)? Could you give some demo code ?
        Thank you very much!

        Reply
        1. Michael Zillgith Post author

          Hi,
          the values received by MMS don’t contain type information about structured types. But any element that is a basic type contains some type information (MMS_FLOAT, MMS_INTEGER, MMS_BITSTRING…). You can get the type with the MmsValue_getType function. You may then use the type of the element to infer the signification. Anyway this may not be unique because there may be different elements of the same type.
          For the general case there are two ways:
          1) You can rely on the order of the data attributes as they are specified in the CDC of the data object. If the device is standard compliant you can rely on this order.
          2) You can use the IedConnection_getVariableSpecification function once for each dataset member to get the exact type information including the names of the elements. All the required information can be found in the returned MmsVariableSpecification structure.

          Reply
          1. Richard Lee

            Thank you very much for your reply.
            If any more question , i will ask you again later(after think myself)!
            Thank you~~~~~~

      2. said

        I have used ” MmsValue_getBoolean(MmsValue_getElement(MmsValue_getElement(dataSetValues, i), j)) where i & j are the index, And it’s works 🙂

        Thank you for your suggestion, Michael

        Reply
  18. Alexandr Leonov

    Hi Michael
    Michael this time I had a problem with the native library iec61850.dll.
    I designed the project on my machine. Then I transferred both the project and the library – iec61850.dll to another PC. On the PC, I copied this library in the same way to the System32 folder. In this case, on the other machine, the program crashes and displays a BadImageFormatException error. I read: it’s a mistake of the library image. The other machine does not have Visual Studio, but there’s FrameWork. Why does this happen?

    Reply
    1. Michael Zillgith Post author

      Hi, I am not sure. Maybe you need to compile with “Release” instead of “Debug” target? Or perhaps one machine is 64 bit while the other is 32 bit.

      Reply
  19. said

    Hi Michael,
    How to get timestamp including the miliseconds from the MmsValue?
    I have simulated MmsValue (using IED simulator) with timestamp 14/08/2016 18.09.21.656.
    When I used function “MmsValue_toUnixTimestamp”, the result was : 1471172961 s => 14/08/2016 18.09.21,000 (without mili second)
    But when I used function “MmsValue_getUtcTimeInMs”, the result was : -2000820872 (the result was minus , why ?)
    Which function that I must choose to get timestamp including the miliseconds?

    Reply
    1. said

      Sorry, Michael. It’s my fault 🙂
      Prior, I have used “printf(” TIMESTAMP (MILISECOND) : %d”, MmsValue_getUtcTimeInMs((MmsValue_getElement(MmsValue_getElement(dataSetValues, i), j)));
      It’s should be using “printf(” TIMESTAMP (MILISECOND) : %lld”, MmsValue_getUtcTimeInMs((MmsValue_getElement(MmsValue_getElement(dataSetValues, i), j)));
      %lld because it is integer 64 bit.
      And It’s works, thank you michael 🙂

      Reply
  20. said

    Hi Michael,
    File client_example_reporting.c is example for reporting but it’s just for one report of an IED.
    Do you have example for more than one report (multiple reports of an IED)?

    Reply
    1. said

      I already have reportCallbackFunction, dataSetDirectory, clientDataSet, rcb for report #1 then I add reportCallbackFunction2, dataSetDirectory2, clientDataSet2, rcb2 for report #2, And it’s works 🙂
      thank you

      Reply
  21. said

    Hi Michael,
    I have used function “IedConnection_close(con)” to release the connection between IEC61850 client and the IED, but the IEC61850 client did not send ‘release’ to the IED. I have used function “IedConnection_release” too, but It did not send ‘release’ to theIED too. Which function that send ‘release’ to IED?
    Thank You

    Reply
    1. Michael Zillgith Post author

      Hi, you can use the IedConnection_abort function or IedConnection_release function before calling IedConnection_close .

      Reply
  22. Hilaly Adam

    Hi Michael,
    I’m using your library to read reports from GEMultilin F650 and I can read a report but I don’t know if it’s possible or how to use the report handler to read multiple reports

    Reply
    1. Michael Zillgith Post author

      Hi, you can subscribe to multiple reports. Just use a second instance of ClientReportControlBlock and install a second report handler with the RCB object reference and report ID.

      Reply
      1. Hilaly Adam

        I’m using different ReportControlBlock in my application but with one handler (I used the example I found in the library in a for loop and with only one handler that detect the report and save the data in a specific location) but it’s not working should I make a report handler for every report or just one is enough ?

        Reply
  23. Patrick

    Hi,
    In the example, you say:
    static void
    reportHandler (void* parameter, ClientReport report)
    {
    printf(“report received\n”);
    }

    ClientDataSet dataSet = IedConnection_readDataSetValues(con,
    &error, dataSetReference, NULL);

    IedConnection_installReportHandler(con, “simpleIOGenericIO/LLN0.RP.EventsRCB”,
    reportHandler, NULL, dataSet);

    For the reporting part. But now the prototype of installReportHandler don’t use dataSet?
    Unfortunately my subscription doesn’t work, is it due to dataset missing?
    Thanks

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *