Giter Site home page Giter Site logo

mz-automation / libiec61850 Goto Github PK

View Code? Open in Web Editor NEW
792.0 94.0 439.0 6.62 MB

Official repository for libIEC61850, the open-source library for the IEC 61850 protocols

Home Page: http://libiec61850.com/libiec61850

License: GNU General Public License v3.0

CMake 0.83% Makefile 0.24% C 77.47% C# 13.63% Python 0.34% C++ 0.69% CSS 1.14% HTML 0.06% Shell 0.02% Java 5.45% SWIG 0.12%
iec-61850 mms goose

libiec61850's People

Contributors

aaribaud avatar amoorcroft-nortech avatar andy1547 avatar cedricboudinet avatar cngkaygusuz avatar davideandreuzza avatar davidkorczynski avatar fedepell avatar jamieslome avatar kiralypeterprolan avatar mbourhis avatar mzillgith avatar rm5248 avatar romainnaour avatar stv0g avatar vermeulenthi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

libiec61850's Issues

Harmonisation of Sampled Values subscriber / publisher

Hi,

I noticed that the API of Sampled Values subscriber and publisher both use ASDU's as their central entity for storing exchanged measurements.

Both APIs have their own implementations of this data structure: SVClientASDU vs SV_ASDU.

I also noticed that the publisher uses a different naming scheme than the subscriber: SampledValuesPublisher vs SVSubscriber.

I would volunteer to clean up the API by:

  • renaming the publisher code to use the SV prefix
  • Combine the two implementations of Sampled Values ASDUs into one

I would like to know what other users of the library think about these changes and whether they might be merged?

Renaming the functions will break ABI compatibility.

IedServer_update*AttributeValue segmentation fault

When I try to update the value of a DataAttribute inside an Oper Object, the library goes into segmentation fault. Probably what I am trying to do is not so widely used, but could you consider not to crash the application?
Just to detail more my problem, let's assume I want to update a boolean ctlVal. The problem is inside IedServer_updateBooleanAttributeValue, when MmsValue_getBoolean is called.

ReportControl and rptID is empty

Hi Michael,

I made some testing together with Anvil from Triangle MicroWorks (IEC61850 Test Suite). There is one case file TMWSample.icd where prtID is not set inside ReportControl.
You can register as client the reports but the callback function is not executed.

I found small problem in private_IedConnection_handleReport(IedConnection self, MmsValue* value)
(file client_report.c)


while (element != NULL) {
    ClientReport report = (ClientReport) element->data;
    char repID[129];
    char* rptId = report->rptId;

    if (rptId == NULL || (rptId && (strlen(rptId)== 0)))
    {
        strcpy(repID, report->rcbReference);
        StringUtils_replace(repID, '.', '$');
        rptId = repID;
    }


    if (strcmp(MmsValue_toString(rptIdValue), rptId) == 0) {
        matchingReport = report;
        break;
    }

    element = LinkedList_getNext(element);
}

More or less rptId pointer was not NULL but the string was empty.
Regards,

Boris

How convert a void *data in python?

I want find the LD name in python like this:

deviceList, error = iec61850.IedConnection_getLogicalDeviceList(con)
assert (error == iec61850.IED_ERROR_OK)
device = iec61850.LinkedList_getNext(deviceList)
while device:
    print device.data
    device = iec61850.LinkedList_getNext(device)

But 'device.data' is a SWIG void * obj, so result is:
<Swig Object of type 'void *' at 0x........>

I don't know how convert it in python, just modify the 'iec61850.i':

%module iec61850
%{
......
char* Prt2Char(void *prt)
{ return (char*)prt;}
%}
......
char* Prt2Char(void *prt);

then I try again like this:

......
while device:
    print iec61850.Prt2Char(device.data)
......

It's work, but I don't think is good way, does anyone have a better idea?

