- .NET API: Added destructor and Dispose method to ReportControlBlock

- .NET API: Changed ReportControlBlock access to IedConnection to improve stability when connection closes unexpectedly
pull/63/head
Michael Zillgith 7 years ago
parent a696e6e35e
commit 76ab1ec9f6

@ -371,6 +371,20 @@ namespace IEC61850
static extern IntPtr IedConnection_queryLogByTime (IntPtr self, out int error, string logReference, static extern IntPtr IedConnection_queryLogByTime (IntPtr self, out int error, string logReference,
ulong startTime, ulong endTime, out bool moreFollows); 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 * FileDirectoryEntry
@ -436,7 +450,6 @@ namespace IEC61850
public void Dispose() public void Dispose()
{ {
if (connection != IntPtr.Zero) { if (connection != IntPtr.Zero) {
cleanupRCBs ();
IedConnection_destroy (connection); IedConnection_destroy (connection);
@ -446,11 +459,7 @@ namespace IEC61850
~IedConnection () ~IedConnection ()
{ {
if (connection != IntPtr.Zero) { Dispose ();
cleanupRCBs ();
IedConnection_destroy (connection);
}
} }
private IsoConnectionParameters isoConnectionParameters = null; private IsoConnectionParameters isoConnectionParameters = null;
@ -1436,6 +1445,39 @@ namespace IEC61850
return newList; 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 public class IedConnectionException : Exception

@ -1,7 +1,7 @@
/* /*
* ReportControlBlock.cs * ReportControlBlock.cs
* *
* Copyright 2014 Michael Zillgith * Copyright 2014-2018 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -36,6 +36,9 @@ namespace IEC61850
/// </summary> /// </summary>
public delegate void ReportHandler (Report report, object parameter); public delegate void ReportHandler (Report report, object parameter);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void InternalReportHandler (IntPtr parameter, IntPtr report);
/// <summary> /// <summary>
/// Report control block (RCB) representation. /// Report control block (RCB) representation.
/// </summary> /// </summary>
@ -44,16 +47,13 @@ namespace IEC61850
/// Values from the server will only be read when the GetRCBValues method is called. /// 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. /// Values at the server are only affected when the SetRCBValues method is called.
/// </description> /// </description>
public class ReportControlBlock public class ReportControlBlock : IDisposable
{ {
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr ClientReportControlBlock_create (string dataAttributeReference); static extern IntPtr ClientReportControlBlock_create (string dataAttributeReference);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr IedConnection_getRCBValues (IntPtr connection, out int error, string rcbReference, IntPtr updateRcb); static extern void ClientReportControlBlock_destroy (IntPtr self);
[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)] [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)] [return: MarshalAs(UnmanagedType.I1)]
@ -147,18 +147,7 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr ClientReportControlBlock_getOwner (IntPtr self); 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 self;
private IntPtr connection;
private IedConnection iedConnection = null; private IedConnection iedConnection = null;
private string objectReference; private string objectReference;
private bool flagRptId = false; private bool flagRptId = false;
@ -221,14 +210,11 @@ namespace IEC61850
internal ReportControlBlock (string objectReference, IedConnection iedConnection, IntPtr connection) internal ReportControlBlock (string objectReference, IedConnection iedConnection, IntPtr connection)
{ {
self = ClientReportControlBlock_create (objectReference); self = ClientReportControlBlock_create (objectReference);
this.iedConnection = iedConnection;
this.connection = connection;
this.objectReference = objectReference;
}
internal void DisposeInternal() if (self != IntPtr.Zero) {
{ this.iedConnection = iedConnection;
IedConnection_uninstallReportHandler(connection, objectReference); this.objectReference = objectReference;
}
} }
/// <summary> /// <summary>
@ -239,11 +225,25 @@ namespace IEC61850
/// After calling <see cref="Dispose"/>, you must release all references to the /// After calling <see cref="Dispose"/>, you must release all references to the
/// <see cref="IEC61850.Client.ReportControlBlock"/> so the garbage collector can reclaim the memory that the /// <see cref="IEC61850.Client.ReportControlBlock"/> so the garbage collector can reclaim the memory that the
/// <see cref="IEC61850.Client.ReportControlBlock"/> was occupying.</remarks> /// <see cref="IEC61850.Client.ReportControlBlock"/> was occupying.</remarks>
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 () public string GetObjectReference ()
@ -279,9 +279,10 @@ namespace IEC61850
{ {
internalHandler = new InternalReportHandler(internalReportHandler); 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; int error;
IedConnection_getRCBValues (connection, out error, objectReference, self); iedConnection.GetRCBValues (out error, objectReference, self);
if (error != 0) if (error != 0)
throw new IedConnectionException ("getRCBValues service failed", error); throw new IedConnectionException ("getRCBValues service failed", error);
@ -370,7 +371,7 @@ namespace IEC61850
int error; int error;
IedConnection_setRCBValues (connection, out error, self, parametersMask, singleRequest); iedConnection.SetRCBValues (out error, self, parametersMask, singleRequest);
resetSendFlags(); resetSendFlags();

@ -35,17 +35,6 @@ namespace IEC61850
private List<ReportControlBlock> activeRCBs = null; private List<ReportControlBlock> activeRCBs = null;
private void cleanupRCBs()
{
if (activeRCBs != null) {
foreach (ReportControlBlock rcb in activeRCBs) {
rcb.DisposeInternal ();
}
}
}
public ReportControlBlock GetReportControlBlock (string rcbObjectReference) public ReportControlBlock GetReportControlBlock (string rcbObjectReference)
{ {
var newRCB = new ReportControlBlock (rcbObjectReference, this, connection); var newRCB = new ReportControlBlock (rcbObjectReference, this, connection);

Loading…
Cancel
Save