Merged in v1.6_develop_394 (pull request #4)

V1.6 develop 394

Approved-by: Michael Zillgith
v1.6
Maxson Anjos 1 month ago committed by Michael Zillgith
commit aa9a8dc2de

@ -1,8 +1,11 @@
Changes to version 1.6.1
------------------------
New features and improvements:
- .NET API: SVControlBlock added
- .NET API: Added additional callbacks to control external access to the data model (required to implement RBAC)
- .NET API: IEC61850ServerAPI -> LogStorage function wrapper added.
- .NET API: MmsValue -> MmsValue_encodeMmsData and MmsValue_decodeMmsData added.
- .NET API: Fixed issue of not printing log entries in log_client and log_server examples.

@ -0,0 +1,95 @@
/*
* IEC61850ServerAPI.cs
*
* Copyright 2016-2025 Michael Zillgith
*
* This file is part of libIEC61850.
*
* libIEC61850 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* libIEC61850 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with libIEC61850. If not, see <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/
using IEC61850.Server;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
// IEC 61850 API for the libiec61850 .NET wrapper library
namespace IEC61850
{
// IEC 61850 server API.
namespace Model
{
public enum SMVEvent
{
IEC61850_SVCB_EVENT_ENABLE = 1,
IEC61850_SVCB_EVENT_DISABLE = 0,
}
public class SVControlBlock : ModelNode
{
private IntPtr self = IntPtr.Zero;
public IedModel parent { get; }
internal IntPtr Self { get => self; }
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr SVControlBlock_create(string name, IntPtr parent, string svID,string dataSet, UInt32 confRev, uint smpMod,
UInt16 smpRate, uint optFlds, bool isUnicast);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr SVControlBlock_getName(IntPtr self);
/// <summary>
/// create a new Multicast/Unicast Sampled Value (SV) control block (SvCB)
/// Create a new Sampled Value control block(SvCB) and add it to the given logical node(LN)
/// </summary>
/// <param name="name">name of the SvCB relative to the parent LN</param>
/// <param name="parent">the parent LN</param>
/// <param name="svID">the application ID of the SvCB</param>
/// <param name="dataSet">the data set reference to be used by the SVCB</param>
/// <param name="confRev">the configuration revision</param>
/// <param name="smpMod">the sampling mode used</param>
/// <param name="smpRate">the sampling rate used</param>
/// <param name="optFlds"></param>
/// <param name="isUnicast">the optional element configuration</param>
public SVControlBlock(string name, IedModel parent, string svID, string dataSet, UInt32 confRev, uint smpMod,
UInt16 smpRate, uint optFlds, bool isUnicast)
{
this.self = SVControlBlock_create(name, parent.self, svID, dataSet, confRev, smpMod, smpRate, optFlds, isUnicast);
this.parent = parent;
}
/// <summary>
/// create a new Multicast/Unicast Sampled Value (SV) control block (SvCB)
/// Create a new Sampled Value control block(SvCB) and add it to the given logical node(LN)
/// </summary>
/// <param name="self">the svcontrol instance</param>
public SVControlBlock(IntPtr self)
{
this.self = self;
}
public string Name
{
get
{
return Marshal.PtrToStringAnsi(SVControlBlock_getName(self));
}
}
}
}
}

@ -22,10 +22,18 @@
*/
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Xml.Linq;
using IEC61850.Client;
using IEC61850.Common;
using IEC61850.Model;
using IEC61850.TLS;
using static System.Collections.Specialized.BitVector32;
using static System.Net.Mime.MediaTypeNames;
using static IEC61850.Client.IedConnection;
// IEC 61850 API for the libiec61850 .NET wrapper library
@ -79,6 +87,9 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr IedModel_getDeviceByInst(IntPtr self, string ldInst);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr IedModel_getSVControlBlock(IntPtr self, IntPtr parentLN, string svcbName);
internal IntPtr self = IntPtr.Zero;
internal IedModel(IntPtr self)
@ -299,6 +310,16 @@ namespace IEC61850
return GetModelNodeFromNodeRef (nodeRef);
}
public SVControlBlock GetSVControlBlock(LogicalNode logicalNode, string svcbName)
{
IntPtr nodeRef = IedModel_getSVControlBlock(self, logicalNode.self, svcbName);
if (nodeRef == IntPtr.Zero)
return null;
return new SVControlBlock(nodeRef);
}
}
/// <summary>
@ -312,6 +333,9 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr LogicalDevice_createEx(string name, IntPtr parent, string ldName);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr LogicalDevice_getSettingGroupControlBlock(IntPtr self);
public IedModel IedModel { get; }
public LogicalDevice (IntPtr self, IedModel iedModel) : base (self)
@ -343,6 +367,20 @@ namespace IEC61850
self = LogicalDevice_createEx(inst, parent.self, ldName);
}
/// <summary>
/// Get the setting group control block (SGCB) of the logical device
/// </summary>
/// <returns>the SGCB instance or NULL if no SGCB is available</returns>
public SettingGroupControlBlock GetSettingGroupControlBlock()
{
IntPtr sgcb = LogicalDevice_getSettingGroupControlBlock(this.self);
if(sgcb == IntPtr.Zero)
return null;
return new SettingGroupControlBlock(sgcb);
}
}
/// <summary>
@ -904,6 +942,9 @@ namespace IEC61850
{
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr DataObject_create(string name, IntPtr parent, int arrayElements);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr ModelNode_getChildWithFc(IntPtr self, string objectReference, int fc);
internal DataObject(IntPtr self, ModelNode parent) : base(self)
{
@ -921,6 +962,28 @@ namespace IEC61850
self = DataObject_create (name, parent.self, arrayElements);
}
/// <summary>
/// return a child model node with a given functional constraint
/// Sometimes the name is not enough to identify a model node.This is the case when
/// editable setting groups are used.In this case the setting group members have two different
/// model nodes associated that differ in their FC (SG and SE).
/// </summary>
/// <param name="objectReference">the name of the child model node</param>
/// <param name="fc">the functional constraint of the model node</param>
/// <returns>the model node instance or NULL if model node does not exist.</returns>
public DataAttribute GetChildWithFc(string objRef, FunctionalConstraint fc)
{
DataAttribute dataAttribute = null;
IntPtr da = ModelNode_getChildWithFc(this.self, objRef, (int)fc);
if (da != IntPtr.Zero)
{
dataAttribute = new DataAttribute(da, this);
}
return dataAttribute;
}
}
public class DataAttribute : ModelNode
@ -1686,6 +1749,11 @@ namespace IEC61850
{
self = SettingGroupControlBlock_create(parent.self, (byte) actSG, (byte) numOfSGs);
}
public SettingGroupControlBlock(IntPtr self)
{
this.self = self ;
}
}
public class ClientConnection
@ -2154,6 +2222,21 @@ namespace IEC61850
OBJECT_UNDEFINED = 4
}
public enum ControlBlockAccessType
{
IEC61850_CB_ACCESS_TYPE_READ,
IEC61850_CB_ACCESS_TYPE_WRITE
}
public enum DataSetOperation
{
DATASET_CREATE,
DATASET_DELETE,
DATASET_READ,
DATASET_WRITE,
DATASET_GET_DIRECTORY
}
public delegate CheckHandlerResult CheckHandler (ControlAction action, object parameter, MmsValue ctlVal, bool test, bool interlockCheck);
public static class SqliteLogStorage
@ -2389,6 +2472,177 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
public static extern void IedServer_setListObjectsAccessHandler(IntPtr self, IedServer_ListObjectsAccessHandler handler, IntPtr parameter);
/// <summary>
/// Set a handler to control read and write access to control blocks and logs
/// </summary>
/// <param name="self">IedServer</param>
/// <param name="handler">handler the callback handler to be used</param>
/// <param name="parameter">a user provided parameter that is passed to the handler</param>
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
public static extern void IedServer_setControlBlockAccessHandler(IntPtr self, IedServer_ControlBlockAccessHandler handler, IntPtr parameter);
/// <summary>
/// Install the global read access handler
/// The read access handler will be called for every read access before the server grants access to the client
/// </summary>
/// <param name="self">IedServer</param>
/// <param name="handler">the callback function that is invoked if a client tries to read a data object</param>
/// <param name="parameter">a user provided parameter that is passed to the callback function</param>
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
public static extern void IedServer_setReadAccessHandler(IntPtr self, ReadAccessHandler handler, IntPtr parameter);
/// <summary>
/// Set a handler to control access to a dataset (create, delete, read, write, list directory)
/// </summary>
/// <param name="self">IedServer</param>
/// <param name="handler">the callback handler to be used</param>
/// <param name="parameter">a user provided parameter that is passed to the handler</param>
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
public static extern void IedServer_setDataSetAccessHandler(IntPtr self, IedServer_DataSetAccessHandler handler, IntPtr parameter);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
public static extern void IedServer_setDirectoryAccessHandler(IntPtr self, IedServer_DirectoryAccessHandler handler, IntPtr parameter);
/// <summary>
/// Set the callback handler for the SetActSG event
/// </summary>
/// <param name="self">the instance of IedServer to operate on</param>
/// <param name="sgcb">the handle of the setting group control block of the setting group</param>
/// <param name="handler">the user provided callback handler</param>
/// <param name="parameter">a user provided parameter that is passed to the control handler</param>
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
public static extern void IedServer_setActiveSettingGroupChangedHandler(IntPtr self, IntPtr sgcb, ActiveSettingGroupChangedHandler handler, IntPtr parameter);
/// <summary>
/// Get the active setting group number
/// </summary>
/// <param name="self">the instance of IedServer to operate on</param>
/// <param name="sgcb">the handle of the setting group control block of the setting group</param>
/// <returns>the number of the active setting group</returns>
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
public static extern uint IedServer_getActiveSettingGroup(IntPtr self, IntPtr sgcb);
/// <summary>
/// Set the callback handler for the SetEditSG event
/// </summary>
/// <param name="self">the instance of IedServer to operate on</param>
/// <param name="sgcb">the handle of the setting group control block of the setting group</param>
/// <param name="handler">the user provided callback handler</param>
/// <param name="parameter">a user provided parameter that is passed to the control handler</param>
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
public static extern void IedServer_setEditSettingGroupChangedHandler(IntPtr self, IntPtr sgcb, EditSettingGroupChangedHandler handler, IntPtr parameter);
/// <summary>
/// Set the callback handler for the COnfEditSG event
/// </summary>
/// <param name="self">the instance of IedServer to operate on</param>
/// <param name="sgcb">the handle of the setting group control block of the setting group</param>
/// <param name="handler">the user provided callback handler</param>
/// <param name="parameter">a user provided parameter that is passed to the control handler</param>
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
public static extern void IedServer_setEditSettingGroupConfirmationHandler(IntPtr self, IntPtr sgcb, EditSettingGroupConfirmationHandler handler, IntPtr parameter);
///// <summary>
///// Set a handler for SVCB control block events (enable/disable)
///// </summary>
///// <param name="self">the instance of IedServer to operate on.</param>
///// <param name="svcb">the SVCB control block instance</param>
///// <param name="handler">the event handler to be used</param>
///// <param name="parameter">user provided parameter that is passed to the handler</param>
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
public static extern void IedServer_setSVCBHandler(IntPtr self, IntPtr svcb, SVCBEventHandler handler, IntPtr parameter);
///// <summary>
///// callback handler for SVCB events
///// </summary>
///// <param name="svcb">the related SVCB instance</param>
///// <param name="eventType">event type</param>
///// <param name="parameter">user defined parameter</param>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void SVCBEventHandler(IntPtr svcb, int eventType, IntPtr parameter);
/// <summary>
/// callback handler to control client read access to data attributes
/// User provided callback function to control MMS client read access to IEC 61850
/// data objects.The application is to allow read access to data objects for specific clients only.
/// It can be used to implement a role based access control (RBAC).
/// </summary>
/// <param name="ld">the logical device the client wants to access</param>
/// <param name="ln">the logical node the client wants to access</param>
/// <param name="dataObject">the data object the client wants to access</param>
/// <param name="fc">the functional constraint of the access</param>
/// <param name="connection">the client connection that causes the access</param>
/// <param name="parameter">the user provided parameter</param>
/// <returns>DATA_ACCESS_ERROR_SUCCESS if access is accepted, DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED if access is denied</returns>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate MmsDataAccessError ReadAccessHandler(IntPtr ld, IntPtr ln, IntPtr dataObject, int fc, IntPtr connection, IntPtr parameter);
/// <summary>
/// Callback handler that is invoked when the active setting group is about to be changed by an external client.
/// This function is called BEFORE the active setting group is changed. The user can reject to change the active setting group by returning false.
/// </summary>
/// <param name="parameter">user provided parameter</param>
/// <param name="sgcb">sgcb the setting group control block of the setting group that is about to be changed</param>
/// <param name="newActSg">newActSg the new active setting group</param>
/// <param name="connection">connection the client connection that requests the change</param>
/// <returns>true if the change is accepted, false otherwise</returns>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate bool ActiveSettingGroupChangedHandler(IntPtr parameter, IntPtr sgcb, uint newActSg, IntPtr connection);
/// <summary>
/// Callback handler that is invoked when the edit setting group is about to be changed by an external client.
/// In this function the user should update all SE data attributes associated with the given SettingGroupControlBlock.
/// This function is called BEFORE the active setting group is changed.The user can reject to change the
/// edit setting group by returning false. This can be used to implement RBAC.
/// </summary>
/// <param name="parameter">user provided parameter</param>
/// <param name="sgcb">the setting group control block of the setting group that is about to be changed</param>
/// <param name="newEditSg">the new edit setting group</param>
/// <param name="connection">the client connection that requests the change</param>
/// <returns>true if the change is accepted, false otherwise</returns>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate bool EditSettingGroupChangedHandler(IntPtr parameter, IntPtr sgcb, uint newEditSg, IntPtr connection);
/// <summary>
/// Callback handler that is invoked when the edit setting group has been confirmed by an external client.
/// </summary>
/// <param name="parameter">user provided parameter</param>
/// <param name="sgcb">the setting group control block of the setting group that is about to be changed</param>
/// <param name="editSg">the edit setting group that has been confirmed</param>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void EditSettingGroupConfirmationHandler(IntPtr parameter, IntPtr sgcb, uint editSg);
/// <summary>
/// Callback that is called when the client is calling a dataset operation (create, delete, read, write, list directory)
/// his callback is called before the IedServer_RCBEventHandler and only in case of operations (RCB_EVENT_GET_PARAMETER, RCB_EVENT_SET_PARAMETER, RCB_EVENT_ENABLE
/// </summary>
/// <param name="parameter">user provided parameter</param>
/// <param name="connection">client connection that is involved</param>
/// <param name="operation">one of the following operation types: DATASET_CREATE, DATASET_DELETE, DATASET_READ, DATASET_WRITE, DATASET_GET_DIRECTORY</param>
/// <param name="datasetRef"></param>
/// <returns>true to allow operation, false to deny operation</returns>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate bool IedServer_DataSetAccessHandler(IntPtr parameter, IntPtr connection, int operation, string datasetRef);
/// <summary>
/// Callback that is called when a client is invoking a read or write service to a control block or log
/// This callback can be used to control the read and write access to control blocks and logs (SGCB, LCBs, URCBs, BRCBs, GoCBs, SVCBs, logs)
/// </summary>
/// <param name="parameter">user provided parameter</param>
/// <param name="connection">client connection that is involved</param>
/// <param name="acsiClass">the ACSI class of the object</param>
/// <param name="ld">the logical device of the object</param>
/// <param name="ln">the logical node of the object</param>
/// <param name="objectName">the name of the object (e.g. data object name, data set name, log name, RCB name, ...)</param>
/// <param name="subObjectName">the name of a sub element of an object or NULL</param>
/// <param name="accessType">access type (read=IEC61850_CB_ACCESS_TYPE_READ or write=IEC61850_CB_ACCESS_TYPE_WRITE)</param>
/// <returns>true to include the object in the service response, otherwise false</returns>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate bool IedServer_ControlBlockAccessHandler(IntPtr parameter, IntPtr connection, int acsiClass, IntPtr ld, IntPtr ln, string objectName, string subObjectName, int accessType);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate bool IedServer_DirectoryAccessHandler(IntPtr parameter, IntPtr connection, int category, IntPtr logicalDevice);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate bool IedServer_ListObjectsAccessHandler(IntPtr parameter, ClientConnection connection, ACSIClass acsiClass, LogicalDevice ld, LogicalNode ln, string objectName, string subObjectName, FunctionalConstraint fc);
@ -2615,11 +2869,364 @@ namespace IEC61850
}
}
public void SetListObjectsAccessHandler(IedServer_ListObjectsAccessHandler handler, System.IntPtr parameter)
public void SetListObjectsAccessHandler(IedServer_ListObjectsAccessHandler handler, IntPtr parameter)
{
IedServer_setListObjectsAccessHandler(self, handler, parameter);
}
public delegate bool ControlBlockAccessHandler(object parameter, ClientConnection connection, ACSIClass acsiClass, LogicalDevice ld, LogicalNode ln, string objectName, string subObjectName, ControlBlockAccessType accessType);
private ControlBlockAccessHandler rcbControlHandler = null;
private object rcbControlHandlerParameter = null;
private IedServer_ControlBlockAccessHandler internalRCBControlHandler = null;
private bool InternalRCBControlHandlerImplementation(IntPtr parameter, IntPtr connection, int acsiClass, IntPtr ld, IntPtr ln, string objectName, string subObjectName, int accessType)
{
if (rcbControlHandler != null && connection != IntPtr.Zero && ld != IntPtr.Zero && ln != IntPtr.Zero)
{
ClientConnection con = null;
this.clientConnections.TryGetValue(connection, out con);
ModelNode ldModelNode = iedModel.GetModelNodeFromNodeRef(ld);
ModelNode lnModelNode = iedModel.GetModelNodeFromNodeRef(ln);
return rcbControlHandler(rcbControlHandlerParameter, con, (ACSIClass)acsiClass, ldModelNode as LogicalDevice, lnModelNode as LogicalNode, objectName, subObjectName, (ControlBlockAccessType)accessType);
}
return false;
}
/// <summary>
/// Set a handler to control read and write access to control blocks and logs
/// </summary>
/// <param name="handler">the callback handler to be used</param>
/// <param name="parameter">a user provided parameter that is passed to the handler</param>
public void SetControlBlockAccessHandler(ControlBlockAccessHandler handler, object parameter)
{
rcbControlHandler = handler;
rcbControlHandlerParameter = parameter;
if (internalRCBControlHandler == null)
{
internalRCBControlHandler = new IedServer_ControlBlockAccessHandler(InternalRCBControlHandlerImplementation);
IedServer_setControlBlockAccessHandler(self, internalRCBControlHandler, IntPtr.Zero);
}
}
public delegate bool DataSetAccessHandler(object parameter, ClientConnection connection, DataSetOperation operation, string datasetRef);
private DataSetAccessHandler dataSetAccessHandler = null;
private object dataSetAccessHandlerParameter = null;
private IedServer_DataSetAccessHandler internalDataSetAccessHandler = null;
/// <summary>
/// Callback that is called when the client is calling a dataset operation (create, delete, read, write, list directory)
/// note This callback is called before the IedServer_RCBEventHandler and only in case of operations(RCB_EVENT_GET_PARAMETER, RCB_EVENT_SET_PARAMETER, RCB_EVENT_ENABLE
/// </summary>
/// <param name="handler">the callback handler to be used</param>
/// <param name="parameter">a user provided parameter that is passed to the handler</param>
public void SetDataSetAccessHandler(DataSetAccessHandler handler, object parameter)
{
dataSetAccessHandler = handler;
dataSetAccessHandlerParameter = parameter;
if (internalDataSetAccessHandler == null)
{
internalDataSetAccessHandler = new IedServer_DataSetAccessHandler(InternalDataSetlHandlerImplementation);
IedServer_setDataSetAccessHandler(self, internalDataSetAccessHandler, IntPtr.Zero);
}
}
private bool InternalDataSetlHandlerImplementation (IntPtr parameter, IntPtr connection, int operation, string datasetRef)
{
if (dataSetAccessHandler != null && connection != IntPtr.Zero)
{
ClientConnection con = null;
this.clientConnections.TryGetValue(connection, out con);
return dataSetAccessHandler(dataSetAccessHandlerParameter, con, (DataSetOperation)operation, datasetRef);
}
return false;
}
//------------- Setting group
public delegate bool InternalActiveSettingGroupChangedHandler(object parameter, SettingGroupControlBlock sgcb, uint newActSg, ClientConnection connection);
private InternalActiveSettingGroupChangedHandler internalActiveSettingGroupChangedHandler = null;
private object activeSettingGroupChangedHandlerParameter = null;
private ActiveSettingGroupChangedHandler activeSettingGroupChangedHandler = null;
public void SetActiveSettingGroupChangedHandler(InternalActiveSettingGroupChangedHandler handler,SettingGroupControlBlock settingGroupControlBlock, object parameter)
{
internalActiveSettingGroupChangedHandler = handler;
activeSettingGroupChangedHandlerParameter = parameter;
if (activeSettingGroupChangedHandler == null)
{
activeSettingGroupChangedHandler = new ActiveSettingGroupChangedHandler(InternalActiveSettingGroupChangedImplementation);
IedServer_setActiveSettingGroupChangedHandler(self, settingGroupControlBlock.self, activeSettingGroupChangedHandler, IntPtr.Zero);
}
}
public int GetActiveSettingGroupChangedHandler(SettingGroupControlBlock settingGroupControlBlock)
{
return Convert.ToInt32(IedServer_getActiveSettingGroup(self, settingGroupControlBlock.self));
}
private bool InternalActiveSettingGroupChangedImplementation(IntPtr parameter, IntPtr sgcb, uint newActSg, IntPtr connection)
{
if (sgcb != IntPtr.Zero && connection != IntPtr.Zero)
{
ClientConnection con = null;
this.clientConnections.TryGetValue(connection, out con);
return internalActiveSettingGroupChangedHandler(activeSettingGroupChangedHandlerParameter, new SettingGroupControlBlock(sgcb), newActSg, con);
}
return false;
}
public delegate bool InternalEditSettingGroupChangedHandler(object parameter, SettingGroupControlBlock sgcb, uint newEditSg, ClientConnection connection);
private InternalEditSettingGroupChangedHandler internalEditSettingGroupChangedHandler = null;
private object editSettingGroupChangedHandlerParameter = null;
private EditSettingGroupChangedHandler editSettingGroupChangedHandler = null;
public void SetEditSettingGroupChangedHandler(InternalEditSettingGroupChangedHandler handler, SettingGroupControlBlock settingGroupControlBlock, object parameter)
{
internalEditSettingGroupChangedHandler = handler;
editSettingGroupChangedHandlerParameter = parameter;
if (editSettingGroupChangedHandler == null)
{
editSettingGroupChangedHandler = new EditSettingGroupChangedHandler(InternalEditSettingGroupChangedImplementation);
IedServer_setEditSettingGroupChangedHandler(self, settingGroupControlBlock.self, editSettingGroupChangedHandler, IntPtr.Zero);
}
}
private bool InternalEditSettingGroupChangedImplementation(IntPtr parameter, IntPtr sgcb, uint newEditSg, IntPtr connection)
{
if (sgcb != IntPtr.Zero && connection != IntPtr.Zero)
{
ClientConnection con = null;
this.clientConnections.TryGetValue(connection, out con);
return internalEditSettingGroupChangedHandler(editSettingGroupChangedHandlerParameter, new SettingGroupControlBlock(sgcb), newEditSg, con);
}
return false;
}
public delegate void InternalEditSettingGroupConfirmationHandler(object parameter, SettingGroupControlBlock sgcb, uint editSg);
private InternalEditSettingGroupConfirmationHandler internalEditSettingGroupConfirmationHandler = null;
private object editSettingGroupConfirmationHandlerParameter = null;
private EditSettingGroupConfirmationHandler editSettingGroupConfirmationHandler = null;
public void SetEditSettingGroupConfirmationHandler(InternalEditSettingGroupConfirmationHandler handler, SettingGroupControlBlock settingGroupControlBlock, object parameter)
{
internalEditSettingGroupConfirmationHandler = handler;
editSettingGroupConfirmationHandlerParameter = parameter;
if (editSettingGroupConfirmationHandler == null)
{
editSettingGroupConfirmationHandler = new EditSettingGroupConfirmationHandler(InternalEditSettingGroupConfirmationImplementation);
IedServer_setEditSettingGroupConfirmationHandler(self, settingGroupControlBlock.self, editSettingGroupConfirmationHandler, IntPtr.Zero);
}
}
private void InternalEditSettingGroupConfirmationImplementation(IntPtr parameter, IntPtr sgcb, uint editSg)
{
if (sgcb != IntPtr.Zero)
{
internalEditSettingGroupConfirmationHandler(editSettingGroupChangedHandlerParameter, new SettingGroupControlBlock(sgcb), editSg);
}
}
//------------
public delegate void InternalSVCBEventHandler(SVControlBlock sampledValuesControlBlock, SMVEvent sMVEvent, object parameter);
private InternalSVCBEventHandler internalSVCBEventHandler = null;
private object sVCBEventHandlerParameter = null;
private SVCBEventHandler sVCBEventHandler = null;
internal class SVCHandlerInfo
{
public SVControlBlock sampledValuesControlBlock = null;
public GCHandle handle;
public InternalSVCBEventHandler internalSVCBEventHandler = null;
public object svcHandlerParameter = null;
public SVCHandlerInfo(SVControlBlock sampledValuesControlBlock)
{
this.sampledValuesControlBlock = sampledValuesControlBlock;
this.handle = GCHandle.Alloc(this);
}
~SVCHandlerInfo()
{
this.handle.Free();
}
}
private Dictionary<SVControlBlock, SVCHandlerInfo> svcHandlers = new Dictionary<SVControlBlock, SVCHandlerInfo>();
private SVCHandlerInfo GetSVCHandlerInfo(SVControlBlock sampledValuesControlBlock)
{
SVCHandlerInfo info;
svcHandlers.TryGetValue(sampledValuesControlBlock, out info);
if (info == null)
{
info = new SVCHandlerInfo(sampledValuesControlBlock);
svcHandlers.Add(sampledValuesControlBlock, info);
}
return info;
}
public void SetSVCBHandler(InternalSVCBEventHandler handler, SVControlBlock sampledValuesControlBlock, object parameter)
{
SVCHandlerInfo info = GetSVCHandlerInfo(sampledValuesControlBlock);
info.internalSVCBEventHandler = handler;
info.svcHandlerParameter = parameter;
if (sVCBEventHandler == null)
sVCBEventHandler = new SVCBEventHandler(InternalSVCBEventHandlerImplementation);
IedServer_setSVCBHandler(self, sampledValuesControlBlock.Self, sVCBEventHandler, GCHandle.ToIntPtr(info.handle));
}
private void InternalSVCBEventHandlerImplementation(IntPtr svcb, int eventType, IntPtr parameter)
{
GCHandle handle = GCHandle.FromIntPtr(parameter);
SVCHandlerInfo info = (SVCHandlerInfo)handle.Target;
if (info != null && info.internalSVCBEventHandler != null)
info.internalSVCBEventHandler(info.sampledValuesControlBlock, (SMVEvent)eventType, info.svcHandlerParameter);
}
public delegate MmsDataAccessError InternalReadAccessHandler(LogicalDevice ld, LogicalNode ln, DataObject dataObject, FunctionalConstraint fc, ClientConnection connection, object parameter);
private InternalReadAccessHandler internalReadAccessHandler = null;
private object internalReadAccessHandlerParameter = null;
private ReadAccessHandler readAccessHandler = null;
public void SetReadAccessHandler(InternalReadAccessHandler handler, object parameter)
{
internalReadAccessHandler = handler;
internalReadAccessHandlerParameter = parameter;
if (readAccessHandler == null)
{
readAccessHandler = new ReadAccessHandler (InternalReadHandlerImplementation);
IedServer_setReadAccessHandler(self, readAccessHandler, IntPtr.Zero);
}
}
private MmsDataAccessError InternalReadHandlerImplementation(IntPtr ld, IntPtr ln, IntPtr dataObject, int fc, IntPtr connection, IntPtr parameter)
{
if (internalReadAccessHandler != null && ld != IntPtr.Zero && ln != IntPtr.Zero && connection != IntPtr.Zero)
{
ClientConnection con = null;
this.clientConnections.TryGetValue(connection, out con);
ModelNode ldModelNode = iedModel.GetModelNodeFromNodeRef(ld);
ModelNode lnModelNode = iedModel.GetModelNodeFromNodeRef(ln);
ModelNode doModelNode = null;
if(dataObject != IntPtr.Zero)
doModelNode = iedModel.GetModelNodeFromNodeRef(dataObject);
return internalReadAccessHandler(ldModelNode as LogicalDevice, lnModelNode as LogicalNode, doModelNode as DataObject, (FunctionalConstraint)fc, con, internalReadAccessHandlerParameter);
}
return MmsDataAccessError.UNKNOWN;
}
public enum IedServer_DirectoryCategory
{
DIRECTORY_CAT_LD_LIST,
DIRECTORY_CAT_DATA_LIST,
DIRECTORY_CAT_DATASET_LIST,
DIRECTORY_CAT_LOG_LIST
}
public delegate bool InternalDirectoryAccessHandler(object parameter, ClientConnection connection, IedServer_DirectoryCategory category,LogicalDevice ld);
private InternalDirectoryAccessHandler internalDirectoryAccessHandler = null;
private object internalDirectoryAccessHandlerParameter = null;
private IedServer_DirectoryAccessHandler directoryAccessHandler = null;
public void SetDirectoryAccessHandler(InternalDirectoryAccessHandler handler, object parameter)
{
internalDirectoryAccessHandler = handler;
internalDirectoryAccessHandlerParameter = parameter;
if (directoryAccessHandler == null)
{
directoryAccessHandler = new IedServer_DirectoryAccessHandler(DirectoryAccessHandler);
IedServer_setDirectoryAccessHandler(self, directoryAccessHandler, IntPtr.Zero);
}
}
private bool DirectoryAccessHandler(IntPtr parameter, IntPtr connection, int category, IntPtr logicalDevice)
{
if (internalDirectoryAccessHandler != null && connection != IntPtr.Zero)
{
ClientConnection con = null;
this.clientConnections.TryGetValue(connection, out con);
ModelNode ldModelNode = null;
if(logicalDevice != IntPtr.Zero)
ldModelNode = iedModel.GetModelNodeFromNodeRef(logicalDevice);
return internalDirectoryAccessHandler(internalDirectoryAccessHandlerParameter, con, (IedServer_DirectoryCategory)category, ldModelNode as LogicalDevice);
}
return false;
}
private Dictionary<IntPtr, WriteAccessHandlerInfo> writeAccessHandlers = new Dictionary<IntPtr, WriteAccessHandlerInfo> ();
private void ConnectionIndicationHandlerImpl (IntPtr iedServer, IntPtr clientConnection, bool connected, IntPtr parameter)

