- .NET API: Added IDisposable interface to IedServer and IedModel classes

- .NET API: Added method IedModel.SetIedName
pull/331/head
Michael Zillgith 5 years ago
parent 35713550fb
commit cdd00da057

@ -54,7 +54,7 @@ namespace IEC61850
/// <summary>
/// Representation of the IED server data model
/// </summary>
public class IedModel
public class IedModel : IDisposable
{
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr IedModel_create(string name);
@ -71,6 +71,9 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern int ModelNode_getType(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedModel_setIedNameForDynamicModel(IntPtr self, string iedName);
internal IntPtr self = IntPtr.Zero;
internal IedModel(IntPtr self)
@ -87,24 +90,46 @@ namespace IEC61850
self = IedModel_create(name);
}
// causes undefined behavior
//~IedModel()
//{
// if (self != IntPtr.Zero)
// {
// IedModel_destroy(self);
// }
//}
~IedModel()
{
Dispose();
}
/// <summary>
/// Releases all resource used by the <see cref="IEC61850.Server.IedModel"/> object.
/// </summary>
public void Destroy()
{
Dispose();
}
/// <summary>
/// Releases all resource used by the <see cref="IEC61850.Server.IedModel"/> object.
/// </summary>
/// <remarks>Call <see cref="Dispose"/> when you are done using the <see cref="IEC61850.Server.IedModel"/>. The
/// <see cref="Dispose"/> method leaves the <see cref="IEC61850.Server.IedModel"/> in an unusable state. After
/// calling <see cref="Dispose"/>, you must release all references to the <see cref="IEC61850.Server.IedModel"/> so
/// the garbage collector can reclaim the memory that the <see cref="IEC61850.Server.IedModel"/> was occupying.</remarks>
public void Dispose()
{
lock (this)
{
if (self != IntPtr.Zero)
{
IedModel_destroy(self);
self = IntPtr.Zero;
}
}
}
public static IedModel CreateFromFile(string filePath)
/// <summary>
/// Creates a new <see cref="IEC61850.Server.IedModel"/> instance with the data model of <see langword="async"/> config file.
/// </summary>
/// <returns>new <see cref="IEC61850.Server.IedModel"/> instance</returns>
/// <param name="filename">fila name of the configuration (.cfg) file</param>
public static IedModel CreateFromFile(string filename)
{
return ConfigFileParser.CreateModelFromConfigFile(filePath);
return ConfigFileParser.CreateModelFromConfigFile(filename);
}
private ModelNode getModelNodeFromNodeRef(IntPtr nodeRef)
@ -129,6 +154,20 @@ namespace IEC61850
}
}
/// <summary>
/// Change the IED name of the data model
/// </summary>
/// <param name="iedName">the new IED name</param>
public void SetIedName(string iedName)
{
IedModel_setIedNameForDynamicModel(self, iedName);
}
/// <summary>
/// Gets the model node by full object reference.
/// </summary>
/// <returns>The model node</returns>
/// <param name="objectReference">Full object reference including the IED name</param>
public ModelNode GetModelNodeByObjectReference(string objectReference)
{
IntPtr nodeRef = IedModel_getModelNodeByObjectReference(self, objectReference);
@ -139,6 +178,11 @@ namespace IEC61850
return getModelNodeFromNodeRef (nodeRef);
}
/// <summary>
/// Gets the model node by short object reference (without IED name)
/// </summary>
/// <returns>The model node</returns>
/// <param name="objectReference">Object reference without IED name (e.g. LD0/GGIO1.Ind1.stVal)</param>
public ModelNode GetModelNodeByShortObjectReference(string objectReference)
{
IntPtr nodeRef = IedModel_getModelNodeByShortObjectReference(self, objectReference);
@ -148,6 +192,7 @@ namespace IEC61850
return getModelNodeFromNodeRef (nodeRef);
}
}
public class LogicalDevice : ModelNode
@ -1123,7 +1168,7 @@ namespace IEC61850
/// This class acts as the entry point for the IEC 61850 client API. It represents a single
/// (MMS) connection to a server.
/// </summary>
public class IedServer
public class IedServer : IDisposable
{
[DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr IedServer_createWithConfig(IntPtr modelRef, IntPtr tlsConfiguration, IntPtr serverConfiguratio);
@ -1387,8 +1432,13 @@ namespace IEC61850
internal Dictionary<IntPtr, ClientConnection> clientConnections = new Dictionary<IntPtr, ClientConnection> ();
/* store IedModel instance to prevent garbage collector */
private IedModel iedModel = null;
public IedServer(IedModel iedModel, IedServerConfig config = null)
{
this.iedModel = iedModel;
IntPtr nativeConfig = IntPtr.Zero;
if (config != null)
@ -1399,6 +1449,8 @@ namespace IEC61850
public IedServer(IedModel iedModel, TLSConfiguration tlsConfig, IedServerConfig config = null)
{
this.iedModel = iedModel;
IntPtr nativeConfig = IntPtr.Zero;
IntPtr nativeTLSConfig = IntPtr.Zero;
@ -1462,14 +1514,38 @@ namespace IEC61850
}
/// <summary>
/// Release all server resources.
/// Release all server resources (same as <see cref="Dispose"/>)
/// </summary>
/// <description>This function releases all MMS server resources.</description>
public void Destroy()
{
Dispose();
}
/// <summary>
/// Releases all resource used by the <see cref="IEC61850.Server.IedServer"/> object.
/// </summary>
/// <remarks>Call <see cref="Dispose"/> when you are done using the <see cref="IEC61850.Server.IedServer"/>. The
/// <see cref="Dispose"/> method leaves the <see cref="IEC61850.Server.IedServer"/> in an unusable state. After
/// calling <see cref="Dispose"/>, you must release all references to the <see cref="IEC61850.Server.IedServer"/> so
/// the garbage collector can reclaim the memory that the <see cref="IEC61850.Server.IedServer"/> was occupying.</remarks>
public void Dispose()
{
lock (this)
{
if (self != IntPtr.Zero)
{
IedServer_destroy(self);
self = IntPtr.Zero;
internalConnectionHandler = null;
this.iedModel = null;
}
}
}
~IedServer()
{
Dispose();
}
/// <summary>

@ -12,18 +12,22 @@ namespace server1
bool running = true;
/* run until Ctrl-C is pressed */
Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) {
Console.CancelKeyPress += delegate (object sender, ConsoleCancelEventArgs e)
{
e.Cancel = true;
running = false;
};
IedModel iedModel = ConfigFileParser.CreateModelFromConfigFile("model.cfg");
if (iedModel == null) {
if (iedModel == null)
{
Console.WriteLine("No valid data model found!");
return;
}
iedModel.SetIedName("TestIED");
DataObject spcso1 = (DataObject)iedModel.GetModelNodeByShortObjectReference("GenericIO/GGIO1.SPCSO1");
IedServerConfig config = new IedServerConfig();
@ -31,7 +35,8 @@ namespace server1
IedServer iedServer = new IedServer(iedModel, config);
iedServer.SetCheckHandler(spcso1, delegate(ControlAction action, object parameter, MmsValue ctlVal, bool test, bool interlockCheck) {
iedServer.SetCheckHandler(spcso1, delegate (ControlAction action, object parameter, MmsValue ctlVal, bool test, bool interlockCheck)
{
Console.WriteLine("Received binary control command:");
Console.WriteLine(" ctlNum: " + action.GetCtlNum());
@ -40,7 +45,8 @@ namespace server1
return CheckHandlerResult.ACCEPTED;
}, null);
iedServer.SetControlHandler (spcso1, delegate(ControlAction action, object parameter, MmsValue ctlVal, bool test) {
iedServer.SetControlHandler(spcso1, delegate (ControlAction action, object parameter, MmsValue ctlVal, bool test)
{
bool val = ctlVal.GetBoolean();
if (val)
@ -53,7 +59,8 @@ namespace server1
DataObject spcso2 = (DataObject)iedModel.GetModelNodeByShortObjectReference("GenericIO/GGIO1.SPCSO2");
iedServer.SetSelectStateChangedHandler (spcso2, delegate (ControlAction action, object parameter, bool isSelected, SelectStateChangedReason reason) {
iedServer.SetSelectStateChangedHandler(spcso2, delegate (ControlAction action, object parameter, bool isSelected, SelectStateChangedReason reason)
{
DataObject cObj = action.GetControlObject();
Console.WriteLine("Control object " + cObj.GetObjectReference() + (isSelected ? " selected" : " unselected") + " reason: " + reason.ToString());

@ -58,7 +58,7 @@ IedModel_create(const char* name/*, MemoryAllocator allocator*/);
/**
* \brief Set the name of the IED (use only for dynamic model!)
*
* This will change the default name (usualy "TEMPLATE") to a user configured values.
* This will change the default name (usually "TEMPLATE") to a user configured values.
* NOTE: This function has to be called before IedServer_create !
* NOTE: For dynamic model (and configuration file date model) this function has to be
* used instead of IedModel_setIedName.

Loading…
Cancel
Save