diff --git a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs index 7aa303ba..69beb84c 100644 --- a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs @@ -2214,6 +2214,23 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void IedServer_setConnectionIndicationHandler(IntPtr self, InternalConnectionHandler handler, IntPtr parameter); + public delegate void RCBWriteAccessHandler(IedServer iedServer, string domainName, string rcbName, string elementName, MmsValue value, ClientConnection clientConnection, object parameter); + + private RCBWriteAccessHandler rcbWriteAccessHandler = null; + private object rcbWriteAccessHandlerParameter = null; + + public void SetRCBWriteAccessHandler(RCBWriteAccessHandler handler, object parameter) + { + rcbWriteAccessHandler = handler; + rcbWriteAccessHandlerParameter = parameter; + } + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void InternalRCBWriteAccessHandler(IntPtr iedServer, string domainName, string rcbName, string elementName, IntPtr value, IntPtr clientConnection, IntPtr parameter); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedServer_setRCBWriteAccessHandler(IntPtr self, InternalRCBWriteAccessHandler handler, IntPtr parameter); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void IedServer_enableGoosePublishing(IntPtr self); @@ -2400,6 +2417,18 @@ namespace IEC61850 internal Dictionary clientConnections = new Dictionary (); + private void RCBWriteAccessHandlerImpl(IntPtr iedServer, string domainName, string rcbName, string elementName, IntPtr value, IntPtr clientConnection, IntPtr parameter) + { + if (rcbWriteAccessHandler != null) + { + MmsValue v = new MmsValue(value); + + ClientConnection con = new ClientConnection(clientConnection); + + rcbWriteAccessHandler(this, domainName, rcbName, elementName, v, con, rcbWriteAccessHandlerParameter); + } + } + /* store IedModel instance to prevent garbage collector */ private IedModel iedModel = null; @@ -2432,6 +2461,7 @@ namespace IEC61850 } private InternalConnectionHandler internalConnectionHandler = null; + private InternalRCBWriteAccessHandler internalRCBWriteAccessHandler = null; /// /// Sets the local ip address for listening @@ -2462,6 +2492,11 @@ namespace IEC61850 IedServer_setConnectionIndicationHandler (self, internalConnectionHandler, IntPtr.Zero); + if (internalRCBWriteAccessHandler == null) + internalRCBWriteAccessHandler = new InternalRCBWriteAccessHandler(RCBWriteAccessHandlerImpl); + + IedServer_setRCBWriteAccessHandler(self, internalRCBWriteAccessHandler, IntPtr.Zero); + IedServer_start(self, tcpPort); } @@ -2479,6 +2514,7 @@ namespace IEC61850 { IedServer_stop(self); internalConnectionHandler = null; + internalRCBWriteAccessHandler = null; } /// @@ -2506,6 +2542,7 @@ namespace IEC61850 IedServer_destroy(self); self = IntPtr.Zero; internalConnectionHandler = null; + internalRCBWriteAccessHandler = null; this.iedModel = null; } } diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index 48c79533..52e1723a 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -743,6 +743,28 @@ typedef void (*IedConnectionIndicationHandler) (IedServer self, ClientConnection LIB61850_API void IedServer_setConnectionIndicationHandler(IedServer self, IedConnectionIndicationHandler handler, void* parameter); +/** + * \brief User provided callback function that is invoked whenever a client writes RCB element value. + * + * \param self the instance of IedServer where the connection event occured. + * \param domainName the domain name. + * \param rcbName the RCB name. + * \param elementName the element name. + * \param value the new value to write. + * \param connection the connect object + * \param parameter a user provided parameter + */ +typedef void (*IedRCBWriteAccessHandler) (IedServer self, char* domainName, char* rcbName, char* elementName, MmsValue* value, ClientConnection connection, void* parameter); + +/** + * \brief set a callback function that will be called on write events. + * + * \param self the instance of IedServer to operate on. + * \param handler the user provided callback function + * \param parameter a user provided parameter that is passed to the callback function. + */ +LIB61850_API void +IedServer_setRCBWriteAccessHandler(IedServer self, IedRCBWriteAccessHandler handler, void* parameter); /**@}*/ diff --git a/src/iec61850/inc_private/mms_mapping.h b/src/iec61850/inc_private/mms_mapping.h index 63ec5742..55161097 100644 --- a/src/iec61850/inc_private/mms_mapping.h +++ b/src/iec61850/inc_private/mms_mapping.h @@ -139,6 +139,9 @@ MmsMapping_freeDynamicallyCreatedDataSet(DataSet* dataSet); LIB61850_INTERNAL void MmsMapping_setConnectionIndicationHandler(MmsMapping* self, IedConnectionIndicationHandler handler, void* parameter); +LIB61850_INTERNAL void +MmsMapping_setRCBWriteAccessHandler(MmsMapping* self, IedRCBWriteAccessHandler handler, void* parameter); + LIB61850_INTERNAL void MmsMapping_setLogStorage(MmsMapping* self, const char* logRef, LogStorage logStorage); diff --git a/src/iec61850/inc_private/mms_mapping_internal.h b/src/iec61850/inc_private/mms_mapping_internal.h index 79c9e793..d05cf717 100644 --- a/src/iec61850/inc_private/mms_mapping_internal.h +++ b/src/iec61850/inc_private/mms_mapping_internal.h @@ -332,6 +332,9 @@ struct sMmsMapping { IedServer_RCBEventHandler rcbEventHandler; void* rcbEventHandlerParameter; + + IedRCBWriteAccessHandler rcbWriteAccessHandler; + void* rcbWriteAccessHandlerParameter; }; #endif /* MMS_MAPPING_INTERNAL_H_ */ diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index 6534fb7b..41970eb0 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -1570,6 +1570,12 @@ IedServer_setConnectionIndicationHandler(IedServer self, IedConnectionIndication MmsMapping_setConnectionIndicationHandler(self->mmsMapping, handler, parameter); } +void +IedServer_setRCBWriteAccessHandler(IedServer self, IedRCBWriteAccessHandler handler, void* parameter) +{ + MmsMapping_setRCBWriteAccessHandler(self->mmsMapping, handler, parameter); +} + MmsValue* IedServer_getFunctionalConstrainedData(IedServer self, DataObject* dataObject, FunctionalConstraint fc) { diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index ff7a490f..a42de343 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -2618,6 +2618,13 @@ mmsWriteHandler(void* parameter, MmsDomain* domain, if (strncmp(variableId, rc->name, variableIdLen) == 0) { char* elementName = variableId + rcNameLen + 1; + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + + /* call user provided handler function */ + if (self->rcbWriteAccessHandler != NULL) + self->rcbWriteAccessHandler(self->iedServer, domain->domainName, rc->name, elementName, value, clientConnection, + self->rcbWriteAccessHandlerParameter); + return Reporting_RCBWriteAccessHandler(self, rc, elementName, value, connection); } } @@ -3473,6 +3480,13 @@ MmsMapping_setConnectionIndicationHandler(MmsMapping* self, IedConnectionIndicat self->connectionIndicationHandlerParameter = parameter; } +void +MmsMapping_setRCBWriteAccessHandler(MmsMapping* self, IedRCBWriteAccessHandler handler, void* parameter) +{ + self->rcbWriteAccessHandler = handler; + self->rcbWriteAccessHandlerParameter = parameter; +} + static bool isMemberValueRecursive(MmsValue* container, MmsValue* value) {