[C#/C++] BITSTRING Converter

Hi,

I am testing the method (C#): BitStringFromUInt32
It calls (C++) MmsValue_setBitStringFromInteger(valueReference, intValue);

The simple code:

MmsValue value = MmsValue.NewBitString(2);

value.BitStringFromUInt32(0);
Console.WriteLine(value);

value.BitStringFromUInt32(1);
Console.WriteLine(value);

value.BitStringFromUInt32(2);
Console.WriteLine(value);

value.BitStringFromUInt32(3);
Console.WriteLine(value);

Returns:

00 (0)
10 (1)
01 (2)
11 (3)

image

Binary table:

00 (0)
01 (1)
10 (2)
11 (3)

The results should be the same as the binary table. Is this conversion wrong?

Download a file inside a directory

I'm trying to use this library to download files from an IED with 61850 File Transfer protocol. I used GetFile() method from IedConnection class of IEC61850ClientAPI code.

It runs ok for files on the root path, but it does not work for files in a sub-directory.
How do I pass the full path name to GetFile() method in order to download these files?

Problem testing Goose Publisher/Subscriber examples on Ubuntu 16.04 LTS

Hi!

I was able to compile the goose_publisher and goose_subscriber under the examples. When I run the programs, I don't see the subscriber receiving any messages. I do see a three packets generated by the publisher on the interface.

Could you kindly point to how to test if the subscriber is working correctly? There is nothing printed on the shell and I don't see any log files in its folder.

Thanks,

Rakesh

SWIG. ClientReport object/InstallHandler

When I get reports using the C code from the client reporting example everything about works fine:

/* Configure the report receiver */
IedConnection_installReportHandler(con, 
                           "TEMPLATELD0/LLN0.BR.brcbMX0101", 
                            ClientReportControlBlock_getRptId(rcb), 
                            reportCallbackFunction,
                            (void*) dataSetDirectory);

But when I try to implement this example in for Python client --> I'm stucking in InstallReportHandler method:

iec61850.IedConnection_installReportHandler(con,
                                                "TEMPLATELD0/LLN0.BR.brcbMX0101",
                                                iec61850.ClientReportControlBlock_getRptId(rcb),
                                                MyCallbackFunction,
                                                dataSetDirectory
                                                )

and as a result of it is "Argument 4 of type ReportCallBackFunction" exception from wrapper.cxx parsing part,
If I use MyCallBackFunction() ---with brackets then It calls each time when IedConnection_installReportHandler calls

Issue.part 2:
as a result of it: In C-code it's easy to create and manipulate with ClientReport objects (from example too):

void reportCallbackFunction(void* parameter, ClientReport report)

but in iec61850.py there is only ClientReport methods that take this object as a parameter

If it not from issue-graded problem:
Can anyone provide any example for this "InstallHandler - Receive by event - Create and Read ClientReport object" chain

Thanks/Ivan

[C# API] CreateControlObject throws System.AccessViolationException on Dispose

Hi,

I realized that I get an error when I use the command IedConnection.Dispose() after ControlObject.CreateControlObject().

The error only occurs when I use ControlObject.CreateControlObject().
However, the command was executed successfully.

image
image

System.AccessViolationException was unhandled
HResult=-2147467261
Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Source=iec61850dotnet
StackTrace:
at IEC61850.Client.ControlObject.ControlObjectClient_destroy(IntPtr self)
at IEC61850.Client.ControlObject.Finalize()
InnerException:

[sample code]

    public enum Dbpos
    {
        INTERMEDIATE_STATE = 0,
        OFF = 1,
        ON = 2,
        BAD_STATE = 3
    }

    public static void Main(string[] args)
    {
        string hostname = "192.168.0.125";
        int port = 102;

        IedConnection iedConnection = new IedConnection();

        try
        {
            iedConnection.Connect(hostname, port);

            Dbpos stVal = (Dbpos)iedConnection.ReadBitStringValue("IED7SJ63CTRL/Q0CSWI1.Pos.stVal", FunctionalConstraint.ST);
            Validity q = iedConnection.ReadQualityValue("IED7SJ63CTRL/Q0CSWI1.Pos.q", FunctionalConstraint.ST).GetValidity();
            DateTimeOffset t = MmsValue.MsTimeToDateTimeOffset(iedConnection.ReadTimestampValue("IED7SJ63CTRL/Q0CSWI1.Pos.t", FunctionalConstraint.ST).TimeInMilliseconds);

            bool ctlVal = false;

            switch (stVal)
            {
                case Dbpos.BAD_STATE:
                case Dbpos.INTERMEDIATE_STATE:
                    break;

                case Dbpos.OFF:
                    ctlVal = false;
                    break;

                case Dbpos.ON:
                    ctlVal = true;
                    break;
            }

            ControlObject control = iedConnection.CreateControlObject("IED7SJ63CTRL/Q0CSWI1.Pos");
            control.SetOrigin("192.168.0.100", OrCat.REMOTE_CONTROL);

            switch (control.GetControlModel())
            {
                case ControlModel.STATUS_ONLY:
                    break;

                case ControlModel.DIRECT_NORMAL:
                case ControlModel.DIRECT_ENHANCED:
                    Console.WriteLine(control.Operate(ctlVal) ? "Operated successfully!" : "Operate failed!");
                    break;

                case ControlModel.SBO_NORMAL:
                case ControlModel.SBO_ENHANCED:
                    if (control.SelectWithValue(ctlVal))
                    {
                        Console.WriteLine(control.Operate(ctlVal) ? "Operated successfully!" : "Operate failed!");
                    }
                    else
                        Console.WriteLine("Select failed!");
                    break;
            }

            LastApplError error = control.GetLastApplError();

            iedConnection.Abort();
        }
        catch (IedConnectionException ex)
        {
            Console.WriteLine("[IED ERROR: ({0}) {1}] {2}", (int)ex.GetIedClientError(), ex.GetIedClientError(), ex.Message);
        }
        finally
        {
            iedConnection.Dispose();
        }
    }

MmsVariableSpecification_getName

Hi Michael,

I am not able to get name from MmsVariableSpecification. It is always empty and I cannot find the code in the library where the name is assigned.

MmsVariableSpecification* var = IedConnection_getVariableSpecification(con, &error, dataAttributeReference, fc);
if(error != IED_ERROR_OK)
{
    printf("Failed to read Variable Specification (error code: %i)\n", error);
    return;
}
printf("Variable Name: %s\n", MmsVariableSpecification_getName(var));

Best Regards,
Boris

Problem when generating model configuration file

When I run genconfig.jar, I get the following exception:

parse IED section ...
Exception in thread "main" java.lang.NumberFormatException: For input string: "0,01"
	at sun.misc.FloatingDecimal.readJavaFormatString(Unknown Source)
	at sun.misc.FloatingDecimal.parseFloat(Unknown Source)
	at java.lang.Float.parseFloat(Unknown Source)
	at java.lang.Float.<init>(Unknown Source)
	at com.libiec61850.scl.model.DataModelValue.<init>(DataModelValue.java:113)
	at com.libiec61850.scl.model.LogicalNode.parseDataAttributeNodes(LogicalNode.java:191)
	at com.libiec61850.scl.model.LogicalNode.parseSubDataInstances(LogicalNode.java:220)
	at com.libiec61850.scl.model.LogicalNode.<init>(LogicalNode.java:169)
	at com.libiec61850.scl.model.LogicalDevice.parseLogicalNodes(LogicalDevice.java:65)
	at com.libiec61850.scl.model.LogicalDevice.<init>(LogicalDevice.java:49)
	at com.libiec61850.scl.model.Server.<init>(Server.java:52)
	at com.libiec61850.scl.model.AccessPoint.<init>(AccessPoint.java:48)
	at com.libiec61850.scl.model.IED.<init>(IED.java:50)
	at com.libiec61850.scl.SclParser.parseIedSections(SclParser.java:240)
	at com.libiec61850.scl.SclParser.<init>(SclParser.java:89)
	at com.libiec61850.scl.SclParser.<init>(SclParser.java:102)
	at com.libiec61850.tools.DynamicModelGenerator.<init>(DynamicModelGenerator.java:62)
	at com.libiec61850.tools.DynamicModelGenerator.main(DynamicModelGenerator.java:454)

The problem is that my CID file contains some Vals of float DAIs that are initialized with the comma as a decimal separator, and the constructor of Java Float objects only accepts the dot as decimal separator.
I looked in the standard, and I only found this section in IEC61850-6 that describes the XML schema for the values:

<xs:complexType name="tVal">
   <xs:simpleContent>
      <xs:extension base="xs:normalizedString">
         <xs:attribute name="sGroup" type="xs:unsignedInt" use="optional"/>
      </xs:extension>
   </xs:simpleContent>
</xs:complexType>

It is not clear to me whether the comma separator is accepted or not. Is it possible to make the Java program more robust?

Reporting behaviour in version 1.1.1

Hi,
I noticed a strange behaviour that was not present in version 1.0.
It occous when I use reporting in the client api, sometimes ( not always ) when the callback is called the :

MmsValue* dataSetValues = ClientReport_getDataSetValues(report);

gave me the previous (N-1) MmsValue, like it has not been correctly updated in memory.
The ClientReport_getSeqNum(report) gave me correct SeqNum, identical to IED Scout sniffer, but the mms values were not updated.
I confirm that everything worked perfectly on version 1.0

I tried to check differences in the libraries, but I have not found anything for now..

Has anybody seen something similar? Thanks a lot!

How to utilize control operation for Python (SWIG)?

I've managed to build the lib for Python and now am using it to run a IEC 61850 server.
However SWIG was not able to adopt the control model callback "typedef ControlHandlerResult" in order to utilize the corresponding IedServer_setControlHandler().
The way I see it, there are two options to convert the callback function / typedefs via SWIG:

  1. Modifying the interface-file (*.i) and adding the callback.
  2. Modifying the C source code and rewriting the function.
    Anyway I'm struggling to find the correct solution to make the control operation available in Python, mainly because my skills in C are only very basic. Also my aim is to use the libIEC61850 in Python, since I'm connecting to different APIs via Python.

How can I utilize the control operation with Python?
Does anyone have a description on how to modify the interface file or the source code in order to utilize the control operation with Python?

Regards!

Memory growth when using Report

Hi @mzillgith

I was testing report. I realized that some IED can disable a report without a disconnection. I need to constantly check if the report is enabled. I noticed a memory growth while checking if the report is enabled. This occurs with or without receiving reports. Is this way to verify and enable report correct?

while (running)
{
	ReportControlBlock report = connection.GetReportControlBlock(address);
	report.GetRCBValues();

	bool isReportEnabled = report.GetRptEna();

	if (!isReportEnabled)
	{
		//var a = report.GetOptFlds();
		//var b = report.GetTrgOps();
		//var c = report.GetIntgPd();
		//var d = report.GetGI();
		//var e = report.GetPurgeBuf();
		//var f = report.GetResv();

		//report.SetOptFlds();
		//report.SetTrgOps();
		//report.SetEntryID();

		report.InstallReportHandler(ReportHandler, point);
		report.SetRptEna(true);
		report.SetRCBValues();
	}
}  

I was also thinking of using the method connection.ReadValue instead of report.GetRCBValues to check if RptEna attribute is true or false.

Can you check if a memory leak is occurring when methods are called?

Obs: Wireshark log attached.

wireshark.zip

How to enable keepalive ?

I use libiec61850 in Linux, I wonder how to enable the keepalive,
In stack_config.h , there is a define:
#define CONFIG_ACTIVATE_TCP_KEEPALIVE 1
when TcpServerSocket_create or Socket_connect is called, the above define will be judged, if it is defined activateKeepAlive will be called.
But in socket_linux.c, in the activateKeepAlive function, there are two defines SO_KEEPALIVE and TCP_KEEPCNT,
Do I need to define them by myself?

static void
activateKeepAlive(int sd)
{
#if defined SO_KEEPALIVE
    int optval;
    socklen_t optlen = sizeof(optval);

    optval = 1;
    setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen);

#if defined TCP_KEEPCNT
    optval = CONFIG_TCP_KEEPALIVE_IDLE;
    setsockopt(sd, IPPROTO_TCP, TCP_KEEPIDLE, &optval, optlen);

    optval = CONFIG_TCP_KEEPALIVE_INTERVAL;
    setsockopt(sd, IPPROTO_TCP, TCP_KEEPINTVL, &optval, optlen);

    optval = CONFIG_TCP_KEEPALIVE_CNT;
    setsockopt(sd, IPPROTO_TCP, TCP_KEEPCNT, &optval, optlen);
#endif /* TCP_KEEPCNT */

#endif /* SO_KEEPALIVE */
}

Is that possible to keep the events on buffered report ?

Everyday there are some events generate in my device, only when the client enable the buffered report the device will report events to client. But if power outage all there events will lost due to all the events was buffered in memory. Have any ways to avoid this situation ?

[C#] [ReportControlBlock] The methods (SetTrgOps / SetOptFlds) throwing System.AccessViolationException

Hi,

I am testing the reports. I used the sample projects on dotnet solution

image

image

System.AccessViolationException was unhandled HResult=-2147467261 Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt. Source=iec61850dotnet StackTrace: at IEC61850.Client.ReportControlBlock.ClientReportControlBlock_setTrgOps(IntPtr self, Int32 trgOps) at IEC61850.Client.ReportControlBlock.SetTrgOps(TriggerOptions trgOps) at Debugger.IEC61850v2.Program.Main(String[] args) in C:\Tests\IEC61850\Program.cs:line 118 at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() InnerException:

I realized that the exception is only thrown if the program executes the method GetRCBValues (Image 1 line 3). If this method is not executed. There is no exception and the command works perfectly.

It does not appear to be an error in communication or protocol. Since the SetRCBValues method is not even executed. I believe the problem is in the ReportControlBlock object.

Failed to generate the DLL

When generating the project iec61850 tells me: Can not open file include: 'inttypes.h': No such file or directory.

What do I do wrong?

2 events happened in a second, only one is reported

Hi here,

i am using the buffer report function. something issue happened.
when two events happened in a second, only one is recorded in the report buffer,
if the two events happen more then a second interval, there are two record in the report buffer.
could you analysis this ?

How to associate values with data attribute names?

Is there an easy way to associate the LinkedList of IedConnection_getDataSetDirectory() to the ClientDataSet of IedConnection_readDataSetValues()?

Or even better, is there a way to associate each MMS Structure of MmsConnection_readVariable(Domain, LogicalNode) to the Linked List of MmsConnection_getDomainVariableNames(Domain)?

e.g.

# MmsConnection_getDomainVariableNames("ied1Example")
EVCT
...
EVCT$DC
EVCT$DC$Comm
EVCT$DC$Comm$id
...
EVCT$ST
EVCT$ST$Comm
EVCT$ST$Comm$func

# MmsConnection_readVariable("ied1Example", "EVCT")
{{{Function 1}},{{ID 1}},{{FunctionEvents,false,false,ied1Example/EVCT$FunctionDataset,0,0001000000,0,0,010000,0,false,}}}

The getDomainVariableNames prints the id reference first, but readVariable prints the func value first.

I want to avoid doing several calls for each data attribute and I can't figure out a way to automatically link the values from readVariable to the structure of getDomainVariableNames. Any suggestions?

Thanks!

[C#] Control Operate (MMS_FLOAT) (CAUSE_UNKNOWN)

Hi,

I have already been able to use the operation method on boolean, integer and bit_string control points.
I am trying to use the command operate for float point. But, I am getting an error.

Model: DIRECT_NORMAL
image

[Code]

IedConnection connection = new IedConnection();
connection.Connect("192.168.0.108", 102);

ControlObject control = connection.CreateControlObject("Xtorm_ServerLogicalDevice/YEFN1.ColPos");
control.SetOrigin("192.168.0.249", OrCat.REMOTE_CONTROL);

MmsValue value = new MmsValue(1.0f);
bool isOperated = control.Operate(value);

LastApplError result = control.GetLastApplError();

The Operate method returns: false
image

Wireshark:
image

image

image

image

Am I doing something wrong?

Reason code and DataSet members parameters missing in buffered report

  • when the "CUrrent index" parameter of dataset changed, the lib will generate an buffered report.
    but the strange is that sometimes client received an buffered report which missing the Reason code and DataSet members parameters.
    My understanding is: if no data changed should no buffered report was received.
    but see below log, there are 3 new report were received by client, the last one lost Reason code and DataSet members parameters, is there something wrong with the lib?

2018-05-04 09:01:12.878] [osgp-tst-03] [Thread-118] INFO c.a.o.a.p.i.i.n.r.Iec61850ClientSSLDEventListener@newReport:96 - newReport for device: KAI-002, reportId: evn_rpn, timeOfEntry: 2018-05-04T21:00:00.887Z, sqNum: 0
2018-05-04 09:01:12.878] [osgp-tst-03] [Thread-118] WARN c.a.o.a.p.i.i.n.r.Iec61850ClientSSLDEventListener@newReport:100 - Buffer Overflow reported for device: KAI-002, reportId: evn_rpn, timeOfEntry: 2018-05-04T21:00:00.887Z, sqNum: 0 - entries within the buffer may have been lost.
2018-05-04 09:01:12.878] [osgp-tst-03] [Thread-118] INFO c.a.o.a.p.i.i.n.r.Iec61850ClientSSLDEventListener@logReportDetails:277 - Report details for device KAI-002
RptId: evn_rpn
DataSetRef: SWDeviceGenericIO/LLN0.evn_rpn
ConfRev: null
BufOvfl: true
EntryId: none: [0, 0, 1, 99, 44, -12, 87, -9]
InclusionBitString: [true]
MoreSegmentsFollow: false
SqNum: 0
SubSqNum: null
TimeOfEntry: none: 1083704400887
(2018-05-04T21:00:00.887Z)
ReasonCodes:
0x40 (DataChange)
DataSet: SWDeviceGenericIO/LLN0.evn_rpn
DataSet members: 1
member: SWDeviceGenericIO/CSLC.EvnRpn [ST]
SWDeviceGenericIO/CSLC.EvnRpn.evnType: 2
SWDeviceGenericIO/CSLC.EvnRpn.swNum: 2
SWDeviceGenericIO/CSLC.EvnRpn.trgType: 2
SWDeviceGenericIO/CSLC.EvnRpn.swVal: true
SWDeviceGenericIO/CSLC.EvnRpn.trgTime: Fri May 04 09:01:02 UTC 2018
SWDeviceGenericIO/CSLC.EvnRpn.remark: CUrrent index:4
evnType: 2 = LIGHT_EVENTS_LIGHT_ON
swNum: 2 = get external index for switch 2
trgType: 2 = ad-hoc trigger
swVal: true = ON
trgTime: 2018-05-04T09:01:02.000Z
remark: CUrrent index:4

2018-05-04 09:01:12.879] [osgp-tst-03] [Thread-118] INFO c.a.o.a.p.i.i.n.r.Iec61850ClientSSLDEventListener@newReport:121 - Handle member SWDeviceGenericIO/CSLC.EvnRpn for device: KAI-002, reportId: evn_rpn, timeOfEntry: 2018-05-04T21:00:00.887Z, sqNum: 0
2018-05-04 09:01:12.896] [osgp-tst-03] [Thread-120] INFO c.a.o.a.p.i.i.n.r.Iec61850ClientSSLDEventListener@newReport:96 - newReport for device: KAI-002, reportId: evn_rpn, timeOfEntry: 2018-05-04T21:00:00.888Z, sqNum: 1
2018-05-04 09:01:12.896] [osgp-tst-03] [Thread-120] INFO c.a.o.a.p.i.i.n.r.Iec61850ClientSSLDEventListener@logReportDetails:277 - Report details for device KAI-002
RptId: evn_rpn
DataSetRef: SWDeviceGenericIO/LLN0.evn_rpn
ConfRev: null
BufOvfl: false
EntryId: none: [0, 0, 1, 99, 44, -12, 87, -8]
InclusionBitString: [true]
MoreSegmentsFollow: false
SqNum: 1
SubSqNum: null
TimeOfEntry: none: 1083704400888
(2018-05-04T21:00:00.888Z)
ReasonCodes:
0x40 (DataChange)
DataSet: SWDeviceGenericIO/LLN0.evn_rpn
DataSet members: 1
member: SWDeviceGenericIO/CSLC.EvnRpn [ST]
SWDeviceGenericIO/CSLC.EvnRpn.evnType: 2
SWDeviceGenericIO/CSLC.EvnRpn.swNum: 3
SWDeviceGenericIO/CSLC.EvnRpn.trgType: 2
SWDeviceGenericIO/CSLC.EvnRpn.swVal: true
SWDeviceGenericIO/CSLC.EvnRpn.trgTime: Fri May 04 09:01:03 UTC 2018
SWDeviceGenericIO/CSLC.EvnRpn.remark: CUrrent index:5
evnType: 2 = LIGHT_EVENTS_LIGHT_ON
swNum: 3 = get external index for switch 3
trgType: 2 = ad-hoc trigger
swVal: true = ON
trgTime: 2018-05-04T09:01:03.000Z
remark: CUrrent index:5

