The libiec61850 source code distribution also contains a clinet/server API for C#/.NET. The C# library should run on .NET and Mono (on Linux and Mac OS X 10.9). Please also refer to the examples provided with the C# API.
The C# code is provided with solution and project files that can be either used with Visual Studio or MonoDevelop (Xamarin Studio).
Build the API and examples on Mono for Linux
To build the tools you can either use MonoDevelop or the xbuild command line tool.
To build on the command line just type:
cd dotnet
xbuild dotnet.sln
On a Windows system you can use Visual Studio or the msbuild command line tool respectively.
The C# API requires the C/native library to be built as a native shared library (.so file or DLL).
The runtime (.NET or Mono) has to be able to find the shared library/DLL. This can be done by copying the library to the respective system directory:
On Linux or Mac OS X this is usually /usr/lib
.
On Windows this is the C:/Windows/System32
. (Depending on the version of Windows this directory may differ).
Linux: libiec61850.so
==> /usr/lib
Mac OS X: libiec61850.dylib
==> /usr/lib
Windows: iec61850.dll
==> C:/Windows/System32
A simple example application
using System;
using IEC61850.Client;
using IEC61850.Common;
namespace test1
{
class MainClass
{
public static void Main (string[] args)
{
var connection = new IedConnection ();
connection.Connect ("localhost");
bool stVal = connection.ReadBooleanValue ("simpleIOGenericIO/GGIO1.SPCSO1.stVal",
FunctionalConstraint.ST);
UInt64 t = connection.ReadTimestampValue("simpleIOGenericIO/GGIO1.SPCSO1.t",
FunctionalConstraint.ST);
DateTimeOffset timestamp = MmsValue.MsTimeToDateTimeOffset (t);
Console.WriteLine ("SPCSO1.stVal: " + stVal.ToString ());
Console.WriteLine ("SPCSO1.t: " + timestamp.ToString ());
var spcso1 = connection.CreateControlObject ("simpleIOGenericIO/GGIO1.SPCSO1");
if (stVal)
spcso1.Operate (false);
else
spcso1.Operate (true);
connection.Abort ();
}
}
}
The C# API is designed to be as close as possible to the C API without compromising the C# coding style. Main differences are the usage of real instance methods instead of static functions and exceptions instead of call by reference error variables.
Are there any plans to implement GOOSE publishing in the C# API?
GOOSE publishing may be integrated together with the server side API. But there is not yet a schedule when this will be done.
Hello,
I’m having trouble reading a DPI value. According to the C#/.Net API Ref. manual enum types should be readed with IedConnection.ReadIntegerValue() but this throws exception “Result is not of type integer (MMS_INTEGER)”. I tried getting the type with IedConnection.GetVariableSpecification() and the result is “MMS_BIT_STRING”. Then I tried IedConnection.ReadStringValue() but it throws exception “Result is not of type string”. I’ve also tried IedConnection.ReadValue() but then i get “unknown” value. How should I get the value of a DPI?
I have seen that the readout of DPS (double point status) values is not yet supported by the C# API. The reason is that stVal of DPS is specified as a “CODED ENUM” that is mapped to an MMS bit string variable. This is different to “ENUMERATED” variables that are mapped to MMS integer variables. I will add support for this with the next release.
As a workaround you can add a method like bellow to the IedConnection class in IEC61850ClientAPI.cs:
It is working! Thank you!
I didn’t manage to setup the reporting with C# API. What should be the second parameter of the function ReportControlBlock.InstallReportHandler (ReportHandler reportHandler, object parameter)? I am getting “Access Violation exception” when calling IedConnection_installReportHandler() in the body of InstallReportHandler().
Did you had a look at the provided example (ReportingExample.cs)? Here you can see how to properly set the report handler. The second parameter is just passed to the handler. You can also provide “null” if you don’t need this.
I’m trying with simple example, but I’m facing with this terminating error:
“System.EntryPointNotFoundException: Unable to find an entry point named ‘IedConnection_create’ in DLL ‘iec61850’.
at IEC61850.Client.IedConnection.IedConnection_create()
at IEC61850.Client.IedConnection..ctor() in d:\…\libiec61850-0.8.0\libiec61850-0.8.0\dotnet\IEC61850forCSharp\IEC61850ClientAPI.cs:line 161
at datasets.DataSetExample.Main(String[] args) in d:\….\libiec61850-0.8.0\libiec61850-0.8.0\dotnet\datasets\DataSetExample.cs:line 13”
This exception is thrown when the native library iec61850.dll (or libiec61850.so on linux) is not found. You have to build the native library first and put it in a folder where the OS can find it. On Windows this is usually “C:\Windows\System32, on linux “/usr/lib”.
hello, Can you tell me did you solve the problem already? I have meet this problem too, and i do not know how to resolve it, can you tell me?
Hi All,
I have downloaded the latest version of the application i.e libiec61850-0.8.3.tgz, went to the dotnet folder after extracting, opened the application in VS2013, build project”IEC61850forCSharp” with assembly name as “iec61850” and pasted the dll in System32 folder, started example1 project, i get following error
Unable to find an entry point named ‘IedConnection_create’ in DLL ‘iec61850’.
please help, thanks in advance.
You have to build and install the native library (iec61850.dll) also. See https://libiec61850.net/libiec61850/documentation/building-the-library/
Thanks for the reply, i went through the document and build the library, now i’m able to connect.
Hi,
Have you tested the example of C# API as shown on this web page? When I copy the codes into my VS2012 C# console application, the compiling result says “iec 61850.dll” is not found. How did you solve the problem? I have built the library and copied the “iec61850.dll” into win32/system directory.
Hello, the new version 0.8.3 can’t connect to real ABB protection relays. The old version 0.8.2 is working. The new version fails to connect to relay at MmsConnection_connect().
This is most probably due to the changes in the T-selector handling. Version 0.8.3 uses the value 0 instead of 1 that has been used before. It seems that many devices cannot deal with this value. You can try to change the value by API.
Hi Michael,
I seem to be having trouble reading single byte Boolean values. I’ve tried reading with .ReadBooleanValue and with .ReadDataSetValues. With wireshark I can see the response from my ied is (in hex) 83 01 00 (Boolean value, 1 byte, value = false), however both these functions are always returning true.
Hi, this is a known problem. It is due to the different handling of “bool” type in GCC(C) and VS(C++). It is fixed in the upcoming version (next week). The decorators for native functions with bool return value have to be changed to “[return: MarshalAs(UnmanagedType.I1)]”. If you need the fixed version now you can send me an email.
Hello, congratulations for such a good job with this library.
My question is if you are planning to release a C# api for the server part?
Thanks,
Yes I am planning that. But it is not of high priority at the moment. So don’t expect anything useful in the next few months.
Hi, thanks for your answer.
I will try that myself. If I am lucky, I will give you some feedback about this.
Thanks!
I am facing problem with Enhanced type commands in Windows form application.
The following code causes error when executed 2nd time in a row:
private void selectCommandToolStripMenuItem_Click(object sender, EventArgs e)
{
/* direct control with enhanced security */
string objectReference = “simpleIOGenericIO/GGIO1.SPCSO9″;
Program.control = con.CreateControlObject(objectReference);
controlModel = Program.control.GetControlModel();
this.IED_ListBox.Items.Add(objectReference + ” has control model ” + controlModel.ToString());
Program.control.SetCommandTerminationHandler(commandTerminationHandler, null);
Program.control.Operate(true);
Thread.Sleep(1000);
this.IED_ListBox.SelectedIndex = this.IED_ListBox.Items.Count – 1;
}
Following error occurs:
Managed Debugging Assistant ‘CallbackOnCollectedDelegate’ has detected a problem in
‘G:\Projects\libiec61850-0.8.6\dotnet\Test_Application\bin\Debug\Test_Application.exe’.
Additional Information: A callback was made on a garbage collected delegate of type
‘iec61850dotnet!IEC61850.Client.ControlObject+InternalCommandTerminationHandler::Invoke’.
This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called.
Can you please help me out with this.
After few hours of debugging, I found a workaround by changing the dotnet “Control.cs” in the following way:
private InternalCommandTerminationHandler intCommandTerminationHandler;
//The declaration here prevented Garbage Collection
internal ControlObject (string objectReference, IntPtr connection, IedConnection iedConnection)
{
this.iedConnection = iedConnection;
this.controlObject = ControlObjectClient_create(objectReference, connection);
if (this.controlObject == System.IntPtr.Zero)
throw new IedConnectionException(“Control object not found”, 0);
intCommandTerminationHandler = new InternalCommandTerminationHandler(MyCommandTerminationHandler);
ControlObjectClient_setCommandTerminationHandler(controlObject, intCommandTerminationHandler, controlObject);
}
Is this the right way?
Thanks
Thanks! For me it looks like the correct solution.
In C#, I found when a received MmsValue instance of type MmsType.MMS_STRUCTURE contains q(Quality), the GetType method returns MMS_BIT_STRING of q and I print the value using “Console.WriteLine(q);” it gives me nothing! Is this correct?What‘s the solution if I want to print out the q(Quality)?
IEC61850.Common.MmsValue
MmsValue.cs
warning CS0659
Not overriding GetHashcode when overriding Equals
Sometimes developers forget to override GetHashCode even after the overriding
equals. When we equate two objects, the .NET first calls GetHashCode of each of
the objects before calling the Equals method. So if the hash code of two objects
does not match, they will never be considered as equal. Hence, you need to override
GetHashCode of both the types and return the same value for two objects.
Hi All
I have downloaded the latest version of the application i.e libiec61850-0.9.2.1.tgz, and tried to use CMAKE to build it. But I am getting several errors.
CMAKE Message
****************************************************************
The C compiler identification is unknown
The CXX compiler identification is unknown
CMake Error at CMakeLists.txt:10 (project):
No CMAKE_C_COMPILER could be found.
CMake Error at CMakeLists.txt:10 (project):
No CMAKE_CXX_COMPILER could be found.
Configuring incomplete, errors occurred!
See also “C:/Users/insashe3/Downloads/IEC61850 source code/CMakeFiles/CMakeOutput.log”.
See also “C:/Users/insashe3/Downloads/IEC61850 source code/CMakeFiles/CMakeError.log”.
*********************************************************************************
please help, thanks in advance.
Hello,
Do you know which is the maximum reading of variables per dataset?
thanks.
Hello,
How create server with C# to transfer files on client ?
Or is it only possible for server with C?
It works exactly the same way as with a server written in C. With the standard configuration you only need a folder “vmd-filestore” containing the files you want to serve in the directory where the server is started.
Hi i have some problem with server in libiec61850.
Every time than i try to write something it response me something like
30
3
programm for exaple
DataAttribute GGIO1_SPCSO1_oper_ctlVal = (DataAttribute)iedModel.GetModelNodeByShortObjectReference(“GenericIO/GGIO1.SPCSO1.Oper.ctlVal”);
IedServer iedServer = new IedServer (iedModel);
iedServer.SetWriteAccessPolicy(FunctionalConstraint.ALL, AccessPolicy.ACCESS_POLICY_ALLOW);
if (GGIO1_SPCSO1_oper_ctlVal!= null)
iedServer.HandleWriteAccess(GGIO1_SPCSO1_oper_ctlVal,delegate(DataAttribute attr,MmsValue val,ClientConnection con,object param) {
iedServer.UnlockDataModel();
iedServer.UpdateBooleanAttributeValue(attr,val.GetBoolean());
iedServer.LockDataModel();
return MmsDataAccessError.SUCCESS;
},null);
iedServer.Start (102);
Console.WriteLine (“Server started”);
GC.Collect ();
while (running) {
Thread.Sleep (100);
}
iedServer.Stop ();
Console.WriteLine (“Server stopped”);
iedServer.Destroy ();
What am I doing wrong?
Hi,
The line
iedServer.SetWriteAccessPolicy(FunctionalConstraint.ALL, AccessPolicy.ACCESS_POLICY_ALLOW);
has no effect. You have to specify the FC (it has to be one of DC, CF, SP, SV, SE).
You cannot handle writing of controls this way. For controls you have to use a ControlHandler.
Excuse me Michael !
How i can get a microseconds from timestamp of signal ?
What signal do you mean? Can you give example?
From C# can I dynamically create an IedModel or is the only option to load it from a .cfg file using ConfigFileParser.CreateModelFromConfigFile ?
You can dynamically create an IedModel with C# by using the API. Unfortunately there is no example available yet. But doing it looks like:
IedModel iedModel = new IedModel("MYIED1");
LogicalDevice ld1 = new LogicalDevice("LD1", iedModel);
...
Michael, Yes that seems much easier than using the .cfg files! I have a prototype up and running as a Windows service and it seems to be working well. What test client do you use? I downloaded a 30 day demo of Omicron’s IEDScout which seems quite good but rather expensive!
If want to use an open-source client I can recommend IEDExplorer (https://sourceforge.net/projects/iedexplorer/). It is not as complete as the IEDScout but it is quite useful and evolving rapidly.
hi Michael , is it possible to use sampled value subscriber with c# api? i want sv subscriber in c# language thank you
Download 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 if the file is in a sub-directory.
How do I pass the full path name to GetFile() method in order to download these files?