diff --git a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs index a02a7374..e166c09f 100644 --- a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs @@ -398,6 +398,21 @@ namespace IEC61850 IedConnection_readObjectAsync(IntPtr self, out int error, string objRef, int fc, IedConnection_ReadObjectHandler handler, IntPtr parameter); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void IedConnection_WriteObjectHandler (UInt32 invokeId, IntPtr parameter, int err); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt32 + IedConnection_writeObjectAsync(IntPtr self, out int error, string objRef, int fc, + IntPtr value, IedConnection_WriteObjectHandler handler, IntPtr parameter); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void IedConnection_GetNameListHandler (UInt32 invokeId, IntPtr parameter, int err, IntPtr nameList, [MarshalAs(UnmanagedType.I1)] bool moreFollows); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt32 + IedConnection_getServerDirectoryAsync(IntPtr self, out int error, string continueAfter, IntPtr result, + IedConnection_GetNameListHandler handler, IntPtr parameter); /******************** * FileDirectoryEntry @@ -1492,7 +1507,7 @@ namespace IEC61850 handler(invokeId, handlerParameter, clientError, mmsValue); } - /// Asynchronously read the value of a data attribute (DA) or functional constraint data object (FCDO). + /// Asynchronously read the value of a data attribute (DA) or functional constraint data object (FCDO) - GetData service /// The object reference of a DA or FCDO. /// The functional constraint (FC) of the object /// Callback function to handle the received response or service timeout @@ -1515,6 +1530,121 @@ namespace IEC61850 throw new IedConnectionException("Reading value failed", error); } + return invokeId; + } + + /// + /// Write value handler. + /// + /// The invoke ID of the reqeust triggering this callback + /// user provided callback parameter + /// Error code of response or timeout error in case of a response timeout + public delegate void WriteValueHandler(UInt32 invokeId, object parameter, IedClientError err); + + private void nativeWriteObjectHandler (UInt32 invokeId, IntPtr parameter, int err) + { + GCHandle handle = GCHandle.FromIntPtr(parameter); + + Tuple callbackInfo = handle.Target as Tuple; + + WriteValueHandler handler = callbackInfo.Item1; + object handlerParameter = callbackInfo.Item2; + + handle.Free(); + + IedClientError clientError = (IedClientError)err; + + handler(invokeId, handlerParameter, clientError); + } + + + public UInt32 WriteValueAsync(string objectReference, FunctionalConstraint fc, MmsValue value, WriteValueHandler handler, object parameter) + { + int error; + + Tuple callbackInfo = Tuple.Create(handler, parameter); + + GCHandle handle = GCHandle.Alloc(callbackInfo); + + UInt32 invokeId = IedConnection_writeObjectAsync(connection, out error, objectReference, (int)fc, value.valueReference, nativeWriteObjectHandler, GCHandle.ToIntPtr(handle)); + + if (error != 0) + { + handle.Free(); + throw new IedConnectionException("Writing value failed", error); + } + + return invokeId; + } + + public delegate void GetNameListHandler(UInt32 invokeId, object parameter, IedClientError err, List nameList, bool moreFollows); + + private void nativeGetNameListHandler (UInt32 invokeId, IntPtr parameter, int err, IntPtr nameList, [MarshalAs(UnmanagedType.I1)] bool moreFollows) + { + GCHandle handle = GCHandle.FromIntPtr(parameter); + + Tuple> callbackInfo = handle.Target as Tuple>; + + GetNameListHandler handler = callbackInfo.Item1; + object handlerParameter = callbackInfo.Item2; + List resultList = callbackInfo.Item3; + + handle.Free(); + + IedClientError clientError = (IedClientError)err; + + if (nameList != IntPtr.Zero) + { + IntPtr element = LinkedList_getNext(nameList); + + if (resultList == null) + resultList = new List(); + + while (element != IntPtr.Zero) + { + string ld = Marshal.PtrToStringAnsi(LinkedList_getData(element)); + + resultList.Add(ld); + + element = LinkedList_getNext(element); + } + + LinkedList_destroy(nameList); + + handler(invokeId, handlerParameter, clientError, resultList, moreFollows); + } + else + { + handler(invokeId, handlerParameter, clientError, null, moreFollows); + } + + } + + /// + /// Gets the server directory (Logical devices or file objects) + /// + /// list where to store the result or null to create a new list for the result + /// continuation value (last received name) + /// user provided callback function + /// user provided callback parameter + /// the invoke ID of the sent request + /// This exception is thrown if there is a connection or service error + public UInt32 GetServerDirectoryAsync(List result, string continueAfter, GetNameListHandler handler, object parameter) + { + int error; + + Tuple> callbackInfo = Tuple.Create(handler, parameter, result); + + GCHandle handle = GCHandle.Alloc(callbackInfo); + + UInt32 invokeId = IedConnection_getServerDirectoryAsync(connection, out error, continueAfter, IntPtr.Zero, nativeGetNameListHandler, GCHandle.ToIntPtr(handle)); + + if (error != 0) + { + handle.Free(); + throw new IedConnectionException("Get server directory failed", error); + } + return invokeId; }