2018-05-04 09:01:12.896] [osgp-tst-03] [Thread-120] INFO c.a.o.a.p.i.i.n.r.Iec61850ClientSSLDEventListener@newReport:121 - Handle member SWDeviceGenericIO/CSLC.EvnRpn for device: KAI-002, reportId: evn_rpn, timeOfEntry: 2018-05-04T21:00:00.888Z, sqNum: 1
2018-05-04 09:01:12.960] [osgp-tst-03] [Thread-121] INFO c.a.o.a.p.i.i.n.r.Iec61850ClientSSLDEventListener@newReport:96 - newReport for device: KAI-002, reportId: evn_rpn, timeOfEntry: 2018-05-04T21:00:00.889Z, sqNum: 2
2018-05-04 09:01:12.960] [osgp-tst-03] [Thread-121] INFO c.a.o.a.p.i.i.n.r.Iec61850ClientSSLDEventListener@logReportDetails:277 - Report details for device KAI-002
RptId: evn_rpn
DataSetRef: SWDeviceGenericIO/LLN0.evn_rpn
ConfRev: null
BufOvfl: false
EntryId: none: [0, 0, 1, 99, 44, -12, 87, -7]
InclusionBitString: [false]
MoreSegmentsFollow: false
SqNum: 2
SubSqNum: null
TimeOfEntry: none: 1083704400889
(2018-05-04T21:00:00.889Z)
DataSet: SWDeviceGenericIO/LLN0.evn_rpn

