From 76ab1ec9f68e0c08bdba33cda55b66254828324c Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Fri, 27 Apr 2018 10:45:33 +0200 Subject: [PATCH] - .NET API: Added destructor and Dispose method to ReportControlBlock - .NET API: Changed ReportControlBlock access to IedConnection to improve stability when connection closes unexpectedly --- dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs | 54 ++++++++++++++-- .../IEC61850forCSharp/ReportControlBlock.cs | 63 ++++++++++--------- dotnet/IEC61850forCSharp/Reporting.cs | 11 ---- 3 files changed, 80 insertions(+), 48 deletions(-) diff --git a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs index b17317c4..236439fc 100644 --- a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs @@ -371,6 +371,20 @@ namespace IEC61850 static extern IntPtr IedConnection_queryLogByTime (IntPtr self, out int error, string logReference, ulong startTime, ulong endTime, out bool moreFollows); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_getRCBValues (IntPtr connection, out int error, string rcbReference, IntPtr updateRcb); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_setRCBValues (IntPtr connection, out int error, IntPtr rcb, UInt32 parametersMask, bool singleRequest); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_installReportHandler (IntPtr connection, string rcbReference, string rptId, InternalReportHandler handler, + IntPtr handlerParameter); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedConnection_uninstallReportHandler(IntPtr connection, string rcbReference); + /******************** * FileDirectoryEntry @@ -436,7 +450,6 @@ namespace IEC61850 public void Dispose() { if (connection != IntPtr.Zero) { - cleanupRCBs (); IedConnection_destroy (connection); @@ -446,11 +459,7 @@ namespace IEC61850 ~IedConnection () { - if (connection != IntPtr.Zero) { - cleanupRCBs (); - - IedConnection_destroy (connection); - } + Dispose (); } private IsoConnectionParameters isoConnectionParameters = null; @@ -1436,6 +1445,39 @@ namespace IEC61850 return newList; } + + internal void UninstallReportHandler (string objectReference) + { + if (connection != IntPtr.Zero) { + IedConnection_uninstallReportHandler (connection, objectReference); + } + } + + internal void InstallReportHandler (string objectReference, string reportId, InternalReportHandler internalHandler) + { + if (connection != IntPtr.Zero) { + IedConnection_installReportHandler (connection, objectReference, reportId, internalHandler, IntPtr.Zero); + } + } + + internal void GetRCBValues(out int error, string objectReference, IntPtr updateRcb) + { + if (connection != IntPtr.Zero) { + IedConnection_getRCBValues (connection, out error, objectReference, updateRcb); + } else { + error = 1; /* not connected */ + } + } + + internal void SetRCBValues(out int error, IntPtr rcb, UInt32 parametersMask, bool singleRequest) + { + if (connection != IntPtr.Zero) { + IedConnection_setRCBValues (connection, out error, rcb, parametersMask, singleRequest); + } else { + error = 1; /* not connected */ + } + } + } public class IedConnectionException : Exception diff --git a/dotnet/IEC61850forCSharp/ReportControlBlock.cs b/dotnet/IEC61850forCSharp/ReportControlBlock.cs index ad9f5da3..7d13a674 100644 --- a/dotnet/IEC61850forCSharp/ReportControlBlock.cs +++ b/dotnet/IEC61850forCSharp/ReportControlBlock.cs @@ -1,7 +1,7 @@ /* * ReportControlBlock.cs * - * Copyright 2014 Michael Zillgith + * Copyright 2014-2018 Michael Zillgith * * This file is part of libIEC61850. * @@ -36,6 +36,9 @@ namespace IEC61850 /// public delegate void ReportHandler (Report report, object parameter); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate void InternalReportHandler (IntPtr parameter, IntPtr report); + /// /// Report control block (RCB) representation. /// @@ -44,16 +47,13 @@ namespace IEC61850 /// Values from the server will only be read when the GetRCBValues method is called. /// Values at the server are only affected when the SetRCBValues method is called. /// - public class ReportControlBlock + public class ReportControlBlock : IDisposable { [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern IntPtr ClientReportControlBlock_create (string dataAttributeReference); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern IntPtr IedConnection_getRCBValues (IntPtr connection, out int error, string rcbReference, IntPtr updateRcb); - - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern void IedConnection_setRCBValues (IntPtr connection, out int error, IntPtr rcb, UInt32 parametersMask, bool singleRequest); + static extern void ClientReportControlBlock_destroy (IntPtr self); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.I1)] @@ -147,18 +147,7 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern IntPtr ClientReportControlBlock_getOwner (IntPtr self); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern void IedConnection_installReportHandler (IntPtr connection, string rcbReference, string rptId, InternalReportHandler handler, - IntPtr handlerParameter); - - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern void IedConnection_uninstallReportHandler(IntPtr connection, string rcbReference); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void InternalReportHandler (IntPtr parameter, IntPtr report); - private IntPtr self; - private IntPtr connection; private IedConnection iedConnection = null; private string objectReference; private bool flagRptId = false; @@ -221,14 +210,11 @@ namespace IEC61850 internal ReportControlBlock (string objectReference, IedConnection iedConnection, IntPtr connection) { self = ClientReportControlBlock_create (objectReference); - this.iedConnection = iedConnection; - this.connection = connection; - this.objectReference = objectReference; - } - internal void DisposeInternal() - { - IedConnection_uninstallReportHandler(connection, objectReference); + if (self != IntPtr.Zero) { + this.iedConnection = iedConnection; + this.objectReference = objectReference; + } } /// @@ -239,11 +225,25 @@ namespace IEC61850 /// After calling , you must release all references to the /// so the garbage collector can reclaim the memory that the /// was occupying. - public void Dispose() + public void Dispose() { - DisposeInternal (); + lock (this) { + if (self != IntPtr.Zero) { + + iedConnection.UninstallReportHandler (objectReference); + + iedConnection.RemoveRCB (this); + + ClientReportControlBlock_destroy (self); - iedConnection.RemoveRCB (this); + self = IntPtr.Zero; + } + } + } + + ~ReportControlBlock() + { + Dispose (); } public string GetObjectReference () @@ -279,9 +279,10 @@ namespace IEC61850 { internalHandler = new InternalReportHandler(internalReportHandler); } + + iedConnection.InstallReportHandler (objectReference, reportId, internalHandler); - IedConnection_installReportHandler(this.connection, objectReference, reportId, internalHandler, IntPtr.Zero); - reportHandlerInstalled = true; + reportHandlerInstalled = true; } } @@ -293,7 +294,7 @@ namespace IEC61850 { int error; - IedConnection_getRCBValues (connection, out error, objectReference, self); + iedConnection.GetRCBValues (out error, objectReference, self); if (error != 0) throw new IedConnectionException ("getRCBValues service failed", error); @@ -370,7 +371,7 @@ namespace IEC61850 int error; - IedConnection_setRCBValues (connection, out error, self, parametersMask, singleRequest); + iedConnection.SetRCBValues (out error, self, parametersMask, singleRequest); resetSendFlags(); diff --git a/dotnet/IEC61850forCSharp/Reporting.cs b/dotnet/IEC61850forCSharp/Reporting.cs index dfbf6d6b..90ddba2d 100644 --- a/dotnet/IEC61850forCSharp/Reporting.cs +++ b/dotnet/IEC61850forCSharp/Reporting.cs @@ -35,17 +35,6 @@ namespace IEC61850 private List activeRCBs = null; - private void cleanupRCBs() - { - if (activeRCBs != null) { - - foreach (ReportControlBlock rcb in activeRCBs) { - rcb.DisposeInternal (); - } - } - - } - public ReportControlBlock GetReportControlBlock (string rcbObjectReference) { var newRCB = new ReportControlBlock (rcbObjectReference, this, connection);