From 0dc79d4dd82b9a6627499ecf10f501f64dbda88a Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Sat, 4 Dec 2021 19:44:22 +0100 Subject: [PATCH] - .NET API: Added functions for IedConnction - CreateDataSetAsync, DeleteDataSetAsync, GetDataSetDirectoryAsync (LIB61850-260) --- dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs | 161 +++++++++++++++++- 1 file changed, 156 insertions(+), 5 deletions(-) diff --git a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs index 4c2a53c4..0ccd5b09 100644 --- a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs @@ -1,7 +1,7 @@ /* * IEC61850ClientAPI.cs * - * Copyright 2014-2019 Michael Zillgith + * Copyright 2014-2021 Michael Zillgith * * This file is part of libIEC61850. * @@ -622,13 +622,31 @@ namespace IEC61850 int fc, IedConnection_GetVariableSpecificationHandler handler, IntPtr parameter); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void IedConnection_ReadDataSetHandler(UInt32 invokeId,IntPtr parameter,int err,IntPtr dataSet); + private delegate void IedConnection_ReadDataSetHandler(UInt32 invokeId, IntPtr parameter, int err, IntPtr dataSet); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern UInt32 IedConnection_readDataSetValuesAsync(IntPtr self, out int error, string dataSetReference, IntPtr dataSet, IedConnection_ReadDataSetHandler handler, IntPtr parameter); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt32 + IedConnection_createDataSetAsync(IntPtr self, out int error, [MarshalAs(UnmanagedType.LPStr)] string dataSetReference, IntPtr dataSet, + IedConnection_GenericServiceHandler handler, IntPtr parameter); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt32 + IedConnection_deleteDataSetAsync(IntPtr self, out int error, [MarshalAs(UnmanagedType.LPStr)] string dataSetReference, + IedConnection_GenericServiceHandler handler, IntPtr parameter); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void IedConnection_GetDataSetDirectoryHandler(UInt32 invokeId, IntPtr parameter, int err, IntPtr dataSetDirectory, [MarshalAs(UnmanagedType.I1)] bool isDeletable); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt32 + IedConnection_getDataSetDirectoryAsync(IntPtr self, out int error, [MarshalAs(UnmanagedType.LPStr)] string dataSetReference, + IedConnection_GetDataSetDirectoryHandler handler, IntPtr parameter); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate void IedConnection_GetRCBValuesHandler(UInt32 invokeId,IntPtr parameter,int err,IntPtr rcb); @@ -1727,9 +1745,6 @@ namespace IEC61850 return invokeId; } - - - /// /// Abort (close) the connection. /// @@ -1989,6 +2004,47 @@ namespace IEC61850 } + /// + /// Create a new data set - asynchronous version. + /// + /// This function creates a new data set at the server. The data set consists of the members defined + /// by the list of object references provided. + /// The object reference of the data set + /// A list of object references of the data set elements + /// Callback function to handle the received response or service timeout + /// User provided callback parameter. Will be passed to the callback function + /// the invoke ID of the sent request + /// This exception is thrown if there is a connection or service error + public UInt32 CreateDataSetAsync(string dataSetReference, List dataSetElements, GenericServiceHandler handler, object parameter) + { + int error = 0; + + IntPtr linkedList = LinkedList_create(); + + foreach (string dataSetElement in dataSetElements) + { + IntPtr dataSetElementHandle = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(dataSetElement); + + LinkedList_add(linkedList, dataSetElementHandle); + } + + Tuple callbackInfo = Tuple.Create(handler, parameter); + + GCHandle handle = GCHandle.Alloc(callbackInfo); + + UInt32 invokeId = IedConnection_createDataSetAsync(connection, out error, dataSetReference, linkedList, nativeGenericServiceHandler, GCHandle.ToIntPtr(handle)); + + LinkedList_destroyDeep(linkedList, new LinkedListValueDeleteFunction(FreeHGlobaleDeleteFunction)); + + if (error != 0) + { + handle.Free(); + throw new IedConnectionException("Create data set failed", error); + } + + return invokeId; + } + /// /// Delete a data set. /// @@ -2009,6 +2065,35 @@ namespace IEC61850 return isDeleted; } + /// + /// Delete a data set - asynchronous version. + /// + /// This function will delete a data set at the server. This function may fail if the data set is not + /// deletable. + /// The object reference of the data set + /// Callback function to handle the received response or service timeout + /// User provided callback parameter. Will be passed to the callback function + /// the invoke ID of the sent request + /// This exception is thrown if there is a connection or service error + public UInt32 DeleteDataSetAsync(string dataSetReference, GenericServiceHandler handler, object parameter) + { + int error = 0; + + Tuple callbackInfo = Tuple.Create(handler, parameter); + + GCHandle handle = GCHandle.Alloc(callbackInfo); + + UInt32 invokeId = IedConnection_deleteDataSetAsync(connection, out error, dataSetReference, nativeGenericServiceHandler, GCHandle.ToIntPtr(handle)); + + if (error != 0) + { + handle.Free(); + throw new IedConnectionException("Delete data set failed", error); + } + + return invokeId; + } + /// /// Get the directory of the data set. /// @@ -2058,6 +2143,72 @@ namespace IEC61850 return newList; } + /// + /// Get data set directory 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 + /// the list of data set entry references + /// data set can be deleted by a client (dynamic data set) + public delegate void GetDataSetDirectoryHandler(UInt32 invokeId, object parameter, IedClientError err, List dataSetDirectory, bool isDeletable); + + private void nativeGetDataSetDirectoryHandler(UInt32 invokeId, IntPtr parameter, int err, IntPtr dataSetDirectory, bool isDeletable) + { + GCHandle handle = GCHandle.FromIntPtr(parameter); + + Tuple callbackInfo = handle.Target as Tuple; + + GetDataSetDirectoryHandler handler = callbackInfo.Item1; + object handlerParameter = callbackInfo.Item2; + + IntPtr element = LinkedList_getNext(dataSetDirectory); + + handle.Free(); + + List newList = new List(); + + while (element != IntPtr.Zero) + { + string dataObject = Marshal.PtrToStringAnsi(LinkedList_getData(element)); + + newList.Add(dataObject); + + element = LinkedList_getNext(element); + } + + LinkedList_destroy(dataSetDirectory); + + handler.Invoke(invokeId, handlerParameter, (IedClientError)err, newList, isDeletable); + } + + /// + /// Read the data set directory - asynchronous version + /// + /// The data set directory async. + /// Data set reference. + /// Callback function to handle the received response or service timeout + /// User provided callback parameter. Will be passed to the callback function + /// the invoke ID of the sent request + /// This exception is thrown if there is a connection or service error + public UInt32 GetDataSetDirectoryAsync(string dataSetReference, GetDataSetDirectoryHandler handler, object parameter) + { + int error = 0; + + Tuple callbackInfo = Tuple.Create(handler, parameter); + + GCHandle handle = GCHandle.Alloc(callbackInfo); + + UInt32 invokeId = IedConnection_getDataSetDirectoryAsync(connection, out error, dataSetReference, nativeGetDataSetDirectoryHandler, GCHandle.ToIntPtr(handle)); + + if (error != 0) + { + handle.Free(); + throw new IedConnectionException("Get data set directory failed", error); + } + + return invokeId; + } /// /// Read object handler.