2018-05-04 09:01:12.960] [osgp-tst-03] [Thread-121] WARN c.a.o.a.p.i.i.n.r.Iec61850ClientSSLDEventListener@newReport:111 - No dataSet members available for device: KAI-002, reportId: evn_rpn, timeOfEntry: 2018-05-04T21:00:00.889Z, sqNum: 2
2018-05-04 09:01:27.808] [osgp-tst-03] [Thread-122] INFO c.a.o.a.p.i.i.n.r.Iec61850ClientSSLDEventListener@associationClosed:370 - associationClosed() for device: KAI-002, IOException: Connection reset

server_example1 missing

The following directory is missing in the latest version of the repository, but it is mentioned in the Readme.md

cd examples/server_example1
sudo ./server_example1

client file requests with long name generate invalid encoding

Looks like bug is here in mms_client_files.c mmsclient_createFileDirectoryRequest

uint32_t confirmedRequestPduSize = 1 + 2 + 2 + invokeIdSize + 0; /// This line assumes 
                                                                 /// a fixed length octet for the 
                                                                 /// File dir tagged data
uint32_t parameterSize = 0;

if (fileSpecification)
    parameterSize += encodeFileSpecification(0xa0, fileSpecification, NULL, 0);
if (continueAfter)
    parameterSize += encodeFileSpecification(0xa1, continueAfter, NULL, 0);

