diff --git a/dotnet/IEC61850forCSharp/Control.cs b/dotnet/IEC61850forCSharp/Control.cs index 4fa909cf..c096c923 100644 --- a/dotnet/IEC61850forCSharp/Control.cs +++ b/dotnet/IEC61850forCSharp/Control.cs @@ -28,10 +28,7 @@ using IEC61850.Common; namespace IEC61850 { - - /// - /// IEC 61850 common API parts (used by client and server API) - /// + // IEC 61850 common API parts (used by client and server API) namespace Common { /// @@ -76,8 +73,8 @@ namespace IEC61850 } } - namespace Client { - + namespace Client + { [StructLayout(LayoutKind.Sequential)] internal struct LastApplErrorInternal { @@ -128,7 +125,10 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] private static extern int ControlObjectClient_getCtlValType(IntPtr self); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [DllImport ("iec61850", CallingConvention = CallingConvention.Cdecl)] + private static extern int ControlObjectClient_getLastError (IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.I1)] private static extern bool ControlObjectClient_operate(IntPtr self, IntPtr ctlVal, UInt64 operTime); @@ -190,7 +190,7 @@ namespace IEC61850 public delegate void CommandTerminationHandler (Object parameter, ControlObject controlObject); private IedConnection iedConnection; - private IntPtr controlObject; + private IntPtr self; private CommandTerminationHandler commandTerminationHandler = null; private Object commandTerminationHandlerParameter = null; @@ -207,14 +207,14 @@ namespace IEC61850 { this.iedConnection = iedConnection; - this.controlObject = ControlObjectClient_create(objectReference, connection); + this.self = ControlObjectClient_create(objectReference, connection); - if (this.controlObject == System.IntPtr.Zero) + if (this.self == System.IntPtr.Zero) throw new IedConnectionException("Control object not found", 0); intCommandTerminationHandler = new InternalCommandTerminationHandler (MyCommandTerminationHandler); - ControlObjectClient_setCommandTerminationHandler(controlObject, intCommandTerminationHandler, controlObject); + ControlObjectClient_setCommandTerminationHandler(self, intCommandTerminationHandler, self); } /// @@ -225,7 +225,7 @@ namespace IEC61850 /// public ControlModel GetControlModel () { - ControlModel controlModel = (ControlModel) ControlObjectClient_getControlModel(controlObject); + ControlModel controlModel = (ControlModel) ControlObjectClient_getControlModel(self); return controlModel; } @@ -236,7 +236,7 @@ namespace IEC61850 /// MmsType required for the ctlVal value. public MmsType GetCtlValType () { - MmsType ctlValType = (MmsType) ControlObjectClient_getCtlValType (controlObject); + MmsType ctlValType = (MmsType) ControlObjectClient_getCtlValType (self); return ctlValType; } @@ -252,7 +252,17 @@ namespace IEC61850 /// public void SetOrigin (string originator, OrCat originatorCategory) { - ControlObjectClient_setOrigin(controlObject, originator, (int) originatorCategory); + ControlObjectClient_setOrigin(self, originator, (int) originatorCategory); + } + + /// + /// Gets the error code of the last synchronous control action (operate, select, select-with-value, cancel) + /// + /// error code. + public IedClientError LastError { + get { + return (IedClientError)ControlObjectClient_getLastError (self); + } } /// @@ -342,7 +352,7 @@ namespace IEC61850 /// true when the operation has been successful, false otherwise public bool Operate (MmsValue ctlVal, UInt64 operTime) { - return ControlObjectClient_operate(controlObject, ctlVal.valueReference, operTime); + return ControlObjectClient_operate(self, ctlVal.valueReference, operTime); } private void nativeOperateHandler (UInt32 invokeId, IntPtr parameter, int err, int type, bool success) @@ -477,7 +487,7 @@ namespace IEC61850 GCHandle handle = GCHandle.Alloc(callbackInfo); - UInt32 invokeId = ControlObjectClient_operateAsync(controlObject, out error, ctlVal.valueReference, operTime, nativeOperateHandler, GCHandle.ToIntPtr(handle)); + UInt32 invokeId = ControlObjectClient_operateAsync(self, out error, ctlVal.valueReference, operTime, nativeOperateHandler, GCHandle.ToIntPtr(handle)); if (error != 0) { @@ -494,7 +504,7 @@ namespace IEC61850 /// true when the selection has been successful, false otherwise public bool Select () { - return ControlObjectClient_select(controlObject); + return ControlObjectClient_select(self); } /// @@ -512,7 +522,7 @@ namespace IEC61850 GCHandle handle = GCHandle.Alloc(callbackInfo); - UInt32 invokeId = ControlObjectClient_selectAsync(controlObject, out error, nativeOperateHandler, GCHandle.ToIntPtr(handle)); + UInt32 invokeId = ControlObjectClient_selectAsync(self, out error, nativeOperateHandler, GCHandle.ToIntPtr(handle)); if (error != 0) { @@ -530,7 +540,7 @@ namespace IEC61850 /// true when the selection has been successful, false otherwise public bool SelectWithValue (MmsValue ctlVal) { - return ControlObjectClient_selectWithValue(controlObject, ctlVal.valueReference); + return ControlObjectClient_selectWithValue(self, ctlVal.valueReference); } /// @@ -624,7 +634,7 @@ namespace IEC61850 GCHandle handle = GCHandle.Alloc(callbackInfo); - UInt32 invokeId = ControlObjectClient_selectWithValueAsync(controlObject, out error, ctlVal.valueReference, nativeOperateHandler, GCHandle.ToIntPtr(handle)); + UInt32 invokeId = ControlObjectClient_selectWithValueAsync(self, out error, ctlVal.valueReference, nativeOperateHandler, GCHandle.ToIntPtr(handle)); if (error != 0) { @@ -645,7 +655,7 @@ namespace IEC61850 /// This exception is thrown if there is a connection or service error public bool Cancel () { - return ControlObjectClient_cancel(controlObject); + return ControlObjectClient_cancel(self); } /// @@ -659,7 +669,7 @@ namespace IEC61850 GCHandle handle = GCHandle.Alloc(callbackInfo); - UInt32 invokeId = ControlObjectClient_cancelAsync(controlObject, out error, nativeOperateHandler, GCHandle.ToIntPtr(handle)); + UInt32 invokeId = ControlObjectClient_cancelAsync(self, out error, nativeOperateHandler, GCHandle.ToIntPtr(handle)); if (error != 0) { @@ -676,7 +686,7 @@ namespace IEC61850 [Obsolete("use SetSynchroCheck instead")] public void EnableSynchroCheck () { - ControlObjectClient_setSynchroCheck (controlObject, true); + ControlObjectClient_setSynchroCheck (self, true); } /// @@ -685,7 +695,7 @@ namespace IEC61850 [Obsolete("use SetInterlockCheck instead")] public void EnableInterlockCheck () { - ControlObjectClient_setInterlockCheck (controlObject, true); + ControlObjectClient_setInterlockCheck (self, true); } /// @@ -693,7 +703,7 @@ namespace IEC61850 /// public void SetInterlockCheck (bool value) { - ControlObjectClient_setInterlockCheck (controlObject, value); + ControlObjectClient_setInterlockCheck (self, value); } /// @@ -701,7 +711,7 @@ namespace IEC61850 /// public void SetSynchroCheck (bool value) { - ControlObjectClient_setSynchroCheck (controlObject, value); + ControlObjectClient_setSynchroCheck (self, value); } /// @@ -709,7 +719,7 @@ namespace IEC61850 /// public void SetTestMode (bool value) { - ControlObjectClient_setTestMode (controlObject, value); + ControlObjectClient_setTestMode (self, value); } /// @@ -720,7 +730,7 @@ namespace IEC61850 /// public LastApplError GetLastApplError () { - LastApplErrorInternal lastApplError = ControlObjectClient_getLastApplError(controlObject); + LastApplErrorInternal lastApplError = ControlObjectClient_getLastApplError(self); return new LastApplError(lastApplError); } @@ -741,9 +751,9 @@ namespace IEC61850 } protected virtual void Dispose(bool disposing) { - if (this.controlObject != System.IntPtr.Zero) { - ControlObjectClient_destroy (controlObject); - this.controlObject = System.IntPtr.Zero; + if (this.self != System.IntPtr.Zero) { + ControlObjectClient_destroy (self); + this.self = System.IntPtr.Zero; } } diff --git a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs index 4f613bb9..6a0f8ae9 100644 --- a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs @@ -1,7 +1,7 @@ /* * IEC61850ClientAPI.cs * - * Copyright 2014-2016 Michael Zillgith + * Copyright 2014-2019 Michael Zillgith * * This file is part of libIEC61850. * @@ -29,14 +29,10 @@ using System.Collections; using IEC61850.Common; using IEC61850.TLS; -/// -/// IEC 61850 API for the libiec61850 .NET wrapper library -/// +// IEC 61850 API for the libiec61850 .NET wrapper library namespace IEC61850 { - /// - /// IEC 61850 client API. - /// + // IEC 61850 client API. namespace Client { @@ -201,7 +197,9 @@ namespace IEC61850 } } - + /// + /// Represents a variable in a log entry + /// public class MmsJournalVariable { [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] @@ -265,6 +263,10 @@ namespace IEC61850 this.self = self; } + /// + /// Gets the journal variables. + /// + /// The journal variables. public List GetJournalVariables() { if (variables == null) @@ -289,7 +291,10 @@ namespace IEC61850 return variables; } - + /// + /// Gets the entry identifier of the log entry + /// + /// The entry identifier. public byte[] GetEntryID() { IntPtr mmsValuePtr = MmsJournalEntry_getEntryID(self); @@ -301,6 +306,10 @@ namespace IEC61850 return octetString; } + /// + /// Gets the occurence time of the log entry + /// + /// The occurence time. public ulong GetOccurenceTime() { IntPtr mmsValuePtr = MmsJournalEntry_getOccurenceTime(self); @@ -310,6 +319,9 @@ namespace IEC61850 return mmsValue.GetBinaryTimeAsUtcMs(); } + /// + /// Releases all resource used by the object. + /// public void Dispose() { if (self != IntPtr.Zero) diff --git a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs index efff22ef..683d646b 100644 --- a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs @@ -21,26 +21,21 @@ * 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; -/// -/// IEC 61850 API for the libiec61850 .NET wrapper library -/// +// IEC 61850 API for the libiec61850 .NET wrapper library namespace IEC61850 { - /// - /// IEC 61850 server API. - /// - namespace Server - { - - public class ConfigFileParser + // IEC 61850 server API. + namespace Server + { + /// + /// Config file parser. + /// + public class ConfigFileParser { [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] @@ -69,6 +64,9 @@ namespace IEC61850 } } + /// + /// Representation of the IED server data model + /// public class IedModel { [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] @@ -93,6 +91,10 @@ namespace IEC61850 this.self = self; } + /// + /// Initializes a new instance of the class. + /// + /// IED name 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 } } + /// + /// Represents additional context information of the control action that caused the callback invokation + /// + 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; + } + + /// + /// Sets the add cause for the next command termination or application error message + /// + /// the additional cause code + public void SetAddCause (ControlAddCause addCause) + { + ControlAction_setAddCause (self, (int)addCause); + } + + /// + /// Gets the originator category provided by the client + /// + /// The or cat. + public OrCat GetOrCat () + { + return (OrCat)ControlAction_getOrCat (self); + } + + /// + /// Get the originator identifier provided by the client + /// + /// The or ident. + 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; + } + + /// + /// Gets the control object that is subject to this action + /// + /// the controllable data object instance + public DataObject GetControlObject () + { + return info.controlObject; + } + + /// + /// Gets the client object associated with the client that caused the control action + /// + /// The client connection. + 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 { /// @@ -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); /// /// 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 controlHandlers = new Dictionary (); - 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 writeAccessHandlers = new Dictionary (); - 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 clientConnections = new Dictionary (); - - + internal Dictionary clientConnections = new Dictionary (); 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) diff --git a/dotnet/IEC61850forCSharp/MmsValue.cs b/dotnet/IEC61850forCSharp/MmsValue.cs index 79f570a0..12b6f091 100644 --- a/dotnet/IEC61850forCSharp/MmsValue.cs +++ b/dotnet/IEC61850forCSharp/MmsValue.cs @@ -521,9 +521,12 @@ namespace IEC61850 if ((elementType == MmsType.MMS_ARRAY) || (elementType == MmsType.MMS_STRUCTURE)) { if ((index >= 0) && (index < Size ())) { - MmsValue_setElement (valueReference, index, elementValue.valueReference); - - } else + if (elementValue != null) + MmsValue_setElement (valueReference, index, elementValue.valueReference); + else + MmsValue_setElement (valueReference, index, IntPtr.Zero); + + } else throw new MmsValueException ("Index out of bounds"); } else diff --git a/dotnet/server1/Program.cs b/dotnet/server1/Program.cs index 62c7c5e3..a5910937 100644 --- a/dotnet/server1/Program.cs +++ b/dotnet/server1/Program.cs @@ -31,7 +31,7 @@ namespace server1 IedServer iedServer = new IedServer (iedModel, config); - iedServer.SetControlHandler (spcso1, delegate(DataObject controlObject, object parameter, MmsValue ctlVal, bool test) { + iedServer.SetControlHandler (spcso1, delegate(ControlAction action, object parameter, MmsValue ctlVal, bool test) { bool val = ctlVal.GetBoolean(); if (val) diff --git a/dotnet/tests/Test.cs b/dotnet/tests/Test.cs index d1c38871..934bfe71 100644 --- a/dotnet/tests/Test.cs +++ b/dotnet/tests/Test.cs @@ -126,7 +126,11 @@ namespace tests Assert.AreEqual (elem2.GetType (), MmsType.MMS_INTEGER); Assert.AreEqual (elem2.ToInt32 (), 3); - } + + val.SetElement (0, null); + val.SetElement (1, null); + val.SetElement (2, null); + } [Test()] public void MmsValueStructure() @@ -147,6 +151,9 @@ namespace tests MmsValue elem1 = val.GetElement (1); Assert.AreEqual (elem1.GetType (), MmsType.MMS_BIT_STRING); + + val.SetElement (0, null); + val.SetElement (1, null); } [Test ()] @@ -428,7 +435,17 @@ namespace tests IedServer iedServer = new IedServer (iedModel); - iedServer.SetControlHandler (spcso1, delegate(DataObject controlObject, object parameter, MmsValue ctlVal, bool test) { + iedServer.SetControlHandler (spcso1, delegate(ControlAction action, object parameter, MmsValue ctlVal, bool test) { + + byte [] orIdent = action.GetOrIdent (); + + string orIdentStr = System.Text.Encoding.UTF8.GetString (orIdent, 0, orIdent.Length); + + Assert.AreEqual ("TEST1234", orIdentStr); + Assert.AreEqual (OrCat.MAINTENANCE, action.GetOrCat ()); + + Assert.AreSame (spcso1, action.GetControlObject ()); + handlerCalled++; return ControlHandlerResult.OK; }, null); @@ -440,6 +457,7 @@ namespace tests connection.Connect ("localhost", 10002); ControlObject controlClient = connection.CreateControlObject ("simpleIOGenericIO/GGIO1.SPCSO1"); + controlClient.SetOrigin ("TEST1234", OrCat.MAINTENANCE); Assert.IsNotNull (controlClient); diff --git a/dotnet/tls_server_example/Program.cs b/dotnet/tls_server_example/Program.cs index e7aa0cfc..115cc100 100644 --- a/dotnet/tls_server_example/Program.cs +++ b/dotnet/tls_server_example/Program.cs @@ -46,7 +46,7 @@ namespace tls_server_example IedServer iedServer = new IedServer (iedModel, tlsConfig); - iedServer.SetControlHandler (spcso1, delegate(DataObject controlObject, object parameter, MmsValue ctlVal, bool test) { + iedServer.SetControlHandler (spcso1, delegate(ControlAction action, object parameter, MmsValue ctlVal, bool test) { bool val = ctlVal.GetBoolean(); if (val) diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index cd4336fb..63c668f1 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -1086,7 +1086,7 @@ typedef enum { typedef void* ControlAction; /** - * \brief Set the add cause for the next command termination or application error message + * \brief Sets the add cause for the next command termination or application error message * * \param self the control action instance * \param addCause the additional cause @@ -1095,7 +1095,7 @@ LIB61850_API void ControlAction_setAddCause(ControlAction self, ControlAddCause addCause); /** - * \brief Get the originator category provided by the client + * \brief Gets the originator category provided by the client * * \param self the control action instance * @@ -1105,7 +1105,7 @@ LIB61850_API int ControlAction_getOrCat(ControlAction self); /** - * \brief Get the originator identifier provided by the client + * \brief Gets the originator identifier provided by the client * * \param self the control action instance * @@ -1115,7 +1115,7 @@ LIB61850_API uint8_t* ControlAction_getOrIdent(ControlAction self, int* orIdentSize); /** - * \brief Get the client object associated with the client that caused the control action + * \brief Gets the client object associated with the client that caused the control action * * \param self the control action instance * @@ -1125,7 +1125,7 @@ LIB61850_API ClientConnection ControlAction_getClientConnection(ControlAction self); /** - * \brief Get the control object that is subject to this action + * \brief Gets the control object that is subject to this action * * \param self the control action instance *