@ -96,8 +96,9 @@ namespace IEC61850
private bool isDisposed = false;
public IntPtr Self { get => self;}
internal SampledValuesControlBlock(IntPtr iedConnection, string objectReference)
internal SampledValuesControlBlock(IntPtr iedConnection, string objectReference)
{
self = ClientSVControlBlock_create (iedConnection, objectReference);
this.objectReference = objectReference;

@ -3,54 +3,56 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.10.35004.147
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IEC61850.NET", "IEC61850forCSharp\IEC61850.NET.csproj", "{C35D624E-5506-4560-8074-1728F1FA1A4D}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IEC61850.NET", "IEC61850forCSharp\IEC61850.NET.csproj", "{C35D624E-5506-4560-8074-1728F1FA1A4D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "example1", "example1\example1.csproj", "{C616A6DF-831E-443C-9310-3F343A6E3D1A}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "example1", "example1\example1.csproj", "{C616A6DF-831E-443C-9310-3F343A6E3D1A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "model_browsing", "model_browsing\model_browsing.csproj", "{59B85486-F48D-4978-BD35-8F5C3A8288D4}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "model_browsing", "model_browsing\model_browsing.csproj", "{59B85486-F48D-4978-BD35-8F5C3A8288D4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "datasets", "datasets\datasets.csproj", "{D5C7DD38-032A-49B6-B74F-FFD9724A8AE4}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "datasets", "datasets\datasets.csproj", "{D5C7DD38-032A-49B6-B74F-FFD9724A8AE4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "control", "control\control.csproj", "{C351CFA4-E54E-49A1-86CE-69643535541A}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "control", "control\control.csproj", "{C351CFA4-E54E-49A1-86CE-69643535541A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "reporting", "reporting\reporting.csproj", "{9E29B4CE-EE5F-4CA6-85F6-5D1FF8B27BF8}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "reporting", "reporting\reporting.csproj", "{9E29B4CE-EE5F-4CA6-85F6-5D1FF8B27BF8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "example2", "example2\example2.csproj", "{2A226B6D-1D1F-4BFE-B8CC-158116F71270}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "example2", "example2\example2.csproj", "{2A226B6D-1D1F-4BFE-B8CC-158116F71270}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "authenticate", "authenticate\authenticate.csproj", "{0BECEC77-2315-4B95-AFF9-E6007E644BBF}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "authenticate", "authenticate\authenticate.csproj", "{0BECEC77-2315-4B95-AFF9-E6007E644BBF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tests", "tests\tests.csproj", "{FBDFE530-DBEB-474B-BA54-9AB287DD57B3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "files", "files\files.csproj", "{77127456-19B9-4D1A-AEF9-40F8D1C5695E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "files", "files\files.csproj", "{77127456-19B9-4D1A-AEF9-40F8D1C5695E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "example3", "example3\example3.csproj", "{5E5D0FE0-DF44-48D8-A10E-1FB07D34DEA2}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "example3", "example3\example3.csproj", "{5E5D0FE0-DF44-48D8-A10E-1FB07D34DEA2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "report_new_dataset", "report_new_dataset\report_new_dataset.csproj", "{71485F99-2976-45E6-B73D-4946E594C15C}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "report_new_dataset", "report_new_dataset\report_new_dataset.csproj", "{71485F99-2976-45E6-B73D-4946E594C15C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "log_client", "log_client\log_client.csproj", "{14C71267-2F38-460D-AA55-6803EE80AFB4}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "log_client", "log_client\log_client.csproj", "{14C71267-2F38-460D-AA55-6803EE80AFB4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{0D2F61F1-A173-44E7-BFB0-B698A1D44D12}"
ProjectSection(SolutionItems) = preProject
.nuget\packages.config = .nuget\packages.config
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "server1", "server1\server1.csproj", "{9286D2AB-96ED-4631-AB3C-ED20FF5D6E6C}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "server1", "server1\server1.csproj", "{9286D2AB-96ED-4631-AB3C-ED20FF5D6E6C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tls_client_example", "tls_client_example\tls_client_example.csproj", "{6734BF52-2D0D-476B-8EA2-C9C2D1D69B03}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "tls_client_example", "tls_client_example\tls_client_example.csproj", "{6734BF52-2D0D-476B-8EA2-C9C2D1D69B03}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "goose_subscriber", "goose_subscriber\goose_subscriber.csproj", "{1285372C-2E62-494A-A661-8D5D3873318C}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "goose_subscriber", "goose_subscriber\goose_subscriber.csproj", "{1285372C-2E62-494A-A661-8D5D3873318C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "sv_subscriber", "sv_subscriber\sv_subscriber.csproj", "{44651D2D-3252-4FD5-8B8B-5552DBE1B499}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "sv_subscriber", "sv_subscriber\sv_subscriber.csproj", "{44651D2D-3252-4FD5-8B8B-5552DBE1B499}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tls_server_example", "tls_server_example\tls_server_example.csproj", "{B63F7A81-1D3A-4F2F-A7C2-D6F77E5BD307}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "tls_server_example", "tls_server_example\tls_server_example.csproj", "{B63F7A81-1D3A-4F2F-A7C2-D6F77E5BD307}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client_example_setting_groups", "client_example_setting_groups\client_example_setting_groups.csproj", "{0DA95476-B149-450B-AC36-01CEECFC1A43}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "client_example_setting_groups", "client_example_setting_groups\client_example_setting_groups.csproj", "{0DA95476-B149-450B-AC36-01CEECFC1A43}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client_example_async", "client_example_async\client_example_async.csproj", "{71902641-776A-47D8-9C0E-9ACBBEAC1370}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "client_example_async", "client_example_async\client_example_async.csproj", "{71902641-776A-47D8-9C0E-9ACBBEAC1370}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "server_goose_publisher", "server_goose_publisher\server_goose_publisher.csproj", "{C14BB883-86B8-401C-B3D6-B655F55F3298}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "server_goose_publisher", "server_goose_publisher\server_goose_publisher.csproj", "{C14BB883-86B8-401C-B3D6-B655F55F3298}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "log_server", "log_server\log_server.csproj", "{96124F40-D38E-499B-9968-674E0D32F933}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "log_server", "log_server\log_server.csproj", "{96124F40-D38E-499B-9968-674E0D32F933}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "server_example_access_control", "server_example_access_control\server_example_access_control.csproj", "{304D9146-1490-46EF-B771-20B0603084F5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -146,6 +148,10 @@ Global
{96124F40-D38E-499B-9968-674E0D32F933}.Debug|Any CPU.Build.0 = Debug|Any CPU
{96124F40-D38E-499B-9968-674E0D32F933}.Release|Any CPU.ActiveCfg = Release|Any CPU
{96124F40-D38E-499B-9968-674E0D32F933}.Release|Any CPU.Build.0 = Release|Any CPU
{304D9146-1490-46EF-B771-20B0603084F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{304D9146-1490-46EF-B771-20B0603084F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{304D9146-1490-46EF-B771-20B0603084F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{304D9146-1490-46EF-B771-20B0603084F5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

@ -0,0 +1,369 @@
/*
* server_example_access_control.cs
*
* - How to use access control mechanisms
* - How to implement RBAC features based on access control mechanisms
*/
using System;
using IEC61850.Server;
using IEC61850.Common;
using System.Threading;
using System.Net;
using static IEC61850.Server.IedServer;
using System.Collections.Generic;
using System.Reflection.Metadata;
using IEC61850.Client;
using ReportControlBlock = IEC61850.Server.ReportControlBlock;
using IEC61850.Model;
using System.Data.Common;
namespace server_access_control
{
class MainClass
{
class PTOC1Settings
{
public float strVal;
public int opDlTmms;
public int rsDlTmms;
public int rstTms;
}
public static void Main(string[] args)
{
bool running = true;
/* run until Ctrl-C is pressed */
Console.CancelKeyPress += delegate (object sender, ConsoleCancelEventArgs e)
{
e.Cancel = true;
running = false;
};
/* Create new server configuration object */
IedServerConfig config = new IedServerConfig();
/* Set buffer size for buffered report control blocks to 200000 bytes */
config.ReportBufferSize = 200000;
/* Set stack compliance to a specific edition of the standard (WARNING: data model has also to be checked for compliance) */
config.Edition = Iec61850Edition.EDITION_2;
/* Set the base path for the MMS file services */
config.FileServiceBasePath = "./vmd-filestore/";
/* disable MMS file service */
config.FileServiceEnabled = false;
/* enable dynamic data set service */
config.DynamicDataSetServiceEnabled = true;
/* disable log service */
config.LogServiceEnabled = false;
/* set maximum number of clients */
config.MaxMmsConnections = 2;
IedModel iedModel = ConfigFileParser.CreateModelFromConfigFile("model.cfg");
IedServer iedServer = new IedServer(iedModel, config);
iedServer.SetServerIdentity("libiec61850.com", "access control example", "1.0.0");
DataObject spcso1 = (DataObject)iedModel.GetModelNodeByShortObjectReference("GenericIO/GGIO1.SPCSO1");
iedServer.SetControlHandler(spcso1, delegate (ControlAction action, object parameter, MmsValue value, bool test)
{
if (test)
return ControlHandlerResult.FAILED;
if (value.GetType() == MmsType.MMS_BOOLEAN)
{
Console.WriteLine("received binary control command: ");
if (value.GetBoolean())
Console.WriteLine("on\n");
else
Console.WriteLine("off\n");
}
else
return ControlHandlerResult.FAILED;
return ControlHandlerResult.OK;
}, spcso1);
void ConnectionCallBack(IedServer server, ClientConnection clientConnection, bool connected, object parameter)
{
if (connected)
Console.WriteLine("Connection opened\n");
else
Console.WriteLine("Connection closed\n");
}
var connectionCallBack = new ConnectionIndicationHandler(ConnectionCallBack);
iedServer.SetConnectionIndicationHandler(connectionCallBack, "127.0.0.1");
/* Install handler to log RCB events */
iedServer.SetRCBEventHandler(delegate (object parameter, ReportControlBlock rcb, ClientConnection con, RCBEventType eventType, string parameterName, MmsDataAccessError serviceError)
{
Console.WriteLine("RCB: " + rcb.Parent.GetObjectReference() + "." + rcb.Name + " event: " + eventType.ToString());
if (con != null)
{
Console.WriteLine(" caused by client " + con.GetPeerAddress());
}
else
{
Console.WriteLine(" client = null");
}
if ((eventType == RCBEventType.SET_PARAMETER) || (eventType == RCBEventType.GET_PARAMETER))
{
Console.WriteLine("RCB: "+rcb.Name + " event: "+ eventType .ToString()+ "\n");
Console.WriteLine(" param: "+ parameterName + "\n");
Console.WriteLine(" result: "+ serviceError.ToString() + "\n");
}
if (eventType == RCBEventType.ENABLED)
{
Console.WriteLine("RCB: "+ rcb.Name + " event: " + eventType.ToString() + "\n");
string rptId = rcb.RptID;
Console.WriteLine(" rptID: "+ rptId+"\n");
string dataSet =rcb.DataSet;
Console.WriteLine(" datSet:"+ dataSet+"\n");
}
}, null);
/* Install handler to control access to control blocks (RCBs, LCBs, GoCBs, SVCBs, SGCBs)*/
bool ControlBlockAccessCallBack(object parameter, ClientConnection connection, ACSIClass acsiClass, LogicalDevice ld, LogicalNode ln, string objectName, string subObjectName, ControlBlockAccessType accessType)
{
Console.WriteLine(acsiClass.ToString() + " "+ accessType.ToString() + " access " + ld.GetName() + ln.GetName() +"/"+ objectName + "." + subObjectName + "\n");
return true;
}
iedServer.SetControlBlockAccessHandler(ControlBlockAccessCallBack, iedServer);
/* By default access to variables with FC=DC and FC=CF is not allowed.
* This allow to write to simpleIOGenericIO/GGIO1.NamPlt.vendor variable used
* by iec61850_client_example1.
*/
iedServer.SetWriteAccessPolicy(FunctionalConstraint.DC, AccessPolicy.ACCESS_POLICY_ALLOW);
/* Install handler to perform access control on datasets */
bool dataSetAccessHandler(object parameter, ClientConnection connection, DataSetOperation operation, string datasetRef)
{
Console.WriteLine("Data set access: "+ datasetRef+" operation: "+ operation.ToString() + "\n");
return true;
}
iedServer.SetDataSetAccessHandler(dataSetAccessHandler, iedServer);
/* Install handler to perform read access control on data model elements
* NOTE: when read access to a data model element is blocked this will also prevent the client
* to read the data model element in a data set or enable a RCB instance that uses a dataset
* containing the restricted data model element.
*/
MmsDataAccessError readAccessHandler(LogicalDevice ld, LogicalNode ln, DataObject dataObject, FunctionalConstraint fc, ClientConnection connection, object parameter)
{
if( dataObject!= null)
Console.WriteLine("Read access to "+ld.GetName() + "/"+ln.GetName() + "."+dataObject.GetName() + "\n");
else
Console.WriteLine("Read access to "+ld.GetName() + "/"+ln.GetName() + "\n");
if (dataObject == null)
{
if (ln.GetName() == "GGIO1")
{
return MmsDataAccessError.OBJECT_ACCESS_DENIED;
}
}
else
{
if (ln.GetName() == "GGIO1" && dataObject.GetName() == "AnIn1")
{
return MmsDataAccessError.OBJECT_ACCESS_DENIED;
}
}
return MmsDataAccessError.SUCCESS;
}
iedServer.SetReadAccessHandler(readAccessHandler, null);
bool directoryAccessHandler(object parameter, ClientConnection connection, IedServer_DirectoryCategory category, LogicalDevice ld)
{
switch (category)
{
case IedServer_DirectoryCategory.DIRECTORY_CAT_LD_LIST:
Console.WriteLine("Get list of logical devices from "+ connection.GetPeerAddress()+"\n");
break;
case IedServer_DirectoryCategory.DIRECTORY_CAT_DATASET_LIST:
Console.WriteLine("Get list of datasets for LD "+ ld.GetName() + " from "+ connection.GetPeerAddress()+"\n");
break;
case IedServer_DirectoryCategory.DIRECTORY_CAT_DATA_LIST:
Console.WriteLine("Get list of data for LD " + ld.GetName() + " from " + connection.GetPeerAddress() + "\n");
break;
case IedServer_DirectoryCategory.DIRECTORY_CAT_LOG_LIST:
Console.WriteLine("Get list of logs for LD" + ld.GetName() + " from " + connection.GetPeerAddress() + "\n");
return false;
}
return true;
}
iedServer.SetDirectoryAccessHandler(directoryAccessHandler, null);
/*SettingGroups*/
LogicalDevice logicalDevice = (LogicalDevice)iedModel.GetModelNodeByShortObjectReference("GenericIO"); ;
SettingGroupControlBlock settingGroupControlBlock = logicalDevice.GetSettingGroupControlBlock();
List<PTOC1Settings> ptoc1Settings = new List<PTOC1Settings>();
ptoc1Settings.Add(new PTOC1Settings { strVal = 1.0f, opDlTmms = 500, rsDlTmms = 500, rstTms = 500 });
ptoc1Settings.Add(new PTOC1Settings { strVal = 2.0f, opDlTmms = 1500, rsDlTmms = 2500, rstTms = 750 });
ptoc1Settings.Add(new PTOC1Settings { strVal = 3.0f, opDlTmms = 500, rsDlTmms = 1500, rstTms = 750 });
ptoc1Settings.Add(new PTOC1Settings { strVal = 3.5f, opDlTmms = 1250, rsDlTmms = 1750, rstTms = 500 });
ptoc1Settings.Add(new PTOC1Settings { strVal = 3.75f, opDlTmms = 1250, rsDlTmms = 1750, rstTms = 750 });
void LoadActiveSgValues(int actSG)
{
DataAttribute dataAttribute = (DataAttribute)iedModel.GetModelNodeByShortObjectReference("GenericIO/PTOC1.StrVal.setMag.f");
iedServer.UpdateFloatAttributeValue(dataAttribute, ptoc1Settings[actSG - 1].strVal);
dataAttribute = (DataAttribute)iedModel.GetModelNodeByShortObjectReference("GenericIO/PTOC1.OpDlTmms.setVal");
iedServer.UpdateInt32AttributeValue(dataAttribute, ptoc1Settings[actSG - 1].opDlTmms);
dataAttribute = (DataAttribute)iedModel.GetModelNodeByShortObjectReference("GenericIO/PTOC1.RsDlTmms.setVal");
iedServer.UpdateInt32AttributeValue(dataAttribute, ptoc1Settings[actSG - 1].rsDlTmms);
dataAttribute = (DataAttribute)iedModel.GetModelNodeByShortObjectReference("GenericIO/PTOC1.RstTms.setVal");
iedServer.UpdateInt32AttributeValue(dataAttribute, ptoc1Settings[actSG - 1].rstTms);
}
void LoadEditSgValues(int actSG)
{
DataObject strVal = (DataObject)iedModel.GetModelNodeByShortObjectReference("GenericIO/PTOC1.StrVal");
DataAttribute setMagF = strVal.GetChildWithFc("setMag.f", FunctionalConstraint.SE);
iedServer.UpdateFloatAttributeValue(setMagF, ptoc1Settings[actSG - 1].strVal);
DataObject opDlTmms = (DataObject)iedModel.GetModelNodeByShortObjectReference("GenericIO/PTOC1.OpDlTmms");
DataAttribute setVal = opDlTmms.GetChildWithFc("setVal", FunctionalConstraint.SE);
iedServer.UpdateInt32AttributeValue(setVal, ptoc1Settings[actSG - 1].opDlTmms);
DataObject rsDlTmms = (DataObject)iedModel.GetModelNodeByShortObjectReference("GenericIO/PTOC1.RsDlTmms");
DataAttribute rsDlTmms_setVal = rsDlTmms.GetChildWithFc("setVal", FunctionalConstraint.SE);
iedServer.UpdateInt32AttributeValue(rsDlTmms_setVal, ptoc1Settings[actSG - 1].rsDlTmms);
DataObject rstTms = (DataObject)iedModel.GetModelNodeByShortObjectReference("GenericIO/PTOC1.RstTms");
DataAttribute rstTms_setVal = rstTms.GetChildWithFc("setVal", FunctionalConstraint.SE);
iedServer.UpdateInt32AttributeValue(rstTms_setVal, ptoc1Settings[actSG - 1].rstTms);
}
bool activeSGChangedHandler(object parameter, SettingGroupControlBlock sgcb, uint newActSg, ClientConnection connection)
{
Console.WriteLine("Switch to setting group "+ newActSg +"\n");
LoadActiveSgValues(Convert.ToInt32(newActSg));
return true;
}
bool editSGChangedHandler(object parameter, SettingGroupControlBlock sgcb, uint newEditSg, ClientConnection connection)
{
Console.WriteLine("Set edit setting group to " + newEditSg + "\n");
LoadEditSgValues(Convert.ToInt32(newEditSg));
return true;
}
void editSGConfirmationHandler(object parameter, SettingGroupControlBlock sgcb, uint editSg)
{
Console.WriteLine("Received edit sg confirm for sg " + editSg + "\n");
int edit = Convert.ToInt32(editSg);
DataObject strVal = (DataObject)iedModel.GetModelNodeByShortObjectReference("GenericIO/PTOC1.StrVal");
DataAttribute setMagF = strVal.GetChildWithFc("setMag.f", FunctionalConstraint.SE);
MmsValue setMagFValue = iedServer.GetAttributeValue(setMagF);
DataObject opDlTmms = (DataObject)iedModel.GetModelNodeByShortObjectReference("GenericIO/PTOC1.OpDlTmms");
DataAttribute setVal = opDlTmms.GetChildWithFc("setVal", FunctionalConstraint.SE);
MmsValue setValValue = iedServer.GetAttributeValue(setVal);
DataObject rsDlTmms = (DataObject)iedModel.GetModelNodeByShortObjectReference("GenericIO/PTOC1.RsDlTmms");
DataAttribute rsDlTmmsSetVal = rsDlTmms.GetChildWithFc("setVal", FunctionalConstraint.SE);
MmsValue rsDlTmmsSetValValue = iedServer.GetAttributeValue(rsDlTmmsSetVal);
DataObject rstTms = (DataObject)iedModel.GetModelNodeByShortObjectReference("GenericIO/PTOC1.RstTms");
DataAttribute rstTmsSetVal = rstTms.GetChildWithFc("setVal", FunctionalConstraint.SE);
MmsValue rstTmsSetValVaue = iedServer.GetAttributeValue(rstTmsSetVal);
ptoc1Settings[edit - 1].strVal = setMagFValue.ToFloat();
ptoc1Settings[edit - 1].opDlTmms = setValValue.ToInt32();
ptoc1Settings[edit - 1].rsDlTmms = rsDlTmmsSetValValue.ToInt32();
ptoc1Settings[edit - 1].rstTms = rsDlTmmsSetValValue.ToInt32();
if (iedServer.GetActiveSettingGroupChangedHandler(sgcb) == edit)
{
LoadActiveSgValues(edit);
}
}
iedServer.SetActiveSettingGroupChangedHandler(activeSGChangedHandler, settingGroupControlBlock, null);
iedServer.SetEditSettingGroupChangedHandler(editSGChangedHandler, settingGroupControlBlock, null);
iedServer.SetEditSettingGroupConfirmationHandler(editSGConfirmationHandler, settingGroupControlBlock, null);
LogicalNode logicalNode = (LogicalNode)iedModel.GetModelNodeByShortObjectReference("GenericIO/LLN0");
SVControlBlock sampledValuesControlBlock_1 = iedModel.GetSVControlBlock(logicalNode, "SMV1");
SVControlBlock sampledValuesControlBlock_2 = iedModel.GetSVControlBlock(logicalNode, "SMV2");
void sVCBEventHandler(SVControlBlock sampledValuesControlBlock, SMVEvent sMVEvent, object parameter)
{
Console.WriteLine("control called " + sampledValuesControlBlock.Name + " Event: " + sMVEvent.ToString() + "\n");
}
iedServer.SetSVCBHandler(sVCBEventHandler, sampledValuesControlBlock_1, null);
iedServer.SetSVCBHandler(sVCBEventHandler, sampledValuesControlBlock_2, null);
iedServer.Start(102);
if (iedServer.IsRunning())
{
Console.WriteLine("Server started");
GC.Collect();
DataObject ggio1AnIn1 = (DataObject)iedModel.GetModelNodeByShortObjectReference("GenericIO/GGIO1.AnIn1");
DataAttribute ggio1AnIn1magF = (DataAttribute)ggio1AnIn1.GetChild("mag.f");
DataAttribute ggio1AnIn1T = (DataAttribute)ggio1AnIn1.GetChild("t");
float floatVal = 1.0f;
while (running)
{
floatVal += 1f;
iedServer.UpdateTimestampAttributeValue(ggio1AnIn1T, new Timestamp(DateTime.Now));
iedServer.UpdateFloatAttributeValue(ggio1AnIn1magF, floatVal);
Thread.Sleep(100);
}
iedServer.Stop();
Console.WriteLine("Server stopped");
}
else
{
Console.WriteLine("Failed to start server");
}
iedServer.Destroy();
}
}
}

@ -0,0 +1,481 @@
MODEL(simpleIO){
LD(GenericIO){
LN(GGIO1){
DO(Mod 0){
DA(stVal 0 12 0 17 0)=1;
DA(q 0 23 0 18 0);
DA(t 0 22 0 16 0);
DA(ctlModel 0 12 4 16 0)=0;
}
DO(Beh 0){
DA(stVal 0 12 0 17 0)=1;
DA(q 0 23 0 18 0);
DA(t 0 22 0 16 0);
}
DO(Health 0){
DA(stVal 0 12 0 17 0)=1;
DA(q 0 23 0 18 0);
DA(t 0 22 0 16 0);
}
DO(NamPlt 0){
DA(vendor 0 20 5 16 0);
DA(swRev 0 20 5 16 0);
DA(d 0 20 5 16 0);
}
DO(AnIn1 0){
DA(mag 0 27 1 17 0){
DA(f 0 10 1 16 0);
}
DA(q 0 23 1 18 0);
DA(t 0 22 1 16 0);
}
DO(AnIn2 0){
DA(mag 0 27 1 17 0){
DA(f 0 10 1 16 0);
}
DA(q 0 23 1 18 0);
DA(t 0 22 1 16 0);
}
DO(AnIn3 0){
DA(mag 0 27 1 17 0){
DA(f 0 10 1 16 0);
}
DA(q 0 23 1 18 0);
DA(t 0 22 1 16 0);
}
DO(AnIn4 0){
DA(mag 0 27 1 17 0){
DA(f 0 10 1 16 0);
}
DA(q 0 23 1 18 0);
DA(t 0 22 1 16 0);
}
DO(SPCSO1 0){
DA(origin 0 27 0 16 0){
DA(orCat 0 12 0 16 0);
DA(orIdent 0 13 0 16 0);
}
DA(ctlNum 0 6 0 16 0);
DA(stVal 0 0 0 17 0);
DA(q 0 23 0 18 0);
DA(t 0 22 0 16 0);
DA(ctlModel 0 12 4 16 0)=1;
DA(Oper 0 27 12 16 0){
DA(ctlVal 0 0 12 16 0);
DA(origin 0 27 12 16 0){
DA(orCat 0 12 12 16 0);
DA(orIdent 0 13 12 16 0);
}
DA(ctlNum 0 6 12 16 0);
DA(T 0 22 12 16 0);
DA(Test 0 0 12 16 0);
DA(Check 0 24 12 16 0);
}
}
DO(SPCSO2 0){
DA(stVal 0 0 0 17 0);
DA(q 0 23 0 18 0);
DA(Oper 0 27 12 16 0){
DA(ctlVal 0 0 12 16 0);
DA(origin 0 27 12 16 0){
DA(orCat 0 12 12 16 0);
DA(orIdent 0 13 12 16 0);
}
DA(ctlNum 0 6 12 16 0);
DA(T 0 22 12 16 0);
DA(Test 0 0 12 16 0);
DA(Check 0 24 12 16 0);
}
DA(ctlModel 0 12 4 16 0)=1;
DA(t 0 22 0 16 0);
}
DO(SPCSO3 0){
DA(stVal 0 0 0 17 0);
DA(q 0 23 0 18 0);
DA(Oper 0 27 12 16 0){
DA(ctlVal 0 0 12 16 0);
DA(origin 0 27 12 16 0){
DA(orCat 0 12 12 16 0);
DA(orIdent 0 13 12 16 0);
}
DA(ctlNum 0 6 12 16 0);
DA(T 0 22 12 16 0);
DA(Test 0 0 12 16 0);
DA(Check 0 24 12 16 0);
}
DA(ctlModel 0 12 4 16 0)=1;
DA(t 0 22 0 16 0);
}
DO(SPCSO4 0){
DA(stVal 0 0 0 17 0);
DA(q 0 23 0 18 0);
DA(Oper 0 27 12 16 0){
DA(ctlVal 0 0 12 16 0);
DA(origin 0 27 12 16 0){
DA(orCat 0 12 12 16 0);
DA(orIdent 0 13 12 16 0);
}
DA(ctlNum 0 6 12 16 0);
DA(T 0 22 12 16 0);
DA(Test 0 0 12 16 0);
DA(Check 0 24 12 16 0);
}
DA(ctlModel 0 12 4 16 0)=1;
DA(t 0 22 0 16 0);
}
DO(Ind1 0){
DA(stVal 0 0 0 17 0);
DA(q 0 23 0 18 0);
DA(t 0 22 0 16 0);
}
DO(Ind2 0){
DA(stVal 0 0 0 17 0);
DA(q 0 23 0 18 0);
DA(t 0 22 0 16 0);
}
DO(Ind3 0){
DA(stVal 0 0 0 17 0);
DA(q 0 23 0 18 0);
DA(t 0 22 0 16 0);
}
DO(Ind4 0){
DA(stVal 0 0 0 17 0);
DA(q 0 23 0 18 0);
DA(t 0 22 0 16 0);
}
}
LN(LPHD1){
DO(PhyNam 0){
DA(vendor 0 20 5 16 0);
}
DO(PhyHealth 0){
DA(stVal 0 12 0 17 0)=1;
DA(q 0 23 0 18 0);
DA(t 0 22 0 16 0);
}
DO(Proxy 0){
DA(stVal 0 0 0 17 0);
DA(q 0 23 0 18 0);
DA(t 0 22 0 16 0);
}
}
LN(LLN0){
SG(1 5)
DO(Mod 0){
DA(stVal 0 12 0 17 0)=1;
DA(q 0 23 0 18 0);
DA(t 0 22 0 16 0);
DA(ctlModel 0 12 4 16 0)=0;
}
DO(Beh 0){
DA(stVal 0 12 0 17 0)=1;
DA(q 0 23 0 18 0);
DA(t 0 22 0 16 0);
}
DO(Health 0){
DA(stVal 0 12 0 17 0)=1;
DA(q 0 23 0 18 0);
DA(t 0 22 0 16 0);
}
DO(NamPlt 0){
DA(vendor 0 20 5 16 0)="MZ Automation";
DA(swRev 0 20 5 16 0)="1.3.0";
DA(d 0 20 5 16 0)="libiec61850 server example";
DA(configRev 0 20 5 16 0);
DA(ldNs 0 20 11 16 0);
}
DS(Events){
DE(GGIO1$ST$SPCSO1$stVal);
DE(GGIO1$ST$SPCSO2$stVal);
DE(GGIO1$ST$SPCSO3$stVal);
DE(GGIO1$ST$SPCSO4$stVal);
}
DS(Events2){
DE(GGIO1$ST$SPCSO1);
DE(GGIO1$ST$SPCSO2);
DE(GGIO1$ST$SPCSO3);
DE(GGIO1$ST$SPCSO4);
}
DS(Measurements){
DE(GGIO1$MX$AnIn1$mag$f);
DE(GGIO1$MX$AnIn1$q);
DE(GGIO1$MX$AnIn2$mag$f);
DE(GGIO1$MX$AnIn2$q);
DE(GGIO1$MX$AnIn3$mag$f);
DE(GGIO1$MX$AnIn3$q);
DE(GGIO1$MX$AnIn4$mag$f);
DE(GGIO1$MX$AnIn4$q);
}
DS(ServiceTracking){
DE(LTRK1$SR$SpcTrk);
DE(LTRK1$SR$DpcTrk);
DE(LTRK1$SR$IncTrk);
DE(LTRK1$SR$BscTrk);
DE(LTRK1$SR$UrcbTrk);
DE(LTRK1$SR$BrcbTrk);
DE(LTRK1$SR$GocbTrk);
DE(LTRK1$SR$SgcbTrk);
DE(LTRK1$SR$LocbTrk);
}
RC(EventsRCB01 Events1 0 Events2 1 24 175 50 1000);
RC(EventsIndexed01 Events2 0 Events 1 24 175 50 1000);
RC(EventsIndexed02 Events2 0 Events 1 24 175 50 1000);
RC(EventsIndexed03 Events2 0 Events 1 24 175 50 1000);
RC(Measurements01 Measurements 1 Measurements 1 16 239 50 1000);
RC(Measurements02 Measurements 1 Measurements 1 16 239 50 1000);
RC(Measurements03 Measurements 1 Measurements 1 16 239 50 1000);
RC(brcbServiceTracking01 ServiceTracking 1 ServiceTracking 1 19 228 0 0);
RC(brcbServiceTracking02 ServiceTracking 1 ServiceTracking 1 19 228 0 0);
RC(brcbServiceTracking03 ServiceTracking 1 ServiceTracking 1 19 228 0 0);
LC(EventLog Events GenericIO/LLN0$EventLog 19 0 1 0);
LC(GeneralLog - - 19 0 0 0);
LOG();
LOG(EventLog);
GC(gcbEvents events Events 3 0 1000 3000){
PA(4 1 1000 010CCD010001);
}
SMVC(SMV1 xxxxMUnn01 Events 0 0 0 1 0 ){
PA(4 123 4000 010CCD040001);
}
SMVC(SMV2 null Measurements 0 0 0 0 0 ){
PA(4 123 4000 010CCD040001);
}
}
LN(PTOC1){
DO(Mod 0){
DA(stVal 0 12 0 17 0);
DA(q 0 23 0 18 0);
DA(t 0 22 0 16 0);
DA(ctlModel 0 12 4 16 0);
}
DO(Beh 0){
DA(stVal 0 12 0 17 0);
DA(q 0 23 0 18 0);
DA(t 0 22 0 16 0);
}
DO(Str 0){
DA(general 0 0 0 17 0);
DA(dirGeneral 0 12 0 17 0);
DA(q 0 23 0 18 0);
DA(t 0 22 0 16 0);
}
DO(Op 0){
DA(general 0 0 0 17 0);
DA(q 0 23 0 18 0);
DA(t 0 22 0 16 0);
}
DO(StrVal 0){
DA(setMag 0 27 7 16 0){
DA(f 0 10 7 16 0);
}
}
DO(OpDlTmms 0){
DA(setVal 0 3 7 17 0);
}
DO(RsDlTmms 0){
DA(setVal 0 3 7 17 0);
}
DO(RstTms 0){
DA(setVal 0 3 7 17 0);
}
}
LN(LTRK1){
DO(Beh 0){
DA(stVal 0 12 0 17 0);
DA(q 0 23 0 18 0);
DA(t 0 22 0 16 0);
}
DO(SpcTrk 0){
DA(objRef 0 31 8 20 0);
DA(serviceType 0 12 8 16 0);
DA(errorCode 0 12 8 16 0);
DA(originatorID 0 13 8 16 0);
DA(t 0 22 8 16 0);
DA(d 0 20 5 16 0);
DA(dU 0 21 5 16 0);
DA(cdcNs 0 20 11 16 0);
DA(cdcName 0 20 11 16 0);
DA(dataNs 0 20 11 16 0);
DA(ctlVal 0 0 8 16 0);
DA(origin 0 27 8 16 0){
DA(orCat 0 12 8 16 0);
DA(orIdent 0 13 8 16 0);
}
DA(ctlNum 0 6 8 16 0);
DA(T 0 22 8 16 0);
DA(Test 0 0 8 16 0);
DA(Check 0 24 8 16 0);
DA(respAddCause 0 12 8 16 0);
}
DO(DpcTrk 0){
DA(objRef 0 31 8 20 0);
DA(serviceType 0 12 8 16 0);
DA(errorCode 0 12 8 16 0);
DA(originatorID 0 13 8 16 0);
DA(t 0 22 8 16 0);
DA(d 0 20 5 16 0);
DA(dU 0 21 5 16 0);
DA(cdcNs 0 20 11 16 0);
DA(cdcName 0 20 11 16 0);
DA(dataNs 0 20 11 16 0);
DA(ctlVal 0 0 8 16 0);
DA(origin 0 27 8 16 0){
DA(orCat 0 12 8 16 0);
DA(orIdent 0 13 8 16 0);
}
DA(ctlNum 0 6 8 16 0);
DA(T 0 22 8 16 0);
DA(Test 0 0 8 16 0);
DA(Check 0 24 8 16 0);
DA(respAddCause 0 12 8 16 0);
}
DO(IncTrk 0){
DA(objRef 0 31 8 20 0);
DA(serviceType 0 12 8 16 0);
DA(errorCode 0 12 8 16 0);
DA(originatorID 0 13 8 16 0);
DA(t 0 22 8 16 0);
DA(d 0 20 5 16 0);
DA(dU 0 21 5 16 0);
DA(cdcNs 0 20 11 16 0);
DA(cdcName 0 20 11 16 0);
DA(dataNs 0 20 11 16 0);
DA(ctlVal 0 3 8 16 0);
DA(origin 0 27 8 16 0){
DA(orCat 0 12 8 16 0);
DA(orIdent 0 13 8 16 0);
}
DA(ctlNum 0 6 8 16 0);
DA(T 0 22 8 16 0);
DA(Test 0 0 8 16 0);
DA(Check 0 24 8 16 0);
DA(respAddCause 0 12 8 16 0);
}
DO(BscTrk 0){
DA(objRef 0 31 8 20 0);
DA(serviceType 0 12 8 16 0);
DA(errorCode 0 12 8 16 0);
DA(originatorID 0 13 8 16 0);
DA(t 0 22 8 16 0);
DA(d 0 20 5 16 0);
DA(dU 0 21 5 16 0);
DA(cdcNs 0 20 11 16 0);
DA(cdcName 0 20 11 16 0);
DA(dataNs 0 20 11 16 0);
DA(ctlVal 0 25 8 16 0);
DA(origin 0 27 8 16 0){
DA(orCat 0 12 8 16 0);
DA(orIdent 0 13 8 16 0);
}
DA(ctlNum 0 6 8 16 0);
DA(T 0 22 8 16 0);
DA(Test 0 0 8 16 0);
DA(Check 0 24 8 16 0);
DA(respAddCause 0 12 8 16 0);
}
DO(UrcbTrk 0){
DA(objRef 0 31 8 20 0);
DA(serviceType 0 12 8 16 0);
DA(errorCode 0 12 8 16 0);
DA(originatorID 0 13 8 16 0);
DA(t 0 22 8 16 0);
DA(d 0 20 5 16 0);
DA(dU 0 21 5 16 0);
DA(cdcNs 0 20 11 16 0);
DA(cdcName 0 20 11 16 0);
DA(dataNs 0 20 11 16 0);
DA(rptID 0 19 8 16 0);
DA(rptEna 0 0 8 16 0);
DA(resv 0 0 8 16 0);
DA(datSet 0 31 8 16 0);
DA(confRev 0 9 8 16 0);
DA(optFlds 0 26 8 16 0);
DA(bufTm 0 9 8 16 0);
DA(sqNum 0 6 8 16 0);
DA(trgOps 0 26 8 16 0);
DA(intgPd 0 9 8 16 0);
DA(gi 0 0 8 16 0);
}
DO(BrcbTrk 0){
DA(objRef 0 31 8 20 0);
DA(serviceType 0 12 8 16 0);
DA(errorCode 0 12 8 16 0);
DA(originatorID 0 13 8 16 0);
DA(t 0 22 8 16 0);
DA(d 0 20 5 16 0);
DA(dU 0 21 5 16 0);
DA(cdcNs 0 20 11 16 0);
DA(cdcName 0 20 11 16 0);
DA(dataNs 0 20 11 16 0);
DA(rptID 0 19 8 16 0);
DA(rptEna 0 0 8 16 0);
DA(datSet 0 31 8 16 0);
DA(confRev 0 9 8 16 0);
DA(optFlds 0 26 8 16 0);
DA(bufTm 0 9 8 16 0);
DA(sqNum 0 7 8 16 0);
DA(trgOps 0 26 8 16 0);
DA(intgPd 0 9 8 16 0);
DA(gi 0 0 8 16 0);
DA(purgeBuf 0 0 8 16 0);
DA(entryID 0 15 8 16 0);
DA(timeOfEntry 0 28 8 16 0);
DA(resvTms 0 2 8 16 0);
}
DO(GocbTrk 0){
DA(objRef 0 31 8 20 0);
DA(serviceType 0 12 8 16 0);
DA(errorCode 0 12 8 16 0);
DA(originatorID 0 13 8 16 0);
DA(t 0 22 8 16 0);
DA(d 0 20 5 16 0);
DA(dU 0 21 5 16 0);
DA(cdcNs 0 20 11 16 0);
DA(cdcName 0 20 11 16 0);
DA(dataNs 0 20 11 16 0);
DA(goEna 0 0 8 16 0);
DA(goID 0 19 8 16 0);
DA(datSet 0 31 8 16 0);
DA(confRev 0 9 8 16 0);
DA(ndsCom 0 0 8 16 0);
DA(dstAddress 0 29 8 16 0);
}
DO(SgcbTrk 0){
DA(objRef 0 31 8 20 0);
DA(serviceType 0 12 8 16 0);
DA(errorCode 0 12 8 16 0);
DA(originatorID 0 13 8 16 0);
DA(t 0 22 8 16 0);
DA(d 0 20 5 16 0);
DA(dU 0 21 5 16 0);
DA(cdcNs 0 20 11 16 0);
DA(cdcName 0 20 11 16 0);
DA(dataNs 0 20 11 16 0);
DA(numOfSG 0 6 8 16 0);
DA(actSG 0 6 8 16 0);
DA(editSG 0 6 8 16 0);
DA(cnfEdit 0 0 8 16 0);
DA(lActTm 0 22 8 16 0);
DA(resvTms 0 7 8 16 0);
}
DO(LocbTrk 0){
DA(objRef 0 31 8 20 0);
DA(serviceType 0 12 8 16 0);
DA(errorCode 0 12 8 16 0);
DA(originatorID 0 13 8 16 0);
DA(t 0 22 8 16 0);
DA(d 0 20 5 16 0);
DA(dU 0 21 5 16 0);
DA(cdcNs 0 20 11 16 0);
DA(cdcName 0 20 11 16 0);
DA(dataNs 0 20 11 16 0);
DA(logEna 0 0 8 16 0);
DA(datSet 0 31 8 16 0);
DA(bufTm 0 9 8 16 0);
DA(trgOps 0 26 8 16 0);
DA(intgPd 0 9 8 16 0);
DA(logRef 0 31 8 16 0);
}
}
}
}

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<None Remove="model.cfg" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="model.cfg">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\IEC61850forCSharp\IEC61850.NET.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,660 @@
<?xml version="1.0" encoding="UTF-8"?>
<SCL xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.iec.ch/61850/2003/SCL" xsi:schemaLocation="http://www.iec.ch/61850/2003/SCL SCL.xsd" version="2007" revision="B">
<Header id="" nameStructure="IEDName">
</Header>
<Communication>
<SubNetwork name="subnetwork1" type="8-MMS" Name="subnetwork1">
<Text>Station bus</Text>
<BitRate unit="b/s">10</BitRate>
<ConnectedAP iedName="simpleIO" apName="accessPoint1">
<Address>
<P type="IP">0.0.0.0</P>
<P type="IP-SUBNET">255.255.255.0</P>
<P type="IP-GATEWAY">192.168.2.1</P>
<P type="OSI-AP-Title">1,3,9999,33</P>
<P type="OSI-AE-Qualifier">33</P>
<P type="OSI-PSEL">00000001</P>
<P type="OSI-SSEL">0001</P>
<P type="OSI-TSEL">0001</P>
<P type="MMS-Port">102</P>
</Address>
<GSE ldInst="GenericIO" cbName="gcbEvents">
<Address>
<P type="VLAN-ID">1</P>
<P type="VLAN-PRIORITY">4</P>
<P type="MAC-Address">01-0c-cd-01-00-01</P>
<P type="APPID">1000</P>
</Address>
<MinTime>1000</MinTime>
<MaxTime>3000</MaxTime>
</GSE>
<SMV cbName="MSVCB01" ldInst="GenericIO">
<Address>
<P type="MAC-Address">01-0C-CD-04-00-01</P>
<P type="APPID">4000</P>
<P type="VLAN-PRIORITY">4</P>
<P type="VLAN-ID">123</P>
</Address>
</SMV>
</ConnectedAP>
</SubNetwork>
</Communication>
<IED name="simpleIO">
<Services>
<DynAssociation />
<GetDirectory />
<GetDataObjectDefinition />
<GetDataSetValue />
<DataSetDirectory />
<ReadWrite />
<GetCBValues />
<ConfLNs fixPrefix="true" fixLnInst="true" />
<GOOSE max="5" />
<GSSE max="5" />
<FileHandling />
<GSEDir />
<TimerActivatedControl />
</Services>
<AccessPoint name="accessPoint1">
<Server>
<Authentication />
<LDevice inst="GenericIO">
<LN lnClass="LPHD" lnType="LPHD1" inst="1" prefix="">
<DOI name="PhyHealth">
<DAI name="stVal">
<Val>ok</Val>
</DAI>
</DOI>
</LN>
<LN lnClass="GGIO" lnType="GGIO1" inst="1" prefix="">
<DOI name="Mod">
<DAI name="stVal">
<Val>on</Val>
</DAI>
<DAI name="ctlModel">
<Val>status-only</Val>
</DAI>
</DOI>
<DOI name="Beh">
<DAI name="stVal">
<Val>on</Val>
</DAI>
</DOI>
<DOI name="Health">
<DAI name="stVal">
<Val>ok</Val>
</DAI>
</DOI>
<DOI name="SPCSO1">
<DAI name="ctlModel">
<Val>direct-with-normal-security</Val>
</DAI>
</DOI>
<DOI name="SPCSO2">
<DAI name="ctlModel">
<Val>direct-with-normal-security</Val>
</DAI>
</DOI>
<DOI name="SPCSO3">
<DAI name="ctlModel">
<Val>direct-with-normal-security</Val>
</DAI>
</DOI>
<DOI name="SPCSO4">
<DAI name="ctlModel">
<Val>direct-with-normal-security</Val>
</DAI>
</DOI>
</LN>
<LN0 lnClass="LLN0" lnType="LLN01" inst="">
<DataSet name="Events" desc="Events">
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO1" daName="stVal" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO2" daName="stVal" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO3" daName="stVal" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO4" daName="stVal" />
</DataSet>
<DataSet name="Events2" desc="Events2">
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO1" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO2" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO3" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO4" />
</DataSet>
<DataSet name="Measurements" desc="Measurements">
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="MX" lnInst="1" doName="AnIn1" daName="mag.f" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="MX" lnInst="1" doName="AnIn1" daName="q" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="MX" lnInst="1" doName="AnIn2" daName="mag.f" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="MX" lnInst="1" doName="AnIn2" daName="q" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="MX" lnInst="1" doName="AnIn3" daName="mag.f" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="MX" lnInst="1" doName="AnIn3" daName="q" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="MX" lnInst="1" doName="AnIn4" daName="mag.f" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="MX" lnInst="1" doName="AnIn4" daName="q" />
</DataSet>
<DataSet name="ServiceTracking">
<FCDA doName="SpcTrk" fc="SR" ldInst="GenericIO" lnClass="LTRK" lnInst="1" />
<FCDA doName="DpcTrk" fc="SR" ldInst="GenericIO" lnClass="LTRK" lnInst="1" />
<FCDA doName="IncTrk" fc="SR" ldInst="GenericIO" lnClass="LTRK" lnInst="1" />
<FCDA doName="BscTrk" fc="SR" ldInst="GenericIO" lnClass="LTRK" lnInst="1" />
<FCDA doName="UrcbTrk" fc="SR" ldInst="GenericIO" lnClass="LTRK" lnInst="1" />
<FCDA doName="BrcbTrk" fc="SR" ldInst="GenericIO" lnClass="LTRK" lnInst="1" />
<FCDA doName="GocbTrk" fc="SR" ldInst="GenericIO" lnClass="LTRK" lnInst="1" />
<FCDA doName="SgcbTrk" fc="SR" ldInst="GenericIO" lnClass="LTRK" lnInst="1" />
<FCDA doName="LocbTrk" fc="SR" ldInst="GenericIO" lnClass="LTRK" lnInst="1" />
</DataSet>
<ReportControl name="EventsRCB" confRev="1" datSet="Events2" rptID="Events1" buffered="false" intgPd="1000" bufTime="50">
<TrgOps period="true" />
<OptFields seqNum="true" timeStamp="true" dataSet="true" reasonCode="true" configRef="true" />
<RptEnabled max="1" />
</ReportControl>
<ReportControl name="EventsIndexed" indexed="true" confRev="1" datSet="Events" rptID="Events2" buffered="false" intgPd="1000" bufTime="50">
<TrgOps period="true" />
<OptFields seqNum="true" timeStamp="true" dataSet="true" reasonCode="true" configRef="true" />
<RptEnabled max="3" />
</ReportControl>
<ReportControl name="Measurements" indexed="true" confRev="1" datSet="Measurements" rptID="Measurements" buffered="true" intgPd="1000" bufTime="50">
<TrgOps period="false" />
<OptFields seqNum="true" timeStamp="true" dataSet="true" reasonCode="true" entryID="true" configRef="true" />
<RptEnabled max="3" />
</ReportControl>
<ReportControl buffered="true" confRev="1" datSet="ServiceTracking" name="brcbServiceTracking" rptID="ServiceTracking">
<TrgOps dchg="true" qchg="true" />
<OptFields configRef="true" entryID="true" reasonCode="true" />
<RptEnabled max="3" />
</ReportControl>
<LogControl name="EventLog" datSet="Events" logName="EventLog" logEna="true">
<TrgOps dchg="true" qchg="true" />
</LogControl>
<LogControl name="GeneralLog" datSet="" logName="">
<TrgOps dchg="true" qchg="true" />
</LogControl>
<Log />
<Log name="EventLog" />
<GSEControl appID="events" name="gcbEvents" type="GOOSE" datSet="Events" confRev="3" />
<SampledValueControl name="MSVCB01" smvID="xxxxMUnn01" datSet="Events">
<SmvOpts refreshTime="true" />
</SampledValueControl>
<SettingControl desc="parameter set" numOfSGs="5" actSG="1" />
<DOI name="Mod">
<DAI name="stVal">
<Val>on</Val>
</DAI>
<DAI name="ctlModel">
<Val>status-only</Val>
</DAI>
</DOI>
<DOI name="Beh">
<DAI name="stVal">
<Val>on</Val>
</DAI>
</DOI>
<DOI name="Health">
<DAI name="stVal">
<Val>ok</Val>
</DAI>
</DOI>
<DOI name="NamPlt">
<DAI name="vendor">
<Val>MZ Automation</Val>
</DAI>
<DAI name="swRev">
<Val>1.3.0</Val>
</DAI>
<DAI name="d">
<Val>libiec61850 server example</Val>
</DAI>
</DOI>
</LN0>
<LN desc="example for setting groups" inst="1" lnClass="PTOC" lnType="PTOC1" />
<LN desc="Service Tracking Information" inst="1" lnClass="LTRK" lnType="myLTRK" />
</LDevice>
</Server>
</AccessPoint>
</IED>
<DataTypeTemplates>
<LNodeType id="LLN01" lnClass="LLN0">
<DO name="Mod" type="ENC_1_Mod" />
<DO name="Beh" type="ENS_1_Beh" />
<DO name="Health" type="ENS_2_Health" />
<DO name="NamPlt" type="LPL_1_NamPlt" />
</LNodeType>
<LNodeType id="LPHD1" lnClass="LPHD">
<DO name="PhyNam" type="DPL_1_PhyNam" />
<DO name="PhyHealth" type="ENS_2_Health" />
<DO name="Proxy" type="SPS_1_Proxy" />
</LNodeType>
<LNodeType id="GGIO1" lnClass="GGIO">
<DO name="Mod" type="ENC_1_Mod" />
<DO name="Beh" type="ENS_1_Beh" />
<DO name="Health" type="ENS_2_Health" />
<DO name="NamPlt" type="LPL_2_NamPlt" />
<DO name="AnIn1" type="MV_1_AnIn1" />
<DO name="AnIn2" type="MV_1_AnIn1" />
<DO name="AnIn3" type="MV_1_AnIn1" />
<DO name="AnIn4" type="MV_1_AnIn1" />
<DO name="SPCSO1" type="SPC_1_SPCSO1" />
<DO name="SPCSO2" type="SPC_2" />
<DO name="SPCSO3" type="SPC_2" />
<DO name="SPCSO4" type="SPC_2" />
<DO name="Ind1" type="SPS_1_Proxy" />
<DO name="Ind2" type="SPS_1_Proxy" />
<DO name="Ind3" type="SPS_1_Proxy" />
<DO name="Ind4" type="SPS_1_Proxy" />
</LNodeType>
<LNodeType id="PTOC1" lnClass="PTOC">
<DO name="Mod" type="ENC_1_Mod" />
<DO name="Beh" type="ENS_1_Beh" />
<DO name="Str" type="ACD_Str" />
<DO name="Op" type="ACT_Op" />
<DO name="StrVal" type="ASG_SE" />
<DO name="OpDlTmms" type="ING_SE" />
<DO name="RsDlTmms" type="ING_SE" />
<DO name="RstTms" type="ING_SE" />
</LNodeType>
<LNodeType id="myLTRK" lnClass="LTRK">
<DO name="Beh" type="myENS_Beh" desc="" />
<DO name="SpcTrk" type="myCTS_Bool" desc="" />
<DO name="DpcTrk" type="myCTS_Bool" desc="" />
<DO name="IncTrk" type="myCTS_Int32" desc="" />
<DO name="BscTrk" type="myCTS_BSC" desc="" />
<DO name="UrcbTrk" type="myUTS" desc="" />
<DO name="BrcbTrk" type="myBTS" desc="" />
<DO name="GocbTrk" type="myGTS" desc="" />
<DO name="SgcbTrk" type="mySTS" desc="" />
<DO name="LocbTrk" type="myLTS" desc="" />
</LNodeType>
<DOType cdc="ACD" id="ACD_Str">
<DA bType="BOOLEAN" dchg="true" fc="ST" name="general" />
<DA bType="Enum" dchg="true" fc="ST" name="dirGeneral" type="dirGeneral" />
<DA bType="Quality" fc="ST" name="q" qchg="true" />
<DA bType="Timestamp" fc="ST" name="t" />
</DOType>
<DOType cdc="ACT" id="ACT_Op">
<DA bType="BOOLEAN" dchg="true" fc="ST" name="general" />
<DA bType="Quality" fc="ST" name="q" qchg="true" />
<DA bType="Timestamp" fc="ST" name="t" />
</DOType>
<DOType cdc="ASG" id="ASG_SE">
<DA bType="Struct" fc="SE" name="setMag" type="AnalogueValue_1" />
</DOType>
<DOType id="ING_SE" cdc="ING">
<DA name="setVal" bType="INT32" fc="SE" dchg="true" />
</DOType>
<DOType id="myCTS_Bool" cdc="CTS" desc="">
<DA name="objRef" bType="ObjRef" fc="SR" desc="" dupd="true" />
<DA name="serviceType" bType="Enum" type="ServiceType" fc="SR" desc="" />
<DA name="errorCode" bType="Enum" type="ServiceError" fc="SR" desc="" />
<DA name="originatorID" bType="Octet64" fc="SR" desc="" />
<DA name="t" bType="Timestamp" fc="SR" desc="" />
<DA name="d" bType="VisString255" fc="DC" desc="" />
<DA name="dU" bType="Unicode255" fc="DC" desc="" />
<DA name="cdcNs" bType="VisString255" fc="EX" desc="" />
<DA name="cdcName" bType="VisString255" fc="EX" desc="" />
<DA name="dataNs" bType="VisString255" fc="EX" desc="" />
<DA name="ctlVal" bType="BOOLEAN" fc="SR" desc="" />
<!-- <DA name="operTm" bType="Timestamp" fc="SR" desc=""/> -->
<DA name="origin" bType="Struct" type="Originator_1" fc="SR" desc="" />
<DA name="ctlNum" bType="INT8U" fc="SR" desc="" />
<DA name="T" bType="Timestamp" fc="SR" desc="" />
<DA name="Test" bType="BOOLEAN" fc="SR" desc="" />
<DA name="Check" bType="Check" fc="SR" desc="" />
<DA name="respAddCause" bType="Enum" type="AddCause" fc="SR" desc="" />
</DOType>
<DOType id="myCTS_Int32" cdc="CTS" desc="">
<DA name="objRef" bType="ObjRef" fc="SR" desc="" dupd="true" />
<DA name="serviceType" bType="Enum" type="ServiceType" fc="SR" desc="" />
<DA name="errorCode" bType="Enum" type="ServiceError" fc="SR" desc="" />
<DA name="originatorID" bType="Octet64" fc="SR" desc="" />
<DA name="t" bType="Timestamp" fc="SR" desc="" />
<DA name="d" bType="VisString255" fc="DC" desc="" />
<DA name="dU" bType="Unicode255" fc="DC" desc="" />
<DA name="cdcNs" bType="VisString255" fc="EX" desc="" />
<DA name="cdcName" bType="VisString255" fc="EX" desc="" />
<DA name="dataNs" bType="VisString255" fc="EX" desc="" />
<DA name="ctlVal" bType="INT32" fc="SR" desc="TINT32 control value" />
<!-- <DA name="operTm" bType="Timestamp" fc="SR" desc=""/> -->
<DA name="origin" bType="Struct" type="Originator_1" fc="SR" desc="" />
<DA name="ctlNum" bType="INT8U" fc="SR" desc="" />
<DA name="T" bType="Timestamp" fc="SR" desc="" />
<DA name="Test" bType="BOOLEAN" fc="SR" desc="" />
<DA name="Check" bType="Check" fc="SR" desc="" />
<DA name="respAddCause" bType="Enum" type="AddCause" fc="SR" desc="" />
</DOType>
<DOType id="myCTS_BSC" cdc="CTS" desc="">
<DA name="objRef" bType="ObjRef" fc="SR" desc="" dupd="true" />
<DA name="serviceType" bType="Enum" type="ServiceType" fc="SR" desc="" />
<DA name="errorCode" bType="Enum" type="ServiceError" fc="SR" desc="" />
<DA name="originatorID" bType="Octet64" fc="SR" desc="" />
<DA name="t" bType="Timestamp" fc="SR" desc="" />
<DA name="d" bType="VisString255" fc="DC" desc="" />
<DA name="dU" bType="Unicode255" fc="DC" desc="" />
<DA name="cdcNs" bType="VisString255" fc="EX" desc="" />
<DA name="cdcName" bType="VisString255" fc="EX" desc="" />
<DA name="dataNs" bType="VisString255" fc="EX" desc="" />
<DA name="ctlVal" bType="Tcmd" fc="SR" desc="" />
<!-- <DA name="operTm" bType="Timestamp" fc="SR" desc=""/> -->
<DA name="origin" bType="Struct" type="Originator_1" fc="SR" desc="" />
<DA name="ctlNum" bType="INT8U" fc="SR" desc="" />
<DA name="T" bType="Timestamp" fc="SR" desc="" />
<DA name="Test" bType="BOOLEAN" fc="SR" desc="" />
<DA name="Check" bType="Check" fc="SR" desc="" />
<DA name="respAddCause" bType="Enum" type="AddCause" fc="SR" desc="" />
</DOType>
<DOType id="myUTS" cdc="UTS" desc="">
<DA name="objRef" bType="ObjRef" fc="SR" desc="" dupd="true" />
<DA name="serviceType" bType="Enum" type="ServiceType" fc="SR" desc="" />
<DA name="errorCode" bType="Enum" type="ServiceError" fc="SR" desc="" />
<DA name="originatorID" bType="Octet64" fc="SR" desc="" />
<DA name="t" bType="Timestamp" fc="SR" desc="" />
<DA name="d" bType="VisString255" fc="DC" desc="" />
<DA name="dU" bType="Unicode255" fc="DC" desc="" />
<DA name="cdcNs" bType="VisString255" fc="EX" desc="" />
<DA name="cdcName" bType="VisString255" fc="EX" desc="" />
<DA name="dataNs" bType="VisString255" fc="EX" desc="" />
<DA name="rptID" bType="VisString129" fc="SR" desc="" />
<DA name="rptEna" bType="BOOLEAN" fc="SR" desc="" />
<DA name="resv" bType="BOOLEAN" fc="SR" desc="" />
<DA name="datSet" bType="ObjRef" fc="SR" desc="" />
<DA name="confRev" bType="INT32U" fc="SR" desc="" />
<DA name="optFlds" bType="OptFlds" fc="SR" desc="" />
<DA name="bufTm" bType="INT32U" fc="SR" desc="" />
<DA name="sqNum" bType="INT8U" fc="SR" desc="" />
<DA name="trgOps" bType="TrgOps" fc="SR" desc="" />
<DA name="intgPd" bType="INT32U" fc="SR" desc="" />
<DA name="gi" bType="BOOLEAN" fc="SR" desc="" />
</DOType>
<DOType id="myBTS" cdc="BTS" desc="">
<DA name="objRef" bType="ObjRef" fc="SR" desc="" dupd="true" />
<DA name="serviceType" bType="Enum" type="ServiceType" fc="SR" desc="" />
<DA name="errorCode" bType="Enum" type="ServiceError" fc="SR" desc="" />
<DA name="originatorID" bType="Octet64" fc="SR" desc="" />
<DA name="t" bType="Timestamp" fc="SR" desc="" />
<DA name="d" bType="VisString255" fc="DC" desc="" />
<DA name="dU" bType="Unicode255" fc="DC" desc="" />
<DA name="cdcNs" bType="VisString255" fc="EX" desc="" />
<DA name="cdcName" bType="VisString255" fc="EX" desc="" />
<DA name="dataNs" bType="VisString255" fc="EX" desc="" />
<DA name="rptID" bType="VisString129" fc="SR" desc="" />
<DA name="rptEna" bType="BOOLEAN" fc="SR" desc="" />
<DA name="datSet" bType="ObjRef" fc="SR" desc="" />
<DA name="confRev" bType="INT32U" fc="SR" desc="" />
<DA name="optFlds" bType="OptFlds" fc="SR" desc="" />
<DA name="bufTm" bType="INT32U" fc="SR" desc="" />
<DA name="sqNum" bType="INT16U" fc="SR" desc="" />
<DA name="trgOps" bType="TrgOps" fc="SR" desc="" />
<DA name="intgPd" bType="INT32U" fc="SR" desc="" />
<DA name="gi" bType="BOOLEAN" fc="SR" desc="" />
<DA name="purgeBuf" bType="BOOLEAN" fc="SR" desc="" />
<DA name="entryID" bType="EntryID" fc="SR" desc="" />
<DA name="timeOfEntry" bType="EntryTime" fc="SR" desc="" />
<DA name="resvTms" bType="INT16" fc="SR" desc="" />
</DOType>
<DOType id="myGTS" cdc="GTS" desc="">
<DA name="objRef" bType="ObjRef" fc="SR" desc="" dupd="true" />
<DA name="serviceType" bType="Enum" type="ServiceType" fc="SR" desc="" />
<DA name="errorCode" bType="Enum" type="ServiceError" fc="SR" desc="" />
<DA name="originatorID" bType="Octet64" fc="SR" desc="" />
<DA name="t" bType="Timestamp" fc="SR" desc="" />
<DA name="d" bType="VisString255" fc="DC" desc="" />
<DA name="dU" bType="Unicode255" fc="DC" desc="" />
<DA name="cdcNs" bType="VisString255" fc="EX" desc="" />
<DA name="cdcName" bType="VisString255" fc="EX" desc="" />
<DA name="dataNs" bType="VisString255" fc="EX" desc="" />
<DA name="goEna" bType="BOOLEAN" fc="SR" desc="" />
<DA name="goID" bType="VisString129" fc="SR" desc="" />
<DA name="datSet" bType="ObjRef" fc="SR" desc="" />
<DA name="confRev" bType="INT32U" fc="SR" desc="" />
<DA name="ndsCom" bType="BOOLEAN" fc="SR" desc="" />
<DA name="dstAddress" bType="PhyComAddr" fc="SR" desc="" />
</DOType>
<DOType id="mySTS" cdc="STS" desc="">
<DA name="objRef" bType="ObjRef" fc="SR" desc="" dupd="true" />
<DA name="serviceType" bType="Enum" type="ServiceType" fc="SR" desc="" />
<DA name="errorCode" bType="Enum" type="ServiceError" fc="SR" desc="" />
<DA name="originatorID" bType="Octet64" fc="SR" desc="" />
<DA name="t" bType="Timestamp" fc="SR" desc="" />
<DA name="d" bType="VisString255" fc="DC" desc="" />
<DA name="dU" bType="Unicode255" fc="DC" desc="" />
<DA name="cdcNs" bType="VisString255" fc="EX" desc="" />
<DA name="cdcName" bType="VisString255" fc="EX" desc="" />
<DA name="dataNs" bType="VisString255" fc="EX" desc="" />
<DA name="numOfSG" bType="INT8U" fc="SR" desc="" />
<DA name="actSG" bType="INT8U" fc="SR" desc="" />
<DA name="editSG" bType="INT8U" fc="SR" desc="" />
<DA name="cnfEdit" bType="BOOLEAN" fc="SR" desc="" />
<DA name="lActTm" bType="Timestamp" fc="SR" desc="" />
<DA name="resvTms" bType="INT16U" fc="SR" desc="" />
</DOType>
<DOType id="myLTS" cdc="LTS" desc="">
<DA name="objRef" bType="ObjRef" fc="SR" desc="" dupd="true" />
<DA name="serviceType" bType="Enum" type="ServiceType" fc="SR" desc="" />
<DA name="errorCode" bType="Enum" type="ServiceError" fc="SR" desc="" />
<DA name="originatorID" bType="Octet64" fc="SR" desc="" />
<DA name="t" bType="Timestamp" fc="SR" desc="" />
<DA name="d" bType="VisString255" fc="DC" desc="" />
<DA name="dU" bType="Unicode255" fc="DC" desc="" />
<DA name="cdcNs" bType="VisString255" fc="EX" desc="" />
<DA name="cdcName" bType="VisString255" fc="EX" desc="" />
<DA name="dataNs" bType="VisString255" fc="EX" desc="" />
<DA name="logEna" bType="BOOLEAN" fc="SR" desc="" />
<DA name="datSet" bType="ObjRef" fc="SR" desc="" />
<DA name="bufTm" bType="INT32U" fc="SR" desc="" />
<DA name="trgOps" bType="TrgOps" fc="SR" desc="" />
<DA name="intgPd" bType="INT32U" fc="SR" desc="" />
<DA name="logRef" bType="ObjRef" fc="SR" desc="" />
</DOType>
<DOType id="ENC_1_Mod" cdc="ENC">
<DA name="stVal" bType="Enum" type="Beh" fc="ST" dchg="true" />
<DA name="q" bType="Quality" fc="ST" qchg="true" />
<DA name="t" bType="Timestamp" fc="ST" />
<DA name="ctlModel" type="CtlModels" bType="Enum" fc="CF" />
</DOType>
<DOType id="ENS_1_Beh" cdc="ENS">
<DA name="stVal" bType="Enum" type="Beh" fc="ST" dchg="true" />
<DA name="q" bType="Quality" fc="ST" qchg="true" />
<DA name="t" bType="Timestamp" fc="ST" />
</DOType>
<DOType id="myENS_Beh" cdc="INS">
<DA name="stVal" bType="Enum" type="Beh" dchg="true" fc="ST" />
<DA name="q" bType="Quality" qchg="true" fc="ST" />
<DA name="t" bType="Timestamp" fc="ST" />
</DOType>
<DOType id="ENS_2_Health" cdc="ENS">
<DA name="stVal" bType="Enum" type="HealthKind" fc="ST" dchg="true" />
<DA name="q" bType="Quality" fc="ST" qchg="true" />
<DA name="t" bType="Timestamp" fc="ST" />
</DOType>
<DOType id="LPL_1_NamPlt" cdc="LPL">
<DA name="vendor" bType="VisString255" fc="DC" />
<DA name="swRev" bType="VisString255" fc="DC" />
<DA name="d" bType="VisString255" fc="DC" />
<DA name="configRev" bType="VisString255" fc="DC" />
<DA name="ldNs" bType="VisString255" fc="EX" />
</DOType>
<DOType id="DPL_1_PhyNam" cdc="DPL">
<DA name="vendor" bType="VisString255" fc="DC" />
</DOType>
<DOType id="SPS_1_Proxy" cdc="SPS">
<DA name="stVal" bType="BOOLEAN" fc="ST" dchg="true" />
<DA name="q" bType="Quality" fc="ST" qchg="true" />
<DA name="t" bType="Timestamp" fc="ST" />
</DOType>
<DOType id="LPL_2_NamPlt" cdc="LPL">
<DA name="vendor" bType="VisString255" fc="DC" />
<DA name="swRev" bType="VisString255" fc="DC" />
<DA name="d" bType="VisString255" fc="DC" />
</DOType>
<DOType id="MV_1_AnIn1" cdc="MV">
<DA name="mag" type="AnalogueValue_1" bType="Struct" fc="MX" dchg="true" />
<DA name="q" bType="Quality" fc="MX" qchg="true" />
<DA name="t" bType="Timestamp" fc="MX" />
</DOType>
<DOType id="SPC_1_SPCSO1" cdc="SPC">
<DA name="origin" fc="ST" type="Originator_1" bType="Struct" />
<DA name="ctlNum" fc="ST" bType="INT8U" />
<DA name="stVal" bType="BOOLEAN" fc="ST" dchg="true" />
<DA name="q" bType="Quality" fc="ST" qchg="true" />
<DA name="t" bType="Timestamp" fc="ST" />
<DA name="ctlModel" type="CtlModels" bType="Enum" fc="CF" />
<DA name="Oper" type="SPCOperate_1" bType="Struct" fc="CO" />
</DOType>
<DOType id="SPC_2" cdc="SPC">
<DA name="stVal" bType="BOOLEAN" fc="ST" dchg="true" />
<DA name="q" bType="Quality" fc="ST" qchg="true" />
<DA name="Oper" type="SPCOperate_1" bType="Struct" fc="CO" />
<DA name="ctlModel" type="CtlModels" bType="Enum" fc="CF" />
<DA name="t" bType="Timestamp" fc="ST" />
</DOType>
<DAType id="AnalogueValue_1">
<BDA name="f" bType="FLOAT32" />
</DAType>
<DAType id="Originator_1">
<BDA name="orCat" type="OrCat" bType="Enum" />
<BDA name="orIdent" bType="Octet64" />
</DAType>
<DAType id="SPCOperate_1">
<BDA name="ctlVal" bType="BOOLEAN" />
<BDA name="origin" type="Originator_1" bType="Struct" />
<BDA name="ctlNum" bType="INT8U" />
<BDA name="T" bType="Timestamp" />
<BDA name="Test" bType="BOOLEAN" />
<BDA name="Check" bType="Check" />
</DAType>
<EnumType id="AddCause">
<EnumVal ord="0">Unknown</EnumVal>
<EnumVal ord="1">Not-supported</EnumVal>
<EnumVal ord="2">Blocked-by-switching-hierarchy</EnumVal>
<EnumVal ord="3">Select-failed</EnumVal>
<EnumVal ord="4">Invalid-position</EnumVal>
<EnumVal ord="5">Position-reached</EnumVal>
<EnumVal ord="6">Parameter-change-in-execution</EnumVal>
<EnumVal ord="7">Step-limit</EnumVal>
<EnumVal ord="8">Blocked-by-Mode</EnumVal>
<EnumVal ord="9">Blocked-by-process</EnumVal>
<EnumVal ord="10">Blocked-by-interlocking</EnumVal>
<EnumVal ord="11">Blocked-by-synchrocheck</EnumVal>
<EnumVal ord="12">Command-already-in-execution</EnumVal>
<EnumVal ord="13">Blocked-by-health</EnumVal>
<EnumVal ord="14">1-of-n-control</EnumVal>
<EnumVal ord="15">Abortion-by-cancel</EnumVal>
<EnumVal ord="16">Time-limit-over</EnumVal>
<EnumVal ord="17">Abortion-by-trip</EnumVal>
<EnumVal ord="18">Object-not-selected</EnumVal>
<EnumVal ord="19">Object-already-selected</EnumVal>
<EnumVal ord="20">No-access-authority</EnumVal>
<EnumVal ord="21">Ended-with-overshoot</EnumVal>
<EnumVal ord="22">Abortion-due-to-deviation</EnumVal>
<EnumVal ord="23">Abortion-by-communication-loss </EnumVal>
<EnumVal ord="24">Blocked-by-command</EnumVal>
<EnumVal ord="25">None</EnumVal>
<EnumVal ord="26">Inconsistent-parameters</EnumVal>
<EnumVal ord="27">Locked-by-other-client</EnumVal>
</EnumType>
<EnumType id="Beh">
<EnumVal ord="1">on</EnumVal>
<EnumVal ord="2">blocked</EnumVal>
<EnumVal ord="3">test</EnumVal>
<EnumVal ord="4">test/blocked</EnumVal>
<EnumVal ord="5">off</EnumVal>
</EnumType>
<EnumType id="HealthKind">
<EnumVal ord="1">ok</EnumVal>
<EnumVal ord="2">warning</EnumVal>
<EnumVal ord="3">alarm</EnumVal>
</EnumType>
<EnumType id="CtlModels">
<EnumVal ord="0">status-only</EnumVal>
<EnumVal ord="1">direct-with-normal-security</EnumVal>
<EnumVal ord="2">sbo-with-normal-security</EnumVal>
<EnumVal ord="3">direct-with-enhanced-security</EnumVal>
<EnumVal ord="4">sbo-with-enhanced-security</EnumVal>
</EnumType>
<EnumType id="OrCat">
<EnumVal ord="0">not-supported</EnumVal>
<EnumVal ord="1">bay-control</EnumVal>
<EnumVal ord="2">station-control</EnumVal>
<EnumVal ord="3">remote-control</EnumVal>
<EnumVal ord="4">automatic-bay</EnumVal>
<EnumVal ord="5">automatic-station</EnumVal>
<EnumVal ord="6">automatic-remote</EnumVal>
<EnumVal ord="7">maintenance</EnumVal>
<EnumVal ord="8">process</EnumVal>
</EnumType>
<EnumType id="ServiceError">
<EnumVal ord="0">no-error</EnumVal>
<EnumVal ord="1">instance-not-available</EnumVal>
<EnumVal ord="2">instance-in-use</EnumVal>
<EnumVal ord="3">access-violation</EnumVal>
<EnumVal ord="4">access-not-allowed-in-current-state</EnumVal>
<EnumVal ord="5">parameter-value-inappropriate</EnumVal>
<EnumVal ord="6">parameter-value-inconsistent</EnumVal>
<EnumVal ord="7">class-not-supported</EnumVal>
<EnumVal ord="8">instance-locked-by-other-client</EnumVal>
<EnumVal ord="9">control-must-be-selected</EnumVal>
<EnumVal ord="10">type-conflict</EnumVal>
<EnumVal ord="11">failed-due-to-communications-constraint</EnumVal>
<EnumVal ord="12">failed-due-to-server-constraint</EnumVal>
</EnumType>
<EnumType id="ServiceType">
<EnumVal ord="0">Unknown</EnumVal>
<EnumVal ord="1">Associate</EnumVal>
<EnumVal ord="2">Abort</EnumVal>
<EnumVal ord="3">Release</EnumVal>
<EnumVal ord="4">GetServerDirectory</EnumVal>
<EnumVal ord="5">GetLogicalDeviceDirectory</EnumVal>
<EnumVal ord="6">GetAllDataValues</EnumVal>
<EnumVal ord="7">GetDataValues</EnumVal>
<EnumVal ord="8">SetDataValues</EnumVal>
<EnumVal ord="9">GetDataDirectory</EnumVal>
<EnumVal ord="10">GetDataDefinition</EnumVal>
<EnumVal ord="11">GetDataSetValues</EnumVal>
<EnumVal ord="12">SetDataSetValues</EnumVal>
<EnumVal ord="13">CreateDataSet</EnumVal>
<EnumVal ord="14">DeleteDataSet</EnumVal>
<EnumVal ord="15">GetDataSetDirectory</EnumVal>
<EnumVal ord="16">SelectActiveSG</EnumVal>
<EnumVal ord="17">SelectEditSG</EnumVal>
<EnumVal ord="18">SetEditSGValue</EnumVal>
<EnumVal ord="19">ConfirmEditSGValues</EnumVal>
<EnumVal ord="20">GetEditSGValue</EnumVal>
<EnumVal ord="21">GetSGCBValues</EnumVal>
<EnumVal ord="22">Report</EnumVal>
<EnumVal ord="23">GetBRCBValues</EnumVal>
<EnumVal ord="24">SetBRCBValues</EnumVal>
<EnumVal ord="25">GetURCBValues</EnumVal>
<EnumVal ord="26">SetURCBValues</EnumVal>
<EnumVal ord="27">GetLCBValues</EnumVal>
<EnumVal ord="28">SetLCBValues</EnumVal>
<EnumVal ord="29">QueryLogByTime</EnumVal>
<EnumVal ord="30">QueryLogAfter</EnumVal>
<EnumVal ord="31">GetLogStatus</EnumVal>
<EnumVal ord="32">SendGOOSEMessage</EnumVal>
<EnumVal ord="33">GetGoCBValues</EnumVal>
<EnumVal ord="34">SetGoCBValues</EnumVal>
<EnumVal ord="35">GetGoReference</EnumVal>
<EnumVal ord="36">GetGOOSEElementNumber</EnumVal>
<EnumVal ord="37">SendMSVMessage</EnumVal>
<EnumVal ord="38">GetMSVCBValues</EnumVal>
<EnumVal ord="39">SetMSVCBValues</EnumVal>
<EnumVal ord="40">SendUSVMessage</EnumVal>
<EnumVal ord="41">GetUSVCBValues</EnumVal>
<EnumVal ord="42">SetUSVCBValues</EnumVal>
<EnumVal ord="43">Select</EnumVal>
<EnumVal ord="44">SelectWithValue</EnumVal>
<EnumVal ord="45">Cancel</EnumVal>
<EnumVal ord="46">Operate</EnumVal>
<EnumVal ord="47">CommandTermination</EnumVal>
<EnumVal ord="48">TimeActivatedOperate</EnumVal>
<EnumVal ord="49">GetFile</EnumVal>
<EnumVal ord="50">SetFile</EnumVal>
<EnumVal ord="51">DeleteFile</EnumVal>
<EnumVal ord="52">GetFileAttributValues</EnumVal>
<EnumVal ord="53">TimeSynchronisation</EnumVal>
<EnumVal ord="54">InternalChange</EnumVal>
</EnumType>
<EnumType id="dirGeneral">
<EnumVal ord="0">unknown</EnumVal>
<EnumVal ord="1">forward</EnumVal>
<EnumVal ord="2">backward</EnumVal>
<EnumVal ord="3">both</EnumVal>
</EnumType>
</DataTypeTemplates>
</SCL>

@ -114,6 +114,7 @@ controlBlockAccessHandler(void* parameter, ClientConnection connection, ACSIClas
{
printf("%s %s access %s/%s.%s.%s\n", ACSIClassToStr(acsiClass), accessType == IEC61850_CB_ACCESS_TYPE_WRITE ? "write" : "read", ld->name, ln->name, objectName, subObjectName);
return false;
/* allow only read access to LCBs */
if (acsiClass == ACSI_CLASS_LCB) {
if (accessType == IEC61850_CB_ACCESS_TYPE_READ)

@ -468,6 +468,9 @@ LIB61850_API SVControlBlock*
SVControlBlock_create(const char* name, LogicalNode* parent, const char* svID, const char* dataSet, uint32_t confRev, uint8_t smpMod,
uint16_t smpRate, uint8_t optFlds, bool isUnicast);
LIB61850_API const char*
SVControlBlock_getName(SVControlBlock* self);
LIB61850_API void
SVControlBlock_addPhyComAddress(SVControlBlock* self, PhyComAddress* phyComAddress);

@ -587,6 +587,13 @@ SVControlBlock_create(const char* name, LogicalNode* parent, const char* svID, c
return self;
}
const char*
SVControlBlock_getName(SVControlBlock* self)
{
return self->name;
}
void
SVControlBlock_addPhyComAddress(SVControlBlock* self, PhyComAddress* phyComAddress)
{

@ -16,6 +16,7 @@
<None Remove="ICDFiles\sampleModel.icd" />
<None Remove="ICDFiles\sampleModel_errors.icd" />
<None Remove="ICDFiles\sampleModel_with_dataset.icd" />
<None Remove="ICDFiles\simpleIO_access_control.icd" />
<None Remove="ICDFiles\simpleIO_control_tests.cid" />
<None Remove="ICDFiles\simpleIO_direct_control.cid" />
<None Remove="ICDFiles\simpleIO_direct_control.icd" />
@ -49,6 +50,9 @@
<EmbeddedResource Include="ICDFiles\sampleModel_with_dataset.icd">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
<EmbeddedResource Include="ICDFiles\simpleIO_access_control.icd">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
<EmbeddedResource Include="ICDFiles\simpleIO_control_tests.cid">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>

Loading…
Cancel
Save