This seems to happen elsewhere in this file as well.

[C#] [Windows] Project Platform Target only works on x86 ?

Hi,

I realized that if the project platform target is not x86.

image

I get the exception:

image

System.BadImageFormatException was unhandled HResult=-2147024885 Message=An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B) Source=iec61850dotnet StackTrace: at IEC61850.Client.IedConnection.IedConnection_create() at IEC61850.Client.IedConnection..ctor() in C:\libiec61850-master\dotnet\IEC61850forCSharp\IEC61850ClientAPI.cs:line 410 at example1.MainClass.Main(String[] args) in C:\libiec61850-master\dotnet\example1\Main.cs:line 13 at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() InnerException:

I created C++ library by command: cmake -G "Visual Studio 14" C:\libiec61850-master

Am I doing something wrong? Do I have to configure some platform variable?

Control operate not working (ADD_CAUSE_NOT_SUPPORTED)

Hello,

This is a nice project and I am trying to use it.

I have this IED:

image

I am trying to operate a command:

            IedConnection iedConnection = new IedConnection();
            iedConnection.Connect("192.168.0.125", "102");

            switch (controlModel)
            {
                case ControlModel.STATUS_ONLY:
                    Console.WriteLine("Control is status-only!");
                    break;

                case ControlModel.DIRECT_NORMAL:
                case ControlModel.DIRECT_ENHANCED:
                    if (control.Operate(true))
                        Console.WriteLine("operated successfully!");
                    else
                        Console.WriteLine("operate failed!");
                    break;

                case ControlModel.SBO_NORMAL:
                case ControlModel.SBO_ENHANCED:
                    if (control.Operate(false))
                        Console.WriteLine("operated successfully!");
                    else
                        Console.WriteLine("operate failed!");

                    LastApplError error = control.GetLastApplError();

                    break;
            }

            iedConnection.Abort();
            iedConnection.Dispose();

I get error: ADD_CAUSE_NOT_SUPPORTED

What am I doing wrong?

running sampled values examples

Is there anywhere a guide to run the examples concerning the sampled values (publisher/subscriber). It would be great to me.

Since now, I have successfully built the library; I am using Ubuntu 16.04 and I have tried the examples
libiec61850/examples/iec61850_9_2LE_example
libiec61850/examples/iec6185_sv_client_example

These are logs:
log publisher
log subscriber

I presume that subscriber should receive SV, but It seams to stop on some access error.

Thank you in advance,
eng. Stefano Del Prete
research assistan
University of Campania.

Support for R-GOOSE and R-SV (IEC TR 61850-90-5)

IEC TR 61850-90-5 introduces a mechanism for transfer of digital states and time synchronized phasor measurement data over wide-area networks between Phasor Measurement Units (PMUs), Phasor Data Concentrators (PDCs) and WAMPAC applications in the context of IEC 61850.

From: Interpreting and Implementing IEC 61850-90-5 Routed-Sampled Value and Routed-GOOSE Protocols for IEEE C37.118.2 Compliant Wide-Area Synchrophasor Data Transfer

For our research we implemented R-GOOSE in a private fork of libiec61850.
We would like to know if there is interest in merging support for this technical report (TR 61850-90-5) into libiec61850.

Disclaimer: we are not related to the original authors of the above mentioned paper.

Delete

I was wrong about the doubt. Please, delete.

Unnecessary delay in SVReceiver

The SVReceive loop uses Thread_sleep() to wait 1 millisecond in case no packet is currently in the input buffer. This time is lost and can increase the worst case latency to receive a SV packet to 1 ms.

This is mainly because Ethernet_receivePacket() does not block and immediately returns using the MSG_DONTWAIT flag.

I propose to add a poll() / select() compatible interface.

BufferedRCBs error

  1. compile with cygwin + arm-mingw32ce-gcc (v0.59.1) for WinCE.
  2. unrecognized command line option "-mno-unaligned-access", so unaligned access on arm(arm926ej-s).
  3. the buffer report on the iedserver is enabled by the client.
  4. error in reporting.c/sendNextReportEntry()/ add data set value elements/ MmsValue_getSizeInMemory()/case MMS_ARRAY case MMS_STRUCTURE /self->value.structure.components[i] and program exit.

IedConnection_writeObject(...) won't work

I'm running iec61850_client_example1 and server_example_basic_io.

IedConnection_writeObject(...) always outputs

failed to write simpleIOGenericIO/GGIO1.NamPlt.vendor!

Is it supposed to happen?

