|
|
|
@ -21,25 +21,20 @@
|
|
|
|
|
* See COPYING file for the complete license text.
|
|
|
|
|
*/
|
|
|
|
|
using System;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Collections;
|
|
|
|
|
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using IEC61850.Common;
|
|
|
|
|
using IEC61850.TLS;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// IEC 61850 API for the libiec61850 .NET wrapper library
|
|
|
|
|
/// </summary>
|
|
|
|
|
// IEC 61850 API for the libiec61850 .NET wrapper library
|
|
|
|
|
namespace IEC61850
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// IEC 61850 server API.
|
|
|
|
|
/// </summary>
|
|
|
|
|
// IEC 61850 server API.
|
|
|
|
|
namespace Server
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Config file parser.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class ConfigFileParser
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
@ -69,6 +64,9 @@ namespace IEC61850
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Representation of the IED server data model
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class IedModel
|
|
|
|
|
{
|
|
|
|
|
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
|
|
|
|
@ -93,6 +91,10 @@ namespace IEC61850
|
|
|
|
|
this.self = self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Initializes a new instance of the <see cref="T:IEC61850.Server.IedModel"/> class.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="name">IED name</param>
|
|
|
|
|
public IedModel(string name)
|
|
|
|
|
{
|
|
|
|
|
self = IedModel_create(name);
|
|
|
|
@ -159,8 +161,6 @@ namespace IEC61850
|
|
|
|
|
|
|
|
|
|
return getModelNodeFromNodeRef (nodeRef);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class LogicalDevice : ModelNode
|
|
|
|
@ -483,8 +483,6 @@ namespace IEC61850
|
|
|
|
|
|
|
|
|
|
public class ClientConnection
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
|
|
|
|
|
static extern IntPtr ClientConnection_getPeerAddress(IntPtr self);
|
|
|
|
|
|
|
|
|
@ -505,6 +503,99 @@ namespace IEC61850
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Represents additional context information of the control action that caused the callback invokation
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class ControlAction
|
|
|
|
|
{
|
|
|
|
|
[DllImport ("iec61850", CallingConvention = CallingConvention.Cdecl)]
|
|
|
|
|
static extern void ControlAction_setAddCause (IntPtr self, int addCause);
|
|
|
|
|
|
|
|
|
|
[DllImport ("iec61850", CallingConvention = CallingConvention.Cdecl)]
|
|
|
|
|
static extern int ControlAction_getOrCat (IntPtr self);
|
|
|
|
|
|
|
|
|
|
[DllImport ("iec61850", CallingConvention = CallingConvention.Cdecl)]
|
|
|
|
|
static extern IntPtr ControlAction_getOrIdent (IntPtr self, ref int size);
|
|
|
|
|
|
|
|
|
|
[DllImport ("iec61850", CallingConvention = CallingConvention.Cdecl)]
|
|
|
|
|
static extern IntPtr ControlAction_getClientConnection (IntPtr self);
|
|
|
|
|
|
|
|
|
|
private IntPtr self;
|
|
|
|
|
private IedServer.ControlHandlerInfo info;
|
|
|
|
|
private IedServer iedServer;
|
|
|
|
|
|
|
|
|
|
internal ControlAction (IntPtr self, IedServer.ControlHandlerInfo info, IedServer iedServer)
|
|
|
|
|
{
|
|
|
|
|
this.self = self;
|
|
|
|
|
this.info = info;
|
|
|
|
|
this.iedServer = iedServer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Sets the add cause for the next command termination or application error message
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="addCause">the additional cause code</param>
|
|
|
|
|
public void SetAddCause (ControlAddCause addCause)
|
|
|
|
|
{
|
|
|
|
|
ControlAction_setAddCause (self, (int)addCause);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the originator category provided by the client
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>The or cat.</returns>
|
|
|
|
|
public OrCat GetOrCat ()
|
|
|
|
|
{
|
|
|
|
|
return (OrCat)ControlAction_getOrCat (self);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get the originator identifier provided by the client
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>The or ident.</returns>
|
|
|
|
|
public byte [] GetOrIdent ()
|
|
|
|
|
{
|
|
|
|
|
int size = 0;
|
|
|
|
|
|
|
|
|
|
IntPtr orIdentPtr = ControlAction_getOrIdent (self, ref size);
|
|
|
|
|
|
|
|
|
|
if (orIdentPtr == IntPtr.Zero)
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
byte [] orIdent = new byte [size];
|
|
|
|
|
|
|
|
|
|
Marshal.Copy (orIdentPtr, orIdent, 0, size);
|
|
|
|
|
|
|
|
|
|
return orIdent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the control object that is subject to this action
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>the controllable data object instance</returns>
|
|
|
|
|
public DataObject GetControlObject ()
|
|
|
|
|
{
|
|
|
|
|
return info.controlObject;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the client object associated with the client that caused the control action
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>The client connection.</returns>
|
|
|
|
|
public ClientConnection GetClientConnection ()
|
|
|
|
|
{
|
|
|
|
|
ClientConnection con = null;
|
|
|
|
|
|
|
|
|
|
IntPtr conPtr = ControlAction_getClientConnection (self);
|
|
|
|
|
|
|
|
|
|
if (conPtr != IntPtr.Zero) {
|
|
|
|
|
iedServer.clientConnections.TryGetValue (conPtr, out con);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return con;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public delegate MmsDataAccessError WriteAccessHandler (DataAttribute dataAttr, MmsValue value,
|
|
|
|
|
ClientConnection connection, object parameter);
|
|
|
|
|
|
|
|
|
@ -523,9 +614,9 @@ namespace IEC61850
|
|
|
|
|
WAITING = 2
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public delegate ControlHandlerResult ControlWaitForExecutionHandler (DataObject controlObject, object parameter, MmsValue ctlVal, bool test, bool synchroCheck);
|
|
|
|
|
public delegate ControlHandlerResult ControlWaitForExecutionHandler (ControlAction action, object parameter, MmsValue ctlVal, bool test, bool synchroCheck);
|
|
|
|
|
|
|
|
|
|
public delegate ControlHandlerResult ControlHandler (DataObject controlObject, object parameter, MmsValue ctlVal, bool test);
|
|
|
|
|
public delegate ControlHandlerResult ControlHandler (ControlAction action, object parameter, MmsValue ctlVal, bool test);
|
|
|
|
|
|
|
|
|
|
public enum CheckHandlerResult {
|
|
|
|
|
/// <summary>
|
|
|
|
@ -550,8 +641,7 @@ namespace IEC61850
|
|
|
|
|
OBJECT_UNDEFINED = 4
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public delegate CheckHandlerResult CheckHandler (DataObject controlObject, object parameter, MmsValue ctlVal, bool test, bool interlockCheck,
|
|
|
|
|
ClientConnection connection);
|
|
|
|
|
public delegate CheckHandlerResult CheckHandler (ControlAction action, object parameter, MmsValue ctlVal, bool test, bool interlockCheck);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// This class acts as the entry point for the IEC 61850 client API. It represents a single
|
|
|
|
@ -615,13 +705,13 @@ namespace IEC61850
|
|
|
|
|
static extern IntPtr IedServer_getAttributeValue(IntPtr self, IntPtr dataAttribute);
|
|
|
|
|
|
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
|
|
|
private delegate int InternalControlPerformCheckHandler (IntPtr parameter, IntPtr ctlVal, [MarshalAs(UnmanagedType.I1)] bool test, [MarshalAs(UnmanagedType.I1)] bool interlockCheck, IntPtr connection);
|
|
|
|
|
private delegate int InternalControlPerformCheckHandler (IntPtr action, IntPtr parameter, IntPtr ctlVal, [MarshalAs(UnmanagedType.I1)] bool test, [MarshalAs(UnmanagedType.I1)] bool interlockCheck);
|
|
|
|
|
|
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
|
|
|
private delegate int InternalControlWaitForExecutionHandler (IntPtr parameter, IntPtr ctlVal, [MarshalAs(UnmanagedType.I1)] bool test, [MarshalAs(UnmanagedType.I1)] bool synchoCheck);
|
|
|
|
|
private delegate int InternalControlWaitForExecutionHandler (IntPtr action, IntPtr parameter, IntPtr ctlVal, [MarshalAs(UnmanagedType.I1)] bool test, [MarshalAs(UnmanagedType.I1)] bool synchoCheck);
|
|
|
|
|
|
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
|
|
|
private delegate int InternalControlHandler (IntPtr parameter, IntPtr ctlVal, [MarshalAs(UnmanagedType.I1)] bool test);
|
|
|
|
|
private delegate int InternalControlHandler (IntPtr action, IntPtr parameter, IntPtr ctlVal, [MarshalAs(UnmanagedType.I1)] bool test);
|
|
|
|
|
|
|
|
|
|
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
|
|
|
|
|
static extern void IedServer_setWaitForExecutionHandler(IntPtr self, IntPtr node, InternalControlWaitForExecutionHandler handler, IntPtr parameter);
|
|
|
|
@ -665,7 +755,7 @@ namespace IEC61850
|
|
|
|
|
private InternalControlPerformCheckHandler internalControlPerformCheckHandlerRef = null;
|
|
|
|
|
private InternalControlWaitForExecutionHandler internalControlWaitForExecutionHandlerRef = null;
|
|
|
|
|
|
|
|
|
|
private class ControlHandlerInfo {
|
|
|
|
|
internal class ControlHandlerInfo {
|
|
|
|
|
public DataObject controlObject = null;
|
|
|
|
|
public GCHandle handle;
|
|
|
|
|
|
|
|
|
@ -691,42 +781,46 @@ namespace IEC61850
|
|
|
|
|
|
|
|
|
|
private Dictionary<DataObject, ControlHandlerInfo> controlHandlers = new Dictionary<DataObject, ControlHandlerInfo> ();
|
|
|
|
|
|
|
|
|
|
int internalControlHandler (IntPtr parameter, IntPtr ctlVal, bool test)
|
|
|
|
|
int InternalControlHandlerImpl (IntPtr action, IntPtr parameter, IntPtr ctlVal, bool test)
|
|
|
|
|
{
|
|
|
|
|
GCHandle handle = GCHandle.FromIntPtr (parameter);
|
|
|
|
|
|
|
|
|
|
ControlHandlerInfo info = (ControlHandlerInfo)handle.Target;
|
|
|
|
|
|
|
|
|
|
ControlAction controlAction = new ControlAction (action, info, this);
|
|
|
|
|
|
|
|
|
|
if (info != null & info.controlHandler != null)
|
|
|
|
|
return (int)info.controlHandler (info.controlObject, info.controlHandlerParameter, new MmsValue (ctlVal), test);
|
|
|
|
|
return (int)info.controlHandler (controlAction, info.controlHandlerParameter, new MmsValue (ctlVal), test);
|
|
|
|
|
else
|
|
|
|
|
return (int)ControlHandlerResult.FAILED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int internalCheckHandler(IntPtr parameter, IntPtr ctlVal, bool test, bool interlockCheck, IntPtr connection)
|
|
|
|
|
int InternalCheckHandlerImpl(IntPtr action, IntPtr parameter, IntPtr ctlVal, bool test, bool interlockCheck)
|
|
|
|
|
{
|
|
|
|
|
GCHandle handle = GCHandle.FromIntPtr (parameter);
|
|
|
|
|
|
|
|
|
|
ControlHandlerInfo info = (ControlHandlerInfo)handle.Target;
|
|
|
|
|
|
|
|
|
|
if (info != null & info.checkHandler != null) {
|
|
|
|
|
ClientConnection con = null;
|
|
|
|
|
|
|
|
|
|
clientConnections.TryGetValue (connection, out con);
|
|
|
|
|
ControlAction controlAction = new ControlAction (action, info, this);
|
|
|
|
|
|
|
|
|
|
return (int)info.checkHandler (info.controlObject, info.checkHandlerParameter, new MmsValue (ctlVal), test, interlockCheck, con);
|
|
|
|
|
return (int)info.checkHandler (controlAction, info.checkHandlerParameter, new MmsValue (ctlVal), test, interlockCheck);
|
|
|
|
|
} else
|
|
|
|
|
return (int)CheckHandlerResult.OBJECT_UNDEFINED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int internalControlWaitForExecutionHandler (IntPtr parameter, IntPtr ctlVal, bool test, bool synchoCheck)
|
|
|
|
|
int InternalControlWaitForExecutionHandlerImpl (IntPtr action, IntPtr parameter, IntPtr ctlVal, bool test, bool synchoCheck)
|
|
|
|
|
{
|
|
|
|
|
GCHandle handle = GCHandle.FromIntPtr (parameter);
|
|
|
|
|
|
|
|
|
|
ControlHandlerInfo info = (ControlHandlerInfo)handle.Target;
|
|
|
|
|
|
|
|
|
|
if (info != null & info.waitForExecHandler != null) {
|
|
|
|
|
return (int)info.waitForExecHandler (info.controlObject, info.waitForExecHandlerParameter, new MmsValue (ctlVal), test, synchoCheck);
|
|
|
|
|
|
|
|
|
|
ControlAction controlAction = new ControlAction (action, info, this);
|
|
|
|
|
|
|
|
|
|
return (int)info.waitForExecHandler (controlAction, info.waitForExecHandlerParameter, new MmsValue (ctlVal), test, synchoCheck);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return (int)ControlHandlerResult.FAILED;
|
|
|
|
@ -745,7 +839,7 @@ namespace IEC61850
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int writeAccessHandler (IntPtr dataAttribute, IntPtr value, IntPtr connection, IntPtr parameter)
|
|
|
|
|
int WriteAccessHandlerImpl (IntPtr dataAttribute, IntPtr value, IntPtr connection, IntPtr parameter)
|
|
|
|
|
{
|
|
|
|
|
//object info = writeAccessHandlers.Item [dataAttribute];
|
|
|
|
|
WriteAccessHandlerInfo info;
|
|
|
|
@ -761,7 +855,7 @@ namespace IEC61850
|
|
|
|
|
|
|
|
|
|
private Dictionary<IntPtr, WriteAccessHandlerInfo> writeAccessHandlers = new Dictionary<IntPtr, WriteAccessHandlerInfo> ();
|
|
|
|
|
|
|
|
|
|
private void connectionIndicationHandler (IntPtr iedServer, IntPtr clientConnection, bool connected, IntPtr parameter)
|
|
|
|
|
private void ConnectionIndicationHandlerImpl (IntPtr iedServer, IntPtr clientConnection, bool connected, IntPtr parameter)
|
|
|
|
|
{
|
|
|
|
|
if (connected == false) {
|
|
|
|
|
ClientConnection con = null;
|
|
|
|
@ -785,9 +879,7 @@ namespace IEC61850
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Dictionary<IntPtr, ClientConnection> clientConnections = new Dictionary<IntPtr, ClientConnection> ();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
internal Dictionary<IntPtr, ClientConnection> clientConnections = new Dictionary<IntPtr, ClientConnection> ();
|
|
|
|
|
|
|
|
|
|
public IedServer(IedModel iedModel, IedServerConfig config = null)
|
|
|
|
|
{
|
|
|
|
@ -849,7 +941,7 @@ namespace IEC61850
|
|
|
|
|
public void Start(int tcpPort)
|
|
|
|
|
{
|
|
|
|
|
if (internalConnectionHandler == null)
|
|
|
|
|
internalConnectionHandler = new InternalConnectionHandler (connectionIndicationHandler);
|
|
|
|
|
internalConnectionHandler = new InternalConnectionHandler (ConnectionIndicationHandlerImpl);
|
|
|
|
|
|
|
|
|
|
IedServer_setConnectionIndicationHandler (self, internalConnectionHandler, IntPtr.Zero);
|
|
|
|
|
|
|
|
|
@ -910,7 +1002,7 @@ namespace IEC61850
|
|
|
|
|
info.controlHandlerParameter = parameter;
|
|
|
|
|
|
|
|
|
|
if (internalControlHandlerRef == null)
|
|
|
|
|
internalControlHandlerRef = new InternalControlHandler (internalControlHandler);
|
|
|
|
|
internalControlHandlerRef = new InternalControlHandler (InternalControlHandlerImpl);
|
|
|
|
|
|
|
|
|
|
IedServer_setControlHandler(self, controlObject.self, internalControlHandlerRef, GCHandle.ToIntPtr(info.handle));
|
|
|
|
|
}
|
|
|
|
@ -923,7 +1015,7 @@ namespace IEC61850
|
|
|
|
|
info.checkHandlerParameter = parameter;
|
|
|
|
|
|
|
|
|
|
if (internalControlPerformCheckHandlerRef == null)
|
|
|
|
|
internalControlPerformCheckHandlerRef = new InternalControlPerformCheckHandler (internalCheckHandler);
|
|
|
|
|
internalControlPerformCheckHandlerRef = new InternalControlPerformCheckHandler (InternalCheckHandlerImpl);
|
|
|
|
|
|
|
|
|
|
IedServer_setPerformCheckHandler(self, controlObject.self, internalControlPerformCheckHandlerRef, GCHandle.ToIntPtr(info.handle));
|
|
|
|
|
}
|
|
|
|
@ -936,7 +1028,7 @@ namespace IEC61850
|
|
|
|
|
info.waitForExecHandlerParameter = parameter;
|
|
|
|
|
|
|
|
|
|
if (internalControlWaitForExecutionHandlerRef == null)
|
|
|
|
|
internalControlWaitForExecutionHandlerRef = new InternalControlWaitForExecutionHandler (internalControlWaitForExecutionHandler);
|
|
|
|
|
internalControlWaitForExecutionHandlerRef = new InternalControlWaitForExecutionHandler (InternalControlWaitForExecutionHandlerImpl);
|
|
|
|
|
|
|
|
|
|
IedServer_setWaitForExecutionHandler(self, controlObject.self, internalControlWaitForExecutionHandlerRef, GCHandle.ToIntPtr(info.handle));
|
|
|
|
|
}
|
|
|
|
@ -946,7 +1038,7 @@ namespace IEC61850
|
|
|
|
|
writeAccessHandlers.Add (dataAttr.self, new WriteAccessHandlerInfo(handler, parameter, dataAttr));
|
|
|
|
|
//writeAccessHandlers.Item [dataAttr.self] = handler;
|
|
|
|
|
|
|
|
|
|
IedServer_handleWriteAccess (self, dataAttr.self, writeAccessHandler, IntPtr.Zero);
|
|
|
|
|
IedServer_handleWriteAccess (self, dataAttr.self, WriteAccessHandlerImpl, IntPtr.Zero);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SetWriteAccessPolicy(FunctionalConstraint fc, AccessPolicy policy)
|
|
|
|
|