diff --git a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs index 68a22ff3..b919cfeb 100644 --- a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs @@ -439,7 +439,12 @@ namespace IEC61850 static extern IntPtr MmsConnection_getIsoConnectionParameters(IntPtr mmsConnection); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern IntPtr IedConnection_getFileDirectory(IntPtr self, out int error, string directoryName); + static extern IntPtr IedConnection_getFileDirectory(IntPtr self, out int error, string directoryName); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr + IedConnection_getFileDirectoryEx(IntPtr self, out int error, string directoryName, string continueAfter + , [MarshalAs(UnmanagedType.I1)] out bool moreFollows); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void IedConnection_deleteFile(IntPtr self, out int error, string fileName); @@ -484,6 +489,15 @@ namespace IEC61850 * Async functions *********************/ + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + static extern void IedConnection_connectAsync (IntPtr self, out int error, string hostname, int tcpPort); + + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + static extern void IedConnection_abortAsync (IntPtr self, out int error); + + [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] + private static extern void IedConnection_releaseAsync(IntPtr self, out int error); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate void IedConnection_ReadObjectHandler (UInt32 invokeId, IntPtr parameter, int err, IntPtr value); @@ -513,6 +527,11 @@ namespace IEC61850 IedConnection_getLogicalDeviceVariablesAsync(IntPtr self, out int error, string ldName, string continueAfter, IntPtr result, IedConnection_GetNameListHandler handler, IntPtr parameter); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt32 + IedConnection_getLogicalDeviceDataSetsAsync(IntPtr self, out int error, string ldName, string continueAfter, IntPtr result, + IedConnection_GetNameListHandler handler, IntPtr parameter); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate void IedConnection_QueryLogHandler (UInt32 invokeId, IntPtr parameter, int err, IntPtr journalEntries, [MarshalAs(UnmanagedType.I1)] bool moreFollows); @@ -686,6 +705,19 @@ namespace IEC61850 throw new IedConnectionException ("Connect to " + hostname + ":" + tcpPort + " failed", error); } + public void ConnectAsync(string hostname, int tcpPort) + { + int error; + + IedConnection_setConnectTimeout(connection, connectTimeout); + + IedConnection_connectAsync (connection, out error, hostname, tcpPort); + + if (error != 0) + throw new IedConnectionException ("Connect to " + hostname + ":" + tcpPort + " failed", error); + + } + /// /// Gets the current state of the connection /// @@ -1294,6 +1326,41 @@ namespace IEC61850 LinkedList_destroyStatic(fileEntryList); return fileDirectory; + } + + /// Read the content of a file directory. - single request version + /// The name of the directory. + /// This exception is thrown if there is a connection or service error + /// The name of the directory. + public List GetFileDirectoryEx(string directoryName, string continueAfter, out bool moreFollows) + { + int error; + + IntPtr fileEntryList = IedConnection_getFileDirectoryEx(connection, out error, directoryName, continueAfter, out moreFollows); + + if (error != 0) + throw new IedConnectionException("Reading file directory failed", error); + + List fileDirectory = new List(); + + IntPtr element = LinkedList_getNext(fileEntryList); + + while (element != IntPtr.Zero) + { + IntPtr elementData = LinkedList_getData(element); + + FileDirectoryEntry entry = new FileDirectoryEntry(elementData); + + fileDirectory.Add(entry); + + FileDirectoryEntry_destroy(elementData); + + element = LinkedList_getNext(element); + } + + LinkedList_destroyStatic(fileEntryList); + + return fileDirectory; } [UnmanagedFunctionPointer(CallingConvention.Cdecl)] @@ -1376,6 +1443,22 @@ namespace IEC61850 throw new IedConnectionException ("Abort failed", error); } + /// + /// Abort (close) the connection - asynchronous version + /// + /// This function will send an abort request to the server. This will immediately interrupt the + /// connection. + /// This exception is thrown if there is a connection or service error + public void AbortAsync () + { + int error; + + IedConnection_abortAsync (connection, out error); + + if (error != 0) + throw new IedConnectionException ("Abort failed", error); + } + /// /// Release (close) the connection. /// @@ -1392,6 +1475,22 @@ namespace IEC61850 throw new IedConnectionException ("Release failed", error); } + /// + /// Release (close) the connection - asynchronous version + /// + /// This function will send an release request to the server. The function will block until the + /// connection is released or an error occured. + /// This exception is thrown if there is a connection or service error + public void ReleaseAsync () + { + int error; + + IedConnection_releaseAsync(connection, out error); + + if (error != 0) + throw new IedConnectionException ("Release failed", error); + } + /// /// Immediately close the connection. /// @@ -1850,6 +1949,30 @@ namespace IEC61850 return invokeId; } + public UInt32 GetLogicalDeviceDataSetsAsync(string ldName, string continueAfter, GetNameListHandler handler, object parameter) + { + return GetLogicalDeviceDataSetsAsync(null, ldName, continueAfter, handler, parameter); + } + + + public UInt32 GetLogicalDeviceDataSetsAsync(List result, string ldName, string continueAfter, GetNameListHandler handler, object parameter) + { + int error; + + Tuple> callbackInfo = Tuple.Create(handler, parameter, result); + + GCHandle handle = GCHandle.Alloc(callbackInfo); + + UInt32 invokeId = IedConnection_getLogicalDeviceDataSetsAsync(connection, out error, ldName, continueAfter, IntPtr.Zero, nativeGetNameListHandler, GCHandle.ToIntPtr(handle)); + + if (error != 0) + { + handle.Free(); + throw new IedConnectionException("Get logical device data sets failed", error); + } + + return invokeId; + } public delegate void QueryLogHandler(UInt32 invokeId, object parameter, IedClientError err, List journalEntries, bool moreFollows); diff --git a/dotnet/files/FileServicesExample.cs b/dotnet/files/FileServicesExample.cs index f77743fc..bdd02126 100644 --- a/dotnet/files/FileServicesExample.cs +++ b/dotnet/files/FileServicesExample.cs @@ -15,7 +15,9 @@ namespace files { public static void printFiles (IedConnection con, string prefix, string parent) { - List files = con.GetFileDirectory (parent); + bool moreFollows = false; + + List files = con.GetFileDirectoryEx (parent, null, out moreFollows); foreach (FileDirectoryEntry file in files) { Console.WriteLine (prefix + file.GetFileName () + "\t" + file.GetFileSize () + "\t" + @@ -26,6 +28,8 @@ namespace files } } + if (moreFollows) + Console.WriteLine("-- MORE FILES AVAILABLE --"); } static bool getFileHandler (object parameter, byte[] data) @@ -48,7 +52,7 @@ namespace files if (args.Length > 0) hostname = args [0]; else - hostname = "10.0.2.2"; + hostname = "127.0.0.1"; Console.WriteLine ("Connect to " + hostname); diff --git a/examples/iec61850_client_example_files/file-tool.c b/examples/iec61850_client_example_files/file-tool.c index 52680c44..6a53dd0a 100644 --- a/examples/iec61850_client_example_files/file-tool.c +++ b/examples/iec61850_client_example_files/file-tool.c @@ -79,6 +79,7 @@ basename(char* path) static char* hostname = "localhost"; static int tcpPort = 102; static char* filename = NULL; +static bool singleRequest = false; typedef enum { FileOperationType_None = 0, @@ -116,6 +117,7 @@ printHelp() printf(" Options:\n"); printf(" -h \n"); printf(" -p portnumber\n"); + printf(" -s single request for show (sub) directory (ignore morefollows"); printf(" Operations\n"); printf(" dir - show directory\n"); printf(" subdir - show sub directory\n"); @@ -140,6 +142,9 @@ parseOptions(int argc, char** argv) else if (strcmp(argv[currentArgc], "-p") == 0) { tcpPort = atoi(argv[++currentArgc]); } + else if (strcmp(argv[currentArgc], "-s") == 0) { + singleRequest = true; + } else if (strcmp(argv[currentArgc], "del") == 0) { operation = FileOperationType_Del; filename = argv[++currentArgc]; @@ -179,9 +184,15 @@ showDirectory(IedConnection con) { IedClientError error; + bool moreFollows = false; + /* Get the root directory */ - LinkedList rootDirectory = - IedConnection_getFileDirectory(con, &error, filename); + LinkedList rootDirectory; + + if (singleRequest) + rootDirectory = IedConnection_getFileDirectoryEx(con, &error, filename, NULL, &moreFollows); + else + rootDirectory = IedConnection_getFileDirectory(con, &error, filename); if (error != IED_ERROR_OK) { printf("Error retrieving file directory\n"); @@ -200,6 +211,9 @@ showDirectory(IedConnection con) LinkedList_destroyDeep(rootDirectory, (LinkedListValueDeleteFunction) FileDirectoryEntry_destroy); } + + if (moreFollows) + printf("\n- MORE FILES AVAILABLE -\n"); } void diff --git a/src/iec61850/inc/iec61850_client.h b/src/iec61850/inc/iec61850_client.h index 0bd6f358..2a673439 100644 --- a/src/iec61850/inc/iec61850_client.h +++ b/src/iec61850/inc/iec61850_client.h @@ -208,6 +208,8 @@ IedConnection_createEx(TLSConfiguration tlsConfig, bool useThreads); * the \ref IedConnection_connect or \ref IedConnection_connectAsync method has to be called. * The connection will use TLS when a TLSConfiguration object is provided. The connection will be in thread mode. * + * \deprecated Use \ref IedConnection_createEx instead + * * \param tlsConfig the TLS configuration to be used * * \return the new IedConnection instance @@ -287,6 +289,11 @@ IedConnection_connect(IedConnection self, IedClientError* error, const char* hos /** * \brief Asynchronously connect to a server * + * The function will return immediately. No error doesn't indicate that the + * connection is established. The current connection state has to be tracked + * by polling the \ref IedConnection_getState function or by using + * \ref IedConnection_StateChangedHandler + * * \param self the connection object * \param error the error code if an error occurs * \param hostname the host name or IP address of the server to connect to