I followed the client tutorial but I can't get IedConnection_writeObject(...) to work either. Am I missing something?

sv_subscriber is not working

hi
I use sv_publisher example and it works well - I can capture packets with wireshark/tcpdump, but sv_subscriber receives nothing - the callback handler is not called

[Question] [C#] Connection

Hi,

I have doubts about connection.

1 - When the ConnectionClosedHandler method is called. Do I have to call some IedConnection method? Like (Abort, Release, Close and Dispose)

2 - When an IedConnectionException throws with IedClientError like (IED_ERROR_NOT_CONNECTED, IED_ERROR_CONNECTION_LOST, IED_ERROR_CONNECTION_REJECTED). Do I have to call some IedConnection method? Like (Abort, Release, Close and Dispose)

3 - We have 4 methods to close connection (Abort, Release, Close and Dispose). Can I call all methods? Is there a call order? Like (Release, Abort, Close, Dispose)

I read the documentation (http://libiec61850.com/csharp-api/class_i_e_c61850_1_1_client_1_1_ied_connection.html) about each method. However, I did not understand very well.

How to deal with EntryID of ClientReportControlBlock?

I created a client and wanted to receive reports form an IED(I use IEDSCout as my Simulator).
but everytime i restart my client, I will receviced the whole reports buffered by the server.
I followed the method search from internet which says writing the entryId , but it does not work,
my code is as follows, can you help me?

here are the tissues from http://iec61850.tissue-db.com:
BRCB entryID
EntryID needs clarification

/*
 * client_example1.c
 *
 * This example is intended to be used with server_example3 or server_example_goose.
 */

#include "iec61850_client.h"

#include "stack_config.h"

#include "ied_connection_private.h"

#include "libiec61850_platform_includes.h"
#include <stdlib.h>
#include <stdio.h>

#include "hal_thread.h"
void
ClientReportControlBlock_setEntryId_ex(ClientReportControlBlock self, MmsValue* entryId)
{
    if (self->entryId != NULL) {
        bool r = MmsValue_update(self->entryId, entryId);
        printf("ClientReportControlBlock_setEntryId_ex MmsValue_update:%d\n",r);
    }
    else {
        if (MmsValue_getType(entryId) != MMS_OCTET_STRING) {
            if (DEBUG_IED_CLIENT)
                printf("IED_CLIENT: ClientReportControlBlock_setEntryId invalid argument type\n");
        }
        else
            self->entryId = MmsValue_clone(entryId);
    }
}
void
reportCallbackFunction(void* parameter, ClientReport report)
{
    MmsValue* dataSetValues = ClientReport_getDataSetValues(report);
	char* reportId = ClientReport_getRptId(report);
	uint16_t reportSeqNum = ClientReport_getSeqNum(report);
	printf("reportId %s,reportSeqNum %d\n",reportId,reportSeqNum);
    //printf("received report for %s\n", ClientReport_getRcbReference(report));
	MmsValue * entryId = ClientReport_getEntryId(report);	
	if (entryId) {
		char * buf = (char*)MmsValue_getOctetStringBuffer(entryId);
		printf("Entry ID: %02hhX-%02hhX-%02hhX %02hhX-%02hhX-%02hhX-%02hhX-%02hhX\n", buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7]);
	}
    /*int i;
    for (i = 0; i < 4; i++) {
        ReasonForInclusion reason = ClientReport_getReasonForInclusion(report, i);

        if (reason != IEC61850_REASON_NOT_INCLUDED) {
            printf("  GGIO1.SPCSO%i.stVal: %i (included for reason %i)\n", i,
                    MmsValue_getBoolean(MmsValue_getElement(dataSetValues, i)), reason);
        }
    }*/
}

int main(int argc, char** argv) {

    char* hostname;
    int tcpPort = 102;

    if (argc > 1)
        hostname = argv[1];
    else
        hostname = "192.168.25.25";

    if (argc > 2)
        tcpPort = atoi(argv[2]);

    IedClientError error;

    IedConnection con = IedConnection_create();

    IedConnection_connect(con, &error, hostname, tcpPort);

    if (error == IED_ERROR_OK) {

        IedConnection_getServerDirectory(con, &error, false);

        /* read an analog measurement value from server */
        MmsValue* value = IedConnection_readObject(con, &error, "TEMPLATELD0/LLN0.ActSG.mag.i", IEC61850_FC_MX);

        if (value != NULL) {
            int32_t fval = MmsValue_toInt32(value);
            printf("read int32 value: %d\n", fval);
            MmsValue_delete(value);
        }

        /* write a variable to the server */
        value = MmsValue_newVisibleString("test");
        IedConnection_writeObject(con, &error, "TEMPLATELD0/LPHD1.PhyNam.vendor", IEC61850_FC_DC, value);

        if (error != IED_ERROR_OK)
            printf("failed to write TEMPLATELD0/LPHD1.PhyName.vendor!\n");
        else
        	printf("succeed to write TEMPLATELD0/LPHD1.PhyName.vendor test!\n");

        MmsValue_delete(value);


        /* read data set */
        ClientDataSet clientDataSet = IedConnection_readDataSetValues(con, &error, "TEMPLATELD0/LLN0.dsWarning", NULL);

        if (clientDataSet == NULL)
            printf("failed to read dataset TEMPLATELD0/LLN0.dsWarning\n");
        else
        	printf("succeed to read dataset TEMPLATELD0/LLN0.dsWarning\n");
		
        /* Read RCB values */
        ClientReportControlBlock rcb =
                IedConnection_getRCBValues(con, &error, "TEMPLATELD0/LLN0.BR.brcbAlarm01", NULL);

        bool rptEna = ClientReportControlBlock_getRptEna(rcb);
        printf("RptEna = %i\n", rptEna);
        
		/* setEntryId */
        char buf[8] = {00,00,00,00,00,00,0x00,0x16};
		MmsValue *entryId = MmsValue_newOctetString(8, 8); 
		MmsValue_setOctetString(entryId, (uint8_t*)buf, 8);
		ClientReportControlBlock_setEntryId_ex(rcb, entryId);
		
        /* Install handler for reports */
        IedConnection_installReportHandler(con, "TEMPLATELD0/LLN0.BR.brcbAlarm01", ClientReportControlBlock_getRptId(rcb), reportCallbackFunction, rcb);
        
		/* Set trigger options and enable report */
        ClientReportControlBlock_setTrgOps(rcb, TRG_OPT_DATA_UPDATE | TRG_OPT_INTEGRITY | TRG_OPT_GI);
        ClientReportControlBlock_setRptEna(rcb, true);
        ClientReportControlBlock_setIntgPd(rcb, 30000);
        IedConnection_setRCBValues(con, &error, rcb, RCB_ELEMENT_RPT_ENA | RCB_ELEMENT_TRG_OPS | RCB_ELEMENT_INTG_PD, true);
		
        if (error != IED_ERROR_OK)
            printf("report activation failed (code: %i)\n", error);
        else
        	printf("report activation succeed (code: %i)\n", error);	

        //Thread_sleep(1000);

        /* trigger GI report */
        ClientReportControlBlock_setGI(rcb, true);
        IedConnection_setRCBValues(con, &error, rcb, RCB_ELEMENT_GI, true);

        if (error != IED_ERROR_OK)
            printf("Error triggering a GI report (code: %i)\n", error);

        Thread_sleep(1000000);
		
        /* disable reporting */
        ClientReportControlBlock_setRptEna(rcb, false);
        IedConnection_setRCBValues(con, &error, rcb, RCB_ELEMENT_RPT_ENA, true);

        if (error != IED_ERROR_OK)
            printf("disable reporting failed (code: %i)\n", error);
        else
        	printf("disable reporting succeed (code: %i)\n", error);
		
        ClientDataSet_destroy(clientDataSet);

        ClientReportControlBlock_destroy(rcb);

        close_connection:

        IedConnection_close(con);
    }
    else {
        printf("Failed to connect to %s:%i\n", hostname, tcpPort);
    }

    IedConnection_destroy(con);
}


readObjectInternal() hangs occasionally reading mms value

Noticed that in dotnet project readObjectInternal() hangs (doesn't return) sometimes when reading eg. boolean value from IED. Read is executed but nothing related to client reading boolean value is shown in Wireshark. Then it just waits there forever.

iedconnection_readobject

Timestamp change and goose publishing

Hello,
I have noticed a strange behaviour during the transmission of goose messages (from a server using libiec61850), when only timestamp changes in the referenced dataset. It happens the following (output printed from the receiving server using libiec61850, but wireshark shows the same):

received GOOSE from gcb: MODULO1/LLN0$GO$gcb_Segnalaz
stNum: 8, sqNum: 0, timeToLive: 1500, timestamp: 1496921282.235
{false,0000000000000,20170608105249.383Z},{false,0000000000000,20170608105249.735Z},{false,0000000000000,20170608105249.696Z},{false,0000000000000,20170608105249.545Z},{true,0000000000000,20170608112758.848Z},{false,0000000000000,20170608105249.795Z},{false,0000000000000,20170608105249.236Z},{false,0000000000000,
19700101000000.000Z},{false,0000000000000,20170608105249.151Z},{false,0000000000000,20170608105249.844Z},{false,0000000000000,2017060
8105249.668Z}}

received GOOSE from gcb: MODULO1/LLN0$GO$gcb_Segnalaz
stNum: 8, sqNum: 1, timeToLive: 1500, timestamp: 1496921282.235
{false,0000000000000,20170608105249.383Z},{false,0000000000000,20170608105249.735Z},{false,0000000000000,20170608105249.696Z},{false,0000000000000,20170608105249.545Z},{true,0000000000000,20170608112802.704Z},{false,0000000000000,20170608105249.795Z},{false,0000000000000,20170608105249.236Z},{false,0000000000000,
19700101000000.000Z},{false,0000000000000,20170608112802.755Z},{false,0000000000000,20170608105249.844Z},{false,0000000000000,2017060
8105249.668Z}}

As you can see the stNum remains the same but there are some value change (timestamp change).
The standard IEC 61850-7-2, part 18.2.3 says: "A GOOSE message shall at least be sent each time when a value from one or more members referenced by the data-set change". It does not mention the fact that the data attribute must have dchg or qchg set to true. In my publisher server CID, in fact, the timestamps don't have any trigger option specified.

Some compiler warnings

libiec61850_1.2.0/src/mms/iso_acse/acse.c: In function 'parseAarePdu':
libiec61850_1.2.0/src/mms/iso_acse/acse.c:229:7: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
       if (DEBUG_ACSE)
       ^~
libiec61850_1.2.0/src/mms/iso_acse/acse.c:232:4: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
    bufPos += len;
    ^~~~~~
libiec61850_1.2.0/src/mms/iso_mms/common/mms_value.c: In function 'MmsValue_setElement':
libiec61850_1.2.0/src/mms/iso_mms/common/mms_value.c:1905:5: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
     if ((complexValue->type != MMS_ARRAY) && (complexValue->type != MMS_STRUCTURE))
     ^~
libiec61850_1.2.0/src/mms/iso_mms/common/mms_value.c:1908:2: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
  if ((index < 0) || (index >= complexValue->value.structure.size))
  ^~
libiec61850_1.2.0/src/mms/iso_mms/client/mms_client_named_variable_list.c: In function 'mmsClient_parseDeleteNamedVariableListResponse':
libiec61850_1.2.0/src/mms/iso_mms/client/mms_client_named_variable_list.c:132:7: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
       if (invokeId != NULL)
       ^~
libiec61850_1.2.0/src/mms/iso_mms/client/mms_client_named_variable_list.c:135:4: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
    if (mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.present ==
    ^~
libiec61850_1.2.0/src/mms/iso_mms/client/mms_client_named_variable_list.c: In function 'mmsClient_parseGetNamedVariableListAttributesResponse':
libiec61850_1.2.0/src/mms/iso_mms/client/mms_client_named_variable_list.c:269:7: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
       if (invokeId != NULL)
       ^~
libiec61850_1.2.0/src/mms/iso_mms/client/mms_client_named_variable_list.c:272:4: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
    if (mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.present ==
    ^~
libiec61850_1.2.0/src/mms/iso_mms/client/mms_client_named_variable_list.c: In function 'mmsClient_parseDefineNamedVariableResponse':
libiec61850_1.2.0/src/mms/iso_mms/client/mms_client_named_variable_list.c:439:7: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
       if (invokeId != NULL)
       ^~
libiec61850_1.2.0/src/mms/iso_mms/client/mms_client_named_variable_list.c:442:4: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
    if (mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.present ==
    ^~
libiec61850_1.2.0/src/mms/iso_mms/client/mms_client_connection.c: In function 'mmsIsoCallback':
ibiec61850_1.2.0/src/mms/iso_mms/client/mms_client_connection.c:985:25: warning: 'invokeId' may be used uninitialized in this function [-Wmaybe-uninitialized]
                         mmsClient_handleFileOpenRequest(self, buf, bufPos, bufPos + length, invokeId, response);
                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
libiec61850_1.2.0/src/mms/iso_mms/client/mms_client_get_var_access.c: In function 'mmsClient_parseGetVariableAccessAttributesResponse':
libiec61850_1.2.0/src/mms/iso_mms/client/mms_client_get_var_access.c:144:6: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
      if (invokeId != NULL)
      ^~
libiec61850_1.2.0/src/mms/iso_mms/client/mms_client_get_var_access.c:147:3: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
   if (mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.present ==
   ^~
libiec61850_1.2.0/src/mms/iso_mms/client/mms_client_read.c: In function 'mmsClient_parseReadResponse':
libiec61850_1.2.0/src/mms/iso_mms/client/mms_client_read.c:262:6: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
      if (invokeId != NULL)
      ^~
libiec61850_1.2.0/src/mms/iso_mms/client/mms_client_read.c:265:3: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
   if (mmsPdu->choice.confirmedResponsePdu.confirmedServiceResponse.present == ConfirmedServiceResponse_PR_read) {
   ^~
libiec61850_1.2.0/src/mms/iso_mms/server/mms_get_namelist_service.c: In function 'mmsServer_handleGetNameListRequest':
libiec61850_1.2.0/src/mms/iso_mms/server/mms_get_namelist_service.c:531:7: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
       if (DEBUG_MMS_SERVER)
       ^~
libiec61850_1.2.0/src/mms/iso_mms/server/mms_get_namelist_service.c:534:4: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
    LinkedList nameList = getNameListDomainSpecific(connection, domainSpecificName);
    ^~~~~~~~~~
libiec61850_1.2.0/src/mms/iso_mms/server/mms_server_connection.c: In function 'MmsServerConnection_parseMessage':
libiec61850_1.2.0/src/mms/iso_mms/server/mms_server_connection.c:555:6: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
      if (DEBUG_MMS_SERVER)
      ^~
libiec61850_1.2.0/src/mms/iso_mms/server/mms_server_connection.c:557:3: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
   break;
   ^~~~~
libiec61850_1.2.0/src/iec61850/client/client_control.c: In function 'ControlObjectClient_create':
libiec61850_1.2.0/src/iec61850/client/client_control.c:165:13: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
             if (MmsVariableSpecification_getType(ctlVal) == MMS_STRUCTURE)
             ^~
libiec61850_1.2.0/src/iec61850/client/client_control.c:168:7: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
       MmsVariableSpecification* operTm = MmsVariableSpecification_getNamedVariableRecursive(oper, "operTm");
       ^~~~~~~~~~~~~~~~~~~~~~~~
libiec61850_1.2.0/src/iec61850/client/client_control.c: In function 'ControlObjectClient_operate':
libiec61850_1.2.0/src/iec61850/client/client_control.c:352:5: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
     if (self->hasCtlNum)
     ^~
libiec61850_1.2.0/src/iec61850/client/client_control.c:355:2: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
  operParameters = MmsValue_createEmptyStructure(operElementCount);
  ^~~~~~~~~~~~~~
libiec61850_1.2.0/src/goose/goose_receiver.c: In function 'GooseReceiver_tick':
libiec61850_1.2.0/src/goose/goose_receiver.c:598:41: warning: 'confRev' may be used uninitialized in this function [-Wmaybe-uninitialized]
             matchingSubscriber->confRev = confRev;
             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~
libiec61850_1.2.0/src/goose/goose_receiver.c:463:14: note: 'confRev' was declared here
     uint32_t confRev;
              ^~~~~~~

Embedded environment, multi-client connection, system deadlock.

Problem description:
I used ieclib61850 1.2.1 to run the server in an embedded Linux environment (arm bigendian). The first client can connect normally. Connect to the second client and the system will deadlock (the console will not respond). At this point, disconnect the first client, the second client will be immediately connected, and the system will return to normal.

Configuration:
Stack_config.h adds a macro definition of the bigendian:
# define PLATFORM_IS_BIGENDIAN 1

The rest are default and unchanged. The key parts are as follows:

/* Maximum MMS PDU SIZE - default is 65000 */
# define CONFIG_MMS_MAXIMUM_PDU_SIZE 120000

/ *
* Enable single threaded mode
*
* 1 ==> server runs in single threaded mode (a single thread for the server and all client connections)
* 0 => server runs in multi-threaded mode (one thread for each connection and)
* one server background thread)
* /
# define CONFIG_MMS_SINGLE_THREADED 0

/ *
* Optimize stack for threadless oper-don't semt use aphores
*
* WARNING: If set to 1 normal single- and multi-threaded server are no longer working!
* /
# define CONFIG_MMS_THREADLESS_STACK 0

/* number of concurrent MMS client connections the server accepts, -1 for no limit */
# define CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS 5

/* activate TCP keep alive mechanism. 1-> activate */
# define CONFIG_ACTIVATE_TCP_KEEPALIVE 1

/* time (in s) between last message and first keepalive message */
# define CONFIG_TCP_KEEPALIVE_IDLE 5

After that, we kept alive messages if no ack received */
# define CONFIG_TCP_KEEPALIVE_INTERVAL 2

/* number of not missing keepalive responses until socket is considered dead */
# define CONFIG_TCP_KEEPALIVE_CNT 2

/* maximum COTP (ISO 8073) TPDU size-valid range is 1024-8192 */
# define CONFIG_COTP_MAX_TPDU_SIZE 8192

/* timeout while reading from TCP stream in ms */
# define CONFIG_TCP_READ_TIMEOUT_MS 1000

/* Ethernet interface ID for GOOSE and SV */
# define CONFIG_ETHERNET_INTERFACE_ID "eth0"

Cause analysis:
I compared the debug print for the first and second client connections and found that the Socket_read function always returns 0 for the second client connection. That is, "recv(self->fd, buf, size, MSG_DONTWAIT)" always returns -1, and errno = EAGAIN. Causes the CotpConnection_readToTpktBuffer() function to return TPKT_WAITING all the time, system deadlock.
This is not the case with the previous version of 0.7.6. A comparison of socket_linux.c shows that version 0.7.6 USES "read(self->fd, buf, size)" here.
So, when I change the recv to read, I can connect multiple clients. In addition, I tried to change this to block mode "recv(self->fd, buf, size, MSG_WAITALL)", which also solves this problem.

The first time I mentioned a bug on github, if there is anything wrong, please give me more advice. ^_^

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.