From 88148f39ac7b4454233c6678dea776727791897d Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Sat, 22 Jan 2022 00:35:02 +0100 Subject: [PATCH 01/11] - added IedServer_RCBEventHandler --- src/iec61850/inc/iec61850_server.h | 38 ++++++- .../inc_private/mms_mapping_internal.h | 5 +- src/iec61850/server/impl/ied_server.c | 7 ++ src/iec61850/server/mms_mapping/reporting.c | 104 ++++++++++++++++-- 4 files changed, 145 insertions(+), 9 deletions(-) diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index e69f2c0e..b2953226 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -3,7 +3,7 @@ * * IEC 61850 server API for libiec61850. * - * Copyright 2013-2020 Michael Zillgith + * Copyright 2013-2022 Michael Zillgith * * This file is part of libIEC61850. * @@ -1534,6 +1534,42 @@ IedServer_updateCtlModel(IedServer self, DataObject* ctlObject, ControlModel val /**@}*/ +/** + * @defgroup IEC61850_SERVER_RCB Server side report control block (RCB) handling + * + * @{ + */ + +typedef enum { + RCB_EVENT_GET_PARAMETER, /* << parameter read by client (not implemented) */ + RCB_EVENT_SET_PARAMETER, /* << parameter set by client */ + RCB_EVENT_UNRESERVED, /* << RCB reservation canceled */ + RCB_EVENT_RESERVED, /* << RCB reserved */ + RCB_EVENT_ENABLE, /* << RCB enabled */ + RCB_EVENT_DISABLE, /* << RCB disabled */ + RCB_EVENT_GI, /* << GI report triggered */ + RCB_EVENT_PURGEBUF /* << Purge buffer procedure executed */ +} IedServer_RCBEventType; + +/** + * \brief Callback that is called in case of RCB event + * + * \param parameter user provided paramter + */ +typedef void (*IedServer_RCBEventHandler) (void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType event, const char* parameterName, MmsDataAccessError serviceError); + +/** + * \brief Set a handler for report control block (RCB) events + * + * \param self the instance of IedServer to operate on. + * \param handler the event handler to be used + * \param parameter a user provided parameter that is passed to the handler. + */ +LIB61850_API void +IedServer_setRCBEventHandler(IedServer self, IedServer_RCBEventHandler handler, void* parameter); + +/**@}*/ + /** * @defgroup IEC61850_SERVER_SVCB Server side sampled values control block (SVCB) handling * diff --git a/src/iec61850/inc_private/mms_mapping_internal.h b/src/iec61850/inc_private/mms_mapping_internal.h index b73618f6..c61c237e 100644 --- a/src/iec61850/inc_private/mms_mapping_internal.h +++ b/src/iec61850/inc_private/mms_mapping_internal.h @@ -1,7 +1,7 @@ /* * mms_mapping_internal.h * - * Copyright 2013-2020 Michael Zillgith + * Copyright 2013-2022 Michael Zillgith * * This file is part of libIEC61850. * @@ -328,6 +328,9 @@ struct sMmsMapping { IedConnectionIndicationHandler connectionIndicationHandler; void* connectionIndicationHandlerParameter; + + IedServer_RCBEventHandler rcbEventHandler; + void* rcbEventHandlerParameter; }; #endif /* MMS_MAPPING_INTERNAL_H_ */ diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index a158caf8..4c287e77 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -584,6 +584,13 @@ IedServer_createWithTlsSupport(IedModel* dataModel, TLSConfiguration tlsConfigur return IedServer_createWithConfig(dataModel, tlsConfiguration, NULL); } +void +IedServer_setRCBEventHandler(IedServer self, IedServer_RCBEventHandler handler, void* parameter) +{ + self->mmsMapping->rcbEventHandler = handler; + self->mmsMapping->rcbEventHandlerParameter = parameter; +} + void IedServer_destroy(IedServer self) { diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c index 780ba258..919ae346 100644 --- a/src/iec61850/server/mms_mapping/reporting.c +++ b/src/iec61850/server/mms_mapping/reporting.c @@ -1,7 +1,7 @@ /* * reporting.c * - * Copyright 2013-2020 Michael Zillgith + * Copyright 2013-2022 Michael Zillgith * * This file is part of libIEC61850. * @@ -1675,6 +1675,8 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme bool resvTmsAccess = false; /* access is to RecvTms or Resv */ bool dontUpdate = false; + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection); + /* check reservation timeout for buffered RCBs */ if (rc->buffered) { @@ -1713,6 +1715,10 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme rc->reserved = true; rc->clientConnection = connection; rc->reservationTimeout = Hal_getTimeInMs() + (rc->resvTms * 1000); + + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_RESERVED, NULL, DATA_ACCESS_ERROR_SUCCESS); + } } else { if (DEBUG_IED_SERVER) @@ -1735,6 +1741,7 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme if (rc->reserved == false) { if ((strcmp(elementName, "Resv")) && (strcmp(elementName, "ResvTms"))) { retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + goto exit_function; } } @@ -1742,6 +1749,7 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme if ((rc->reserved) && (rc->clientConnection != connection)) { retVal = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; + goto exit_function; } @@ -1764,6 +1772,7 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme if (rc->enabled == true) { retVal = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; + goto exit_function; } @@ -1803,6 +1812,11 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme MmsValue_setUint32(sqNum, 0U); retVal = DATA_ACCESS_ERROR_SUCCESS; + + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_ENABLE, NULL, DATA_ACCESS_ERROR_SUCCESS); + } + goto exit_function; } else { @@ -1816,6 +1830,7 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme if (((rc->enabled) || (rc->reserved)) && (rc->clientConnection != connection)) { retVal = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; + goto exit_function; } @@ -1833,6 +1848,14 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme /* clear report buffer */ purgeBuf(rc); + + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_GI, NULL, DATA_ACCESS_ERROR_SUCCESS); + } + } + + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_DISABLE, NULL, DATA_ACCESS_ERROR_SUCCESS); } rc->enabled = false; @@ -1849,10 +1872,16 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme } retVal = DATA_ACCESS_ERROR_SUCCESS; + + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_GI, NULL, DATA_ACCESS_ERROR_SUCCESS); + } + goto exit_function; } else { retVal = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; + goto exit_function; } } @@ -1861,6 +1890,7 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme if ((rc->reserved) && (rc->clientConnection != connection)) { retVal = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; + goto exit_function; } @@ -1870,6 +1900,11 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme rc->reserved = value->value.boolean; if (rc->reserved == true) { + + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_RESERVED, NULL, DATA_ACCESS_ERROR_SUCCESS); + } + updateOwner(rc, connection); rc->clientConnection = connection; } @@ -1888,6 +1923,11 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme if (MmsValue_getBoolean(value) == true) { purgeBuf(rc); retVal = DATA_ACCESS_ERROR_SUCCESS; + + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_PURGEBUF, NULL, DATA_ACCESS_ERROR_SUCCESS); + } + goto exit_function; } } @@ -1900,15 +1940,21 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme if (updateReportDataset(self, rc, value, connection)) { - if (rc->buffered) + if (rc->buffered) { purgeBuf(rc); + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_PURGEBUF, NULL, DATA_ACCESS_ERROR_SUCCESS); + } + } + MmsValue_update(datSet, value); increaseConfRev(rc); } else { retVal = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + goto exit_function; } } @@ -1927,6 +1973,10 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme if (rc->buffered) { rc->nextIntgReportTime = 0; purgeBuf(rc); + + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_PURGEBUF, NULL, DATA_ACCESS_ERROR_SUCCESS); + } } } @@ -1938,9 +1988,14 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme if (!MmsValue_equals(trgOps, value)) { MmsValue_update(trgOps, value); - if (rc->buffered) + if (rc->buffered) { purgeBuf(rc); + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_PURGEBUF, NULL, DATA_ACCESS_ERROR_SUCCESS); + } + } + refreshTriggerOptions(rc); } @@ -1949,7 +2004,9 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme else if (strcmp(elementName, "EntryID") == 0) { if (MmsValue_getOctetStringSize(value) != 8) { + retVal = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + goto exit_function; } @@ -1957,7 +2014,9 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme if (!checkReportBufferForEntryID(rc, value)) { rc->reportBuffer->isOverflow = true; + retVal = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + goto exit_function; } @@ -1981,9 +2040,14 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme if (!MmsValue_equals(bufTm, value)) { MmsValue_update(bufTm, value); - if (rc->buffered) + if (rc->buffered) { purgeBuf(rc); + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_PURGEBUF, NULL, DATA_ACCESS_ERROR_SUCCESS); + } + } + refreshBufferTime(rc); } @@ -1995,8 +2059,13 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme if (!MmsValue_equals(rptId, value)) { MmsValue_update(rptId, value); - if (rc->buffered) + if (rc->buffered) { purgeBuf(rc); + + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_PURGEBUF, NULL, DATA_ACCESS_ERROR_SUCCESS); + } + } } goto exit_function; @@ -2017,11 +2086,19 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme rc->reservationTimeout = 0; rc->reserved = false; updateOwner(rc, NULL); + + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_UNRESERVED, NULL, DATA_ACCESS_ERROR_SUCCESS); + } } else { rc->reservationTimeout = Hal_getTimeInMs() + (rc->resvTms * 1000); reserveRcb(rc, connection); + + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_RESERVED, NULL, DATA_ACCESS_ERROR_SUCCESS); + } } MmsValue* resvTmsVal = ReportControl_getRCBValue(rc, "ResvTms"); @@ -2029,18 +2106,22 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme if (resvTmsVal != NULL) MmsValue_update(resvTmsVal, value); } - else + else { retVal = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + } } else { if (self->iedServer->edition < IEC_61850_EDITION_2_1) { - retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; } else { rc->reservationTimeout = Hal_getTimeInMs() + (RESV_TMS_IMPLICIT_VALUE * 1000); reserveRcb(rc, connection); + + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_RESERVED, NULL, DATA_ACCESS_ERROR_SUCCESS); + } } } @@ -2049,18 +2130,22 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme } else if (strcmp(elementName, "ConfRev") == 0) { retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + goto exit_function; } else if (strcmp(elementName, "SqNum") == 0) { retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + goto exit_function; } else if (strcmp(elementName, "Owner") == 0) { retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + goto exit_function; } else if (strcmp(elementName, "TimeofEntry") == 0) { retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + goto exit_function; } @@ -2073,6 +2158,7 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme } else { retVal = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + goto exit_function; } @@ -2118,6 +2204,10 @@ exit_function: updateGenericTrackingObjectValues(self, rc, IEC61850_SERVICE_TYPE_SET_URCB_VALUES, retVal); #endif /* (CONFIG_IEC61850_SERVICE_TRACKING == 1) */ + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_SET_PARAMETER, elementName, retVal); + } + return retVal; } From 83e21e207b5f630080de04df1b7f691b0028dc4e Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Sat, 22 Jan 2022 15:57:46 +0100 Subject: [PATCH 02/11] - added additional events for IedServer_RCBEventHandler --- src/iec61850/inc/iec61850_server.h | 7 ++- src/iec61850/server/mms_mapping/reporting.c | 50 ++++++++++++++++++++- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index b2953226..902e4de3 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -1554,7 +1554,12 @@ typedef enum { /** * \brief Callback that is called in case of RCB event * - * \param parameter user provided paramter + * \param parameter user provided parameter + * \param rcb affected report control block + * \param connection client connection that is involved + * \param event event type + * \param parameterName name of the parameter in case of RCB_EVENT_SET_PARAMETER + * \param serviceError service error in case of RCB_EVENT_SET_PARAMETER */ typedef void (*IedServer_RCBEventHandler) (void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType event, const char* parameterName, MmsDataAccessError serviceError); diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c index 919ae346..45433427 100644 --- a/src/iec61850/server/mms_mapping/reporting.c +++ b/src/iec61850/server/mms_mapping/reporting.c @@ -1591,6 +1591,12 @@ checkReservationTimeout(MmsMapping* self, ReportControl* rc) copyRCBValuesToTrackingObject(self, rc); updateGenericTrackingObjectValues(self, rc, IEC61850_SERVICE_TYPE_INTERNAL_CHANGE, DATA_ACCESS_ERROR_SUCCESS); #endif /* (CONFIG_IEC61850_SERVICE_TRACKING == 1) */ + + if (self->rcbEventHandler) { + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, rc->clientConnection); + + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_UNRESERVED, NULL, DATA_ACCESS_ERROR_SUCCESS); + } } } } @@ -1695,6 +1701,10 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme if (isIpAddressMatchingWithOwner(rc, MmsServerConnection_getClientAddress(connection))) { rc->reserved = true; rc->clientConnection = connection; + + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_RESERVED, NULL, DATA_ACCESS_ERROR_SUCCESS); + } } else { if (DEBUG_IED_SERVER) @@ -1703,6 +1713,10 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme #else rc->reserved = true; rc->clientConnection = connection; + + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_RESERVED, NULL, DATA_ACCESS_ERROR_SUCCESS); + } #endif } @@ -1914,6 +1928,10 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme if (rc->resvTms == -1) dontUpdate = true; + + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_UNRESERVED, NULL, DATA_ACCESS_ERROR_SUCCESS); + } } } @@ -2178,13 +2196,25 @@ exit_function: rc->resvTms = RESV_TMS_IMPLICIT_VALUE; reserveRcb(rc, connection); + + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_RESERVED, NULL, DATA_ACCESS_ERROR_SUCCESS); + } } else if (rc->resvTms == -1) { reserveRcb(rc, connection); + + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_RESERVED, NULL, DATA_ACCESS_ERROR_SUCCESS); + } } } else { reserveRcb(rc, connection); + + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_RESERVED, NULL, DATA_ACCESS_ERROR_SUCCESS); + } } } @@ -2214,13 +2244,29 @@ exit_function: static void Reporting_disableReportControlInstance(MmsMapping* self, ReportControl* rc) { + if (rc->enabled) { + if (self->rcbEventHandler) { + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, rc->clientConnection); + + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_DISABLE, NULL, DATA_ACCESS_ERROR_SUCCESS); + } + } + rc->enabled = false; rc->clientConnection = NULL; MmsValue* rptEna = ReportControl_getRCBValue(rc, "RptEna"); MmsValue_setBoolean(rptEna, false); - rc->reserved = false; + if (rc->reserved) { + rc->reserved = false; + + if (self->rcbEventHandler) { + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, rc->clientConnection); + + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_UNRESERVED, NULL, DATA_ACCESS_ERROR_SUCCESS); + } + } if (rc->buffered == false) { @@ -2239,7 +2285,7 @@ Reporting_disableReportControlInstance(MmsMapping* self, ReportControl* rc) if (rc->resvTms == 0) updateOwner(rc, NULL); else if (rc->resvTms > 0) { - rc->reservationTimeout = Hal_getTimeInMs() + (rc->resvTms * 1000); + rc->reservationTimeout = Hal_getTimeInMs() + (rc->resvTms * 1000); } } From 94563cb9f62805000d03f316710737bb6539ec87 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Sat, 22 Jan 2022 19:41:02 +0100 Subject: [PATCH 03/11] - additional methods for ReportControlBlock --- src/iec61850/inc/iec61850_dynamic_model.h | 32 +++++++++++++++++++++++ src/iec61850/server/model/dynamic_model.c | 18 +++++++++++++ 2 files changed, 50 insertions(+) diff --git a/src/iec61850/inc/iec61850_dynamic_model.h b/src/iec61850/inc/iec61850_dynamic_model.h index cd8a421f..8a94940a 100644 --- a/src/iec61850/inc/iec61850_dynamic_model.h +++ b/src/iec61850/inc/iec61850_dynamic_model.h @@ -211,6 +211,38 @@ ReportControlBlock_create(const char* name, LogicalNode* parent, const char* rpt LIB61850_API void ReportControlBlock_setPreconfiguredClient(ReportControlBlock* self, uint8_t clientType, const uint8_t* clientAddress); +/** + * \brief Get the name of the RCB instance + * + * NOTE: the returned string is only valid during the lifetime of the ReportControlBlock instance! + * + * \param self the RCB instance + * + * \return the RCB instance name + */ +LIB61850_API const char* +ReportControlBlock_getName(ReportControlBlock* self); + +/** + * \brief Is the RCB buffered or unbuffered? + * + * \param self the RCB instance + * + * \return true, in case of a buffered RCB, false otherwise + */ +LIB61850_API bool +ReportControlBlock_isBuffered(ReportControlBlock* self); + +/** + * \brief Get the parent (LogicalNode) of the RCB instance + * + * \param self the RCB instance + * + * \return the parent (LogicalNode) of the RCB instance + */ +LIB61850_API LogicalNode* +ReportControlBlock_getParent(ReportControlBlock* self); + /** * \brief create a new log control block (LCB) * diff --git a/src/iec61850/server/model/dynamic_model.c b/src/iec61850/server/model/dynamic_model.c index 043bdc29..69406330 100644 --- a/src/iec61850/server/model/dynamic_model.c +++ b/src/iec61850/server/model/dynamic_model.c @@ -383,6 +383,24 @@ ReportControlBlock_setPreconfiguredClient(ReportControlBlock* self, uint8_t clie } } +const char* +ReportControlBlock_getName(ReportControlBlock* self) +{ + return self->name; +} + +LogicalNode* +ReportControlBlock_getParent(ReportControlBlock* self) +{ + return self->parent; +} + +bool +ReportControlBlock_isBuffered(ReportControlBlock* self) +{ + return self->buffered; +} + #if (CONFIG_IEC61850_SETTING_GROUPS == 1) static void LogicalNode_addSettingGroupControlBlock(LogicalNode* self, SettingGroupControlBlock* sgcb) From d036b09712945cd9ccbcc52c026d2d744d048969 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Sat, 22 Jan 2022 19:42:01 +0100 Subject: [PATCH 04/11] - added .NET wrapper for RCBEventHandler --- dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs | 157 +++++++++++++++++- dotnet/server1/Program.cs | 12 ++ 2 files changed, 168 insertions(+), 1 deletion(-) diff --git a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs index 4cdfbf11..38a1df17 100644 --- a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs @@ -1,7 +1,7 @@ /* * IEC61850ServerAPI.cs * - * Copyright 2016 Michael Zillgith + * Copyright 2016-2022 Michael Zillgith * * This file is part of libIEC61850. * @@ -331,12 +331,19 @@ namespace IEC61850 this.parent = parent; } + internal Dictionary rcbs = new Dictionary(); + public LogicalNode(string name, LogicalDevice parent) { this.parent = parent; base.self = LogicalNode_create(name, parent.self); } + + internal void AddRcb(ReportControlBlock rcb) + { + rcbs.Add(rcb.self, rcb); + } } public enum AccessPolicy { @@ -1301,12 +1308,27 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void ReportControlBlock_setPreconfiguredClient(IntPtr self, byte type, [Out] byte[] buf); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern string ReportControlBlock_getName(IntPtr self); + public IntPtr self = IntPtr.Zero; + private string name = null; + private LogicalNode parent = null; + public ReportControlBlock(string name, LogicalNode parent, string rptId, bool isBuffered, string dataSetName, uint confRev, byte trgOps, byte options, uint bufTm, uint intgPd) { self = ReportControlBlock_create(name, parent.self, rptId, isBuffered, dataSetName, confRev, trgOps, options, bufTm, intgPd); + parent.AddRcb(this); + this.parent = parent; + } + + internal ReportControlBlock(IntPtr self, LogicalNode parent) + { + this.parent = parent; + this.self = self; + parent.AddRcb(this); } public void SetPreconfiguredClient(byte[] clientAddress) @@ -1316,6 +1338,28 @@ namespace IEC61850 else if (clientAddress.Length == 6) ReportControlBlock_setPreconfiguredClient(self, 6, clientAddress); } + + public string Name + { + get + { + if (name == null) + { + name = ReportControlBlock_getName(self); + } + + return name; + } + } + + public LogicalNode Parent + { + get + { + return parent; + } + } + } /// @@ -1691,6 +1735,47 @@ namespace IEC61850 public delegate void GoCBEventHandler(MmsGooseControlBlock goCB, int cbEvent, object parameter); + /// + /// Report control block event types + /// + public enum RCBEventType + { + /// + /// parameter read by client (not implemented). + /// + GET_PARAMETER = 0, + /// + /// parameter set by client. + /// + SET_PARAMETER = 1, + /// + /// reservation canceled. + /// + UNRESERVED = 2, + /// + /// reservation + /// + RESERVED = 3, + /// + /// RCB enabled + /// + ENABLED = 4, + /// + /// RCB disabled + /// + DISABLED = 5, + /// + /// GI report triggered + /// + GI = 6, + /// + /// Purge buffer procedure executed + /// + PURGEBUF = 7 + } + + public delegate void RCBEventHandler(object parameter, ReportControlBlock rcb, ClientConnection con, RCBEventType eventType, string parameterName, MmsDataAccessError serviceError); + public delegate MmsDataAccessError WriteAccessHandler (DataAttribute dataAttr, MmsValue value, ClientConnection connection, object parameter); @@ -1917,6 +2002,12 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void IedServer_setGoCBHandler(IntPtr self, InternalGoCBEventHandler handler, IntPtr parameter); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate void InternalRCBEventHandler(IntPtr paramter, IntPtr rcb, IntPtr connection, int eventType, string parameterName, int serviceError); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void IedServer_setRCBEventHandler(IntPtr self, InternalRCBEventHandler handler, IntPtr parameter); + private IntPtr self = IntPtr.Zero; private InternalControlHandler internalControlHandlerRef = null; @@ -2561,6 +2652,70 @@ namespace IEC61850 } } + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr ReportControlBlock_getParent(IntPtr self); + + + private RCBEventHandler rcbEventHandler = null; + private object rcbEventHandlerParameter = null; + + private InternalRCBEventHandler internalRCBEventHandler = null; + + private void InternalRCBEventHandlerImplementation(IntPtr parameter, IntPtr rcb, IntPtr connection, int eventType, string parameterName, int serviceError) + { + if (rcbEventHandler != null) + { + ClientConnection con = null; + + if (connection != IntPtr.Zero) + { + this.clientConnections.TryGetValue(connection, out con); + } + + ReportControlBlock reportControlBlock = null; + + if (rcb != IntPtr.Zero) + { + IntPtr lnPtr = ReportControlBlock_getParent(rcb); + + if (lnPtr != IntPtr.Zero) + { + ModelNode lnModelNode = iedModel.GetModelNodeFromNodeRef(lnPtr); + + if (lnModelNode != null) + { + LogicalNode ln = lnModelNode as LogicalNode; + + if (ln.rcbs.TryGetValue(rcb, out reportControlBlock) == false) + { + reportControlBlock = new ReportControlBlock(rcb, ln); + } + } + } + } + + rcbEventHandler.Invoke(rcbEventHandlerParameter, reportControlBlock, con, (RCBEventType)eventType, parameterName, (MmsDataAccessError)serviceError); + } + } + + /// + /// Set a callback handler for RCB events + /// + /// the callback handler + /// user provided parameter that is passed to the callback handler + public void SetRCBEventHandler(RCBEventHandler handler, object parameter) + { + rcbEventHandler = handler; + rcbEventHandlerParameter = parameter; + + if (internalRCBEventHandler == null) + { + internalRCBEventHandler = new InternalRCBEventHandler(InternalRCBEventHandlerImplementation); + + IedServer_setRCBEventHandler(self, internalRCBEventHandler, IntPtr.Zero); + } + } + } } diff --git a/dotnet/server1/Program.cs b/dotnet/server1/Program.cs index 569ba74d..c00e097b 100644 --- a/dotnet/server1/Program.cs +++ b/dotnet/server1/Program.cs @@ -67,6 +67,18 @@ namespace server1 }, null); + 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 (eventType == RCBEventType.SET_PARAMETER) + { + Console.WriteLine(" param: " + parameterName); + Console.WriteLine(" result: " + serviceError.ToString()); + } + + }, null); + iedServer.Start(102); if (iedServer.IsRunning()) From b27681f408fe7955815436f06ab94ff99cd29e0d Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Mon, 24 Jan 2022 09:53:43 +0100 Subject: [PATCH 05/11] - implemented GET_PARAMETER event for IedServer_RCBEventHandler - implemented additional access functions for ReportControlBlock to allow access to runtime values --- dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs | 73 +++++++++++++ dotnet/server1/Program.cs | 9 +- .../server_example_basic_io.c | 23 ++++ src/iec61850/inc/iec61850_dynamic_model.h | 18 ++++ src/iec61850/inc/iec61850_model.h | 4 +- src/iec61850/inc_private/reporting.h | 3 +- src/iec61850/server/mms_mapping/mms_mapping.c | 20 +++- src/iec61850/server/mms_mapping/reporting.c | 102 +++++++++++++++++- 8 files changed, 245 insertions(+), 7 deletions(-) diff --git a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs index 38a1df17..82018ad9 100644 --- a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs @@ -1311,6 +1311,28 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern string ReportControlBlock_getName(IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + static extern bool ReportControlBlock_getRptEna(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr ReportControlBlock_getRptID(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr ReportControlBlock_getDataSet(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern int ReportControlBlock_getTrgOps(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt32 ReportControlBlock_getIntgPd(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr ReportControlBlock_getOwner(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void Memory_free(IntPtr self); + public IntPtr self = IntPtr.Zero; private string name = null; @@ -1360,6 +1382,57 @@ namespace IEC61850 } } + public bool RptEna + { + get + { + return ReportControlBlock_getRptEna(self); + } + } + + public string RptID + { + get + { + IntPtr rptIdPtr = ReportControlBlock_getRptID(self); + + string rptId = Marshal.PtrToStringAnsi(rptIdPtr); + + Memory_free(rptIdPtr); + + return rptId; + } + } + + public string DataSet + { + get + { + IntPtr dataSetPtr = ReportControlBlock_getDataSet(self); + + string dataSet = Marshal.PtrToStringAnsi(dataSetPtr); + + Memory_free(dataSetPtr); + + return dataSet; + } + } + + public TriggerOptions TrgOps + { + get + { + return (TriggerOptions)ReportControlBlock_getTrgOps(self); + } + } + + public UInt32 IntgPd + { + get + { + return ReportControlBlock_getIntgPd(self); + } + } } /// diff --git a/dotnet/server1/Program.cs b/dotnet/server1/Program.cs index c00e097b..2d2801dc 100644 --- a/dotnet/server1/Program.cs +++ b/dotnet/server1/Program.cs @@ -71,7 +71,14 @@ namespace server1 { Console.WriteLine("RCB: " + rcb.Parent.GetObjectReference() + "." + rcb.Name + " event: " + eventType.ToString()); - if (eventType == RCBEventType.SET_PARAMETER) + if (eventType == RCBEventType.ENABLED) + { + //Console.WriteLine(" RptID: " + rcb.RptID); + //Console.WriteLine(" DatSet: " + rcb.DataSet); + Console.WriteLine(" TrgOps: " + rcb.TrgOps.ToString()); + } + + if ((eventType == RCBEventType.SET_PARAMETER) || (eventType == RCBEventType.GET_PARAMETER)) { Console.WriteLine(" param: " + parameterName); Console.WriteLine(" result: " + serviceError.ToString()); diff --git a/examples/server_example_basic_io/server_example_basic_io.c b/examples/server_example_basic_io/server_example_basic_io.c index b6f86630..66914aa1 100644 --- a/examples/server_example_basic_io/server_example_basic_io.c +++ b/examples/server_example_basic_io/server_example_basic_io.c @@ -79,6 +79,27 @@ connectionHandler (IedServer self, ClientConnection connection, bool connected, printf("Connection closed\n"); } +static void +rcbEventHandler(void* parameter, ReportControlBlock* rcb, ClientConnection connection, IedServer_RCBEventType event, const char* parameterName, MmsDataAccessError serviceError) +{ + printf("RCB: %s event: %i\n", ReportControlBlock_getName(rcb), event); + + if ((event == RCB_EVENT_SET_PARAMETER) || (event == RCB_EVENT_GET_PARAMETER)) { + printf(" param: %s\n", parameterName); + printf(" result: %i\n", serviceError); + } + + if (event == RCB_EVENT_ENABLE) { + char* rptId = ReportControlBlock_getRptID(rcb); + printf(" rptID: %s\n", rptId); + char* dataSet = ReportControlBlock_getDataSet(rcb); + printf(" datSet: %s\n", dataSet); + + free(rptId); + free(dataSet); + } +} + int main(int argc, char** argv) { @@ -136,6 +157,8 @@ main(int argc, char** argv) IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionHandler, NULL); + IedServer_setRCBEventHandler(iedServer, rcbEventHandler, NULL); + /* 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. diff --git a/src/iec61850/inc/iec61850_dynamic_model.h b/src/iec61850/inc/iec61850_dynamic_model.h index 8a94940a..2a6eec4d 100644 --- a/src/iec61850/inc/iec61850_dynamic_model.h +++ b/src/iec61850/inc/iec61850_dynamic_model.h @@ -243,6 +243,24 @@ ReportControlBlock_isBuffered(ReportControlBlock* self); LIB61850_API LogicalNode* ReportControlBlock_getParent(ReportControlBlock* self); +LIB61850_API int +ReportControlBlock_getRptEna(ReportControlBlock* self); + +LIB61850_API char* +ReportControlBlock_getRptID(ReportControlBlock* self); + +LIB61850_API char* +ReportControlBlock_getDataSet(ReportControlBlock* self); + +LIB61850_API int +ReportControlBlock_getTrgOps(ReportControlBlock* self); + +LIB61850_API uint32_t +ReportControlBlock_getIntgPd(ReportControlBlock* self); + +LIB61850_API MmsValue* +ReportControlBlock_getOwner(ReportControlBlock* self); + /** * \brief create a new log control block (LCB) * diff --git a/src/iec61850/inc/iec61850_model.h b/src/iec61850/inc/iec61850_model.h index e0d54860..6681f5d5 100644 --- a/src/iec61850/inc/iec61850_model.h +++ b/src/iec61850/inc/iec61850_model.h @@ -269,7 +269,9 @@ struct sReportControlBlock { type can be one of (0 - no reservation, 4 - IPv4 client, 6 - IPv6 client) */ uint8_t clientReservation[17]; - ReportControlBlock* sibling; /* next control block in list or NULL if this is the last entry */ + ReportControlBlock* sibling; /* next control block in list or NULL if this is the last entry + * at runtime reuse as pointer to ReportControl instance! + **/ }; struct sLogControlBlock { diff --git a/src/iec61850/inc_private/reporting.h b/src/iec61850/inc_private/reporting.h index 4102e1c1..24537a56 100644 --- a/src/iec61850/inc_private/reporting.h +++ b/src/iec61850/inc_private/reporting.h @@ -107,6 +107,7 @@ typedef struct { MmsValue* timeOfEntry; ReportControlBlock* rcb; + ReportControlBlock* sibling; /* backup sibling field of original ReportControlBlock */ IedServer server; } ReportControl; @@ -136,7 +137,7 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme MmsServerConnection connection); LIB61850_INTERNAL void -ReportControl_readAccess(ReportControl* rc, MmsMapping* mmsMapping, char* elementName); +ReportControl_readAccess(ReportControl* rc, MmsMapping* mmsMapping, MmsServerConnection connection, char* elementName); LIB61850_INTERNAL void Reporting_activateBufferedReports(MmsMapping* self); diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index e65f426e..4547a97d 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -2034,6 +2034,24 @@ MmsMapping_create(IedModel* model, IedServer iedServer) MmsMapping_destroy(self); self = NULL; } + else { + LinkedList rcElem = LinkedList_getNext(self->reportControls); + + while (rcElem) { + ReportControl* rc = (ReportControl*)LinkedList_getData(rcElem); + + /* backup original sibling of ReportControlBlock */; + rc->sibling = rc->rcb->sibling; + + /* reuse ReportControlBlock.sibling as reference to runtime information (ReportControl) */ + rc->rcb->sibling = (ReportControlBlock*)rc; + + /* set runtime mode flag (indicate that sibling field contains now runtime information reference!) */ + rc->rcb->trgOps |= 64; + + rcElem = LinkedList_getNext(rcElem); + } + } return self; } @@ -3075,7 +3093,7 @@ mmsReadHandler(void* parameter, MmsDomain* domain, char* variableId, MmsServerCo char* elementName = MmsMapping_getNextNameElement(reportName); - ReportControl_readAccess(rc, self, elementName); + ReportControl_readAccess(rc, self, connection, elementName); MmsValue* value = NULL; diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c index 45433427..33a8b209 100644 --- a/src/iec61850/server/mms_mapping/reporting.c +++ b/src/iec61850/server/mms_mapping/reporting.c @@ -226,6 +226,10 @@ ReportControl_destroy(ReportControl* self) } } + /* restore original sibling of ReportControlBlock */ + self->rcb->sibling = self->sibling; + self->rcb->trgOps &= ~(64); /* clear runtime mode flag */ + ReportBuffer_destroy(self->reportBuffer); #if (CONFIG_MMS_THREADLESS_STACK != 1) @@ -1603,16 +1607,20 @@ checkReservationTimeout(MmsMapping* self, ReportControl* rc) } void -ReportControl_readAccess(ReportControl* rc, MmsMapping* mmsMapping, char* elementName) +ReportControl_readAccess(ReportControl* rc, MmsMapping* mmsMapping, MmsServerConnection connection, char* elementName) { (void)elementName; - /* TODO add log message */ - /* check reservation timeout */ if (rc->buffered) { checkReservationTimeout(mmsMapping, rc); } + + if (mmsMapping->rcbEventHandler) { + ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(mmsMapping->iedServer, connection); + + mmsMapping->rcbEventHandler(mmsMapping->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_GET_PARAMETER, elementName, DATA_ACCESS_ERROR_SUCCESS); + } } static bool @@ -3642,4 +3650,92 @@ ReportControl_valueUpdated(ReportControl* self, int dataSetEntryIndex, int flag, ReportControl_unlockNotify(self); } +int +ReportControlBlock_getRptEna(ReportControlBlock* self) +{ + if (self->trgOps & 64) { + ReportControl* rc = (ReportControl*)(self->sibling); + + return rc->enabled; + } + else { + return false; + } +} + +char* +ReportControlBlock_getRptID(ReportControlBlock* self) +{ + if (self->trgOps & 64) { + ReportControl* rc = (ReportControl*)(self->sibling); + + MmsValue* rptIdValue = ReportControl_getRCBValue(rc, "RptID"); + + return strdup(MmsValue_toString(rptIdValue)); + } + else { + return self->rptId; + } +} + +char* +ReportControlBlock_getDataSet(ReportControlBlock* self) +{ + if (self->trgOps & 64) { + ReportControl* rc = (ReportControl*)(self->sibling); + + MmsValue* dataSetValue = ReportControl_getRCBValue(rc, "DatSet"); + + return strdup(MmsValue_toString(dataSetValue)); + } + else { + return self->dataSetName; + } +} + +int +ReportControlBlock_getTrgOps(ReportControlBlock* self) +{ + if (self->trgOps & 64) { + ReportControl* rc = (ReportControl*)(self->sibling); + + return rc->triggerOps; + } + else { + return (int)(self->trgOps); + } +} + +uint32_t +ReportControlBlock_getIntgPd(ReportControlBlock* self) +{ + if (self->trgOps & 64) { + ReportControl* rc = (ReportControl*)(self->sibling); + + return rc->intgPd; + } + else { + return self->intPeriod; + } +} + +MmsValue* +ReportControlBlock_getOwner(ReportControlBlock* self) +{ + if (self->trgOps & 64) { + ReportControl* rc = (ReportControl*)(self->sibling); + + if (rc->hasOwner) { + return ReportControl_getRCBValue(rc, "Owner"); + } + else + return NULL; + } + else { + return NULL; + } +} + + + #endif /* (CONFIG_IEC61850_REPORT_SERVICE == 1) */ From b374644d308416292127709784fac6002e2e9246 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Mon, 24 Jan 2022 07:13:37 -0500 Subject: [PATCH 06/11] - added functions Timestamp_fromMmsValue and Quality_toMmsValue --- src/iec61850/common/iec61850_common.c | 35 ++++++++++++++++++++++++++- src/iec61850/inc/iec61850_common.h | 14 +++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/iec61850/common/iec61850_common.c b/src/iec61850/common/iec61850_common.c index 20962e43..66530c96 100644 --- a/src/iec61850/common/iec61850_common.c +++ b/src/iec61850/common/iec61850_common.c @@ -1,7 +1,7 @@ /* * iec61850_common.c * - * Copyright 2013-2020 Michael Zillgith + * Copyright 2013-2022 Michael Zillgith * * This file is part of libIEC61850. * @@ -70,6 +70,20 @@ Quality_fromMmsValue(const MmsValue* mmsValue) return (Quality) MmsValue_getBitStringAsInteger(mmsValue); } +MmsValue* +Quality_toMmsValue(Quality* self, MmsValue* mmsValue) +{ + if (mmsValue == NULL) { + mmsValue = MmsValue_newBitString(13); + } + + if (mmsValue) { + MmsValue_setBitStringFromInteger(mmsValue, *self); + } + + return mmsValue; +} + Dbpos Dbpos_fromMmsValue(const MmsValue* mmsValue) { @@ -491,6 +505,25 @@ Timestamp_toMmsValue(Timestamp* self, MmsValue* mmsValue) return convertedValue; } +Timestamp* +Timestamp_fromMmsValue(Timestamp* self, MmsValue* mmsValue) +{ + if (mmsValue->type == MMS_UTC_TIME) { + + if (self == NULL) + self = Timestamp_create(); + + if (self) { + memcpy(self->val, mmsValue->value.utcTime, 8); + } + + return self; + } + else { + return NULL; + } +} + char* MmsMapping_getMmsDomainFromObjectReference(const char* objectReference, char* buffer) { diff --git a/src/iec61850/inc/iec61850_common.h b/src/iec61850/inc/iec61850_common.h index 335b6ea4..e8374072 100644 --- a/src/iec61850/inc/iec61850_common.h +++ b/src/iec61850/inc/iec61850_common.h @@ -370,6 +370,9 @@ Quality_isFlagSet(Quality* self, int flag); LIB61850_API Quality Quality_fromMmsValue(const MmsValue* mmsValue); +LIB61850_API MmsValue* +Quality_toMmsValue(Quality* self, MmsValue* mmsValue); + /** @} */ /** @@ -515,6 +518,17 @@ Timestamp_setByMmsUtcTime(Timestamp* self, const MmsValue* mmsValue); LIB61850_API MmsValue* Timestamp_toMmsValue(Timestamp* self, MmsValue* mmsValue); +/** + * \brief Get the Timestamp value from an MmsValue instance of type MMS_UTC_TIME + * + * \param self the Timestamp instance or NULL to create a new instance + * \param mmsValue the mmsValue instance of type MMS_UTC_TIME + * + * \return the updated Timestamp value or NULL in case of an error + */ +LIB61850_API Timestamp* +Timestamp_fromMmsValue(Timestamp* self, MmsValue* mmsValue); + /** * \brief Get the version of the library as string * From 81b26f1cb68fb52c6559690ee906728df7a095c8 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Mon, 24 Jan 2022 19:55:56 +0100 Subject: [PATCH 07/11] - added more ReportControlBlock methods --- src/iec61850/inc/iec61850_dynamic_model.h | 35 ++++- src/iec61850/server/mms_mapping/reporting.c | 155 +++++++++++++++++++- 2 files changed, 185 insertions(+), 5 deletions(-) diff --git a/src/iec61850/inc/iec61850_dynamic_model.h b/src/iec61850/inc/iec61850_dynamic_model.h index 2a6eec4d..71cc901d 100644 --- a/src/iec61850/inc/iec61850_dynamic_model.h +++ b/src/iec61850/inc/iec61850_dynamic_model.h @@ -243,21 +243,48 @@ ReportControlBlock_isBuffered(ReportControlBlock* self); LIB61850_API LogicalNode* ReportControlBlock_getParent(ReportControlBlock* self); -LIB61850_API int -ReportControlBlock_getRptEna(ReportControlBlock* self); - LIB61850_API char* ReportControlBlock_getRptID(ReportControlBlock* self); +LIB61850_API int +ReportControlBlock_getRptEna(ReportControlBlock* self); + LIB61850_API char* ReportControlBlock_getDataSet(ReportControlBlock* self); -LIB61850_API int +LIB61850_API uint32_t +ReportControlBlock_getConfRev(ReportControlBlock* self); + +LIB61850_API uint32_t +ReportControlBlock_getOptFlds(ReportControlBlock* self); + +LIB61850_API uint32_t +ReportControlBlock_getBufTm(ReportControlBlock* self); + +LIB61850_API uint16_t +ReportControlBlock_getSqNum(ReportControlBlock* self); + +LIB61850_API uint32_t ReportControlBlock_getTrgOps(ReportControlBlock* self); LIB61850_API uint32_t ReportControlBlock_getIntgPd(ReportControlBlock* self); +LIB61850_API bool +ReportControlBlock_getGI(ReportControlBlock* self); + +LIB61850_API bool +ReportControlBlock_getPurgeBuf(ReportControlBlock* self); + +LIB61850_API MmsValue* +ReportControlBlock_getEntryId(ReportControlBlock* self); + +LIB61850_API uint64_t +ReportControlBlock_getTimeofEntry(ReportControlBlock* self); + +LIB61850_API int16_t +ReportControlBlock_getResvTms(ReportControlBlock* self); + LIB61850_API MmsValue* ReportControlBlock_getOwner(ReportControlBlock* self); diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c index 33a8b209..09d17d57 100644 --- a/src/iec61850/server/mms_mapping/reporting.c +++ b/src/iec61850/server/mms_mapping/reporting.c @@ -3693,7 +3693,75 @@ ReportControlBlock_getDataSet(ReportControlBlock* self) } } -int +uint32_t +ReportControlBlock_getConfRev(ReportControlBlock* self) +{ + if (self->trgOps & 64) { + ReportControl* rc = (ReportControl*)(self->sibling); + + MmsValue* confRevValue = ReportControl_getRCBValue(rc, "ConfRev"); + + uint32_t confRev = MmsValue_toUint32(confRevValue); + + return confRev; + } + else { + return self->confRef; + } +} + +uint32_t +ReportControlBlock_getOptFlds(ReportControlBlock* self) +{ + if (self->trgOps & 64) { + ReportControl* rc = (ReportControl*)(self->sibling); + + MmsValue* optFldsValue = ReportControl_getRCBValue(rc, "OptFlds"); + + uint32_t optFlds = MmsValue_getBitStringAsInteger(optFldsValue) / 2; + + return optFlds; + } + else { + return self->options; + } +} + +uint32_t +ReportControlBlock_getBufTm(ReportControlBlock* self) +{ + if (self->trgOps & 64) { + ReportControl* rc = (ReportControl*)(self->sibling); + + MmsValue* bufTmValue = ReportControl_getRCBValue(rc, "BufTm"); + + uint32_t bufTm = MmsValue_toUint32(bufTmValue); + + return bufTm; + } + else { + return self->bufferTime; + } +} + +uint16_t +ReportControlBlock_getSqNum(ReportControlBlock* self) +{ + if (self->trgOps & 64) { + ReportControl* rc = (ReportControl*)(self->sibling); + + MmsValue* sqNumValue = ReportControl_getRCBValue(rc, "SqNum"); + + uint16_t sqNum = (uint16_t)MmsValue_toUint32(sqNumValue); + + return sqNum; + } + else { + return 0; + } +} + +uint32_t ReportControlBlock_getTrgOps(ReportControlBlock* self) { if (self->trgOps & 64) { @@ -3719,6 +3787,91 @@ ReportControlBlock_getIntgPd(ReportControlBlock* self) } } +bool +ReportControlBlock_getGI(ReportControlBlock* self) +{ + if (self->trgOps & 64) { + ReportControl* rc = (ReportControl*)(self->sibling); + + MmsValue* giValue = ReportControl_getRCBValue(rc, "GI"); + + bool gi = MmsValue_getBoolean(giValue); + + return gi; + } + else { + return false; + } +} + +bool +ReportControlBlock_getPurgeBuf(ReportControlBlock* self) +{ + if (self->trgOps & 64) { + ReportControl* rc = (ReportControl*)(self->sibling); + + MmsValue* purgeBufValue = ReportControl_getRCBValue(rc, "PurgeBuf"); + + bool purgeBuf = MmsValue_getBoolean(purgeBufValue); + + return purgeBuf; + } + else { + return false; + } +} + +MmsValue* +ReportControlBlock_getEntryId(ReportControlBlock* self) +{ + if (self->trgOps & 64) { + ReportControl* rc = (ReportControl*)(self->sibling); + + MmsValue* entryIdValue = ReportControl_getRCBValue(rc, "EntryID"); + + MmsValue* entryId = MmsValue_clone(entryIdValue); + + return entryId; + } + else { + return NULL; + } +} + +uint64_t +ReportControlBlock_getTimeofEntry(ReportControlBlock* self) +{ + if (self->trgOps & 64) { + ReportControl* rc = (ReportControl*)(self->sibling); + + MmsValue* timeofEntryValue = ReportControl_getRCBValue(rc, "TimeofEntry"); + + uint64_t timeofEntry = MmsValue_getBinaryTimeAsUtcMs(timeofEntryValue); + + return timeofEntry; + } + else { + return 0; + } +} + +int16_t +ReportControlBlock_getResvTms(ReportControlBlock* self) +{ + if (self->trgOps & 64) { + ReportControl* rc = (ReportControl*)(self->sibling); + + MmsValue* resvTmsValue = ReportControl_getRCBValue(rc, "ResvTms"); + + int16_t resvTms = (int16_t)MmsValue_toInt32(resvTmsValue); + + return resvTms; + } + else { + return 0; + } +} + MmsValue* ReportControlBlock_getOwner(ReportControlBlock* self) { From e06b4852585b976fdfa39772b421df72c7edb11e Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Tue, 25 Jan 2022 00:40:14 +0100 Subject: [PATCH 08/11] - ensure RESERVED event before ENABLE event --- src/iec61850/server/mms_mapping/reporting.c | 37 +++++++++++++++------ 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c index 09d17d57..6f2b95cb 100644 --- a/src/iec61850/server/mms_mapping/reporting.c +++ b/src/iec61850/server/mms_mapping/reporting.c @@ -1804,6 +1804,14 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme if (updateReportDataset(self, rc, NULL, connection)) { + if (rc->reserved == false) { + reserveRcb(rc, connection); + + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_RESERVED, NULL, DATA_ACCESS_ERROR_SUCCESS); + } + } + updateOwner(rc, connection); MmsValue* rptEna = ReportControl_getRCBValue(rc, "RptEna"); @@ -2201,27 +2209,36 @@ exit_function: rc->reservationTimeout = Hal_getTimeInMs() + (RESV_TMS_IMPLICIT_VALUE * 1000); if (rc->resvTms == 0) { - rc->resvTms = RESV_TMS_IMPLICIT_VALUE; - reserveRcb(rc, connection); + if (rc->reserved == false) { + rc->resvTms = RESV_TMS_IMPLICIT_VALUE; - if (self->rcbEventHandler) { - self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_RESERVED, NULL, DATA_ACCESS_ERROR_SUCCESS); + reserveRcb(rc, connection); + + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_RESERVED, NULL, DATA_ACCESS_ERROR_SUCCESS); + } } + + } else if (rc->resvTms == -1) { - reserveRcb(rc, connection); + if (rc->reserved == false) { + reserveRcb(rc, connection); - if (self->rcbEventHandler) { - self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_RESERVED, NULL, DATA_ACCESS_ERROR_SUCCESS); + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_RESERVED, NULL, DATA_ACCESS_ERROR_SUCCESS); + } } } } else { - reserveRcb(rc, connection); + if (rc->reserved == false) { + reserveRcb(rc, connection); - if (self->rcbEventHandler) { - self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_RESERVED, NULL, DATA_ACCESS_ERROR_SUCCESS); + if (self->rcbEventHandler) { + self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_RESERVED, NULL, DATA_ACCESS_ERROR_SUCCESS); + } } } } From c3191b28641785a0e4fb3f677c8b93f3bb8eac0e Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Tue, 25 Jan 2022 10:24:22 +0100 Subject: [PATCH 09/11] - .NET API: added additional properties for Server.ReportControlBlock --- dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs | 139 +++++++++++++++++- src/iec61850/server/mms_mapping/reporting.c | 8 +- 2 files changed, 143 insertions(+), 4 deletions(-) diff --git a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs index 82018ad9..40bbf830 100644 --- a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs @@ -1322,11 +1322,40 @@ namespace IEC61850 static extern IntPtr ReportControlBlock_getDataSet(IntPtr self); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern int ReportControlBlock_getTrgOps(IntPtr self); + static extern UInt32 ReportControlBlock_getConfRev(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt32 ReportControlBlock_getOptFlds(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt32 ReportControlBlock_getBufTm(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt16 ReportControlBlock_getSqNum(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt32 ReportControlBlock_getTrgOps(IntPtr self); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern UInt32 ReportControlBlock_getIntgPd(IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + static extern bool ReportControlBlock_getGI(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] + static extern bool ReportControlBlock_getPurgeBuf(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr ReportControlBlock_getEntryId(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt64 ReportControlBlock_getTimeofEntry(IntPtr self); + + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern UInt16 ReportControlBlock_getResvTms(IntPtr self); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern IntPtr ReportControlBlock_getOwner(IntPtr self); @@ -1418,6 +1447,38 @@ namespace IEC61850 } } + public UInt32 ConfRev + { + get + { + return ReportControlBlock_getConfRev(self); + } + } + + public ReportOptions OptFlds + { + get + { + return (ReportOptions)ReportControlBlock_getOptFlds(self); + } + } + + public UInt32 BufTm + { + get + { + return ReportControlBlock_getBufTm(self); + } + } + + public UInt16 SqNum + { + get + { + return ReportControlBlock_getSqNum(self); + } + } + public TriggerOptions TrgOps { get @@ -1433,6 +1494,82 @@ namespace IEC61850 return ReportControlBlock_getIntgPd(self); } } + + public bool GI + { + get + { + return ReportControlBlock_getGI(self); + } + } + + public bool PurgeBuf + { + get + { + return ReportControlBlock_getPurgeBuf(self); + } + } + + public byte[] EntryID + { + get + { + IntPtr entryIdPtr = ReportControlBlock_getEntryId(self); + + if (entryIdPtr != IntPtr.Zero) + { + byte[] entryId = null; + + MmsValue octetStringVal = new MmsValue(entryIdPtr, true); + + entryId = octetStringVal.getOctetString(); + + return entryId; + } + else + return null; + } + } + + public UInt64 TimeofEntry + { + get + { + return ReportControlBlock_getTimeofEntry(self); + } + } + + public UInt16 ResvTms + { + get + { + return ReportControlBlock_getResvTms(self); + } + } + + public byte[] Owner + { + get + { + IntPtr mmsValuePtr = ReportControlBlock_getOwner(self); + + if (mmsValuePtr != IntPtr.Zero) + { + byte[] owner = null; + + MmsValue octetStringVal = new MmsValue(mmsValuePtr, true); + + owner = octetStringVal.getOctetString(); + + return owner; + } + else + return null; + } + + } + } /// diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c index 6f2b95cb..ac90581e 100644 --- a/src/iec61850/server/mms_mapping/reporting.c +++ b/src/iec61850/server/mms_mapping/reporting.c @@ -3896,7 +3896,11 @@ ReportControlBlock_getOwner(ReportControlBlock* self) ReportControl* rc = (ReportControl*)(self->sibling); if (rc->hasOwner) { - return ReportControl_getRCBValue(rc, "Owner"); + MmsValue* ownerValue = ReportControl_getRCBValue(rc, "Owner"); + + MmsValue* ownerValueCopy = MmsValue_clone(ownerValue); + + return ownerValueCopy; } else return NULL; @@ -3906,6 +3910,4 @@ ReportControlBlock_getOwner(ReportControlBlock* self) } } - - #endif /* (CONFIG_IEC61850_REPORT_SERVICE == 1) */ From a7362928f4093a773de17ec7abcd9e69067c5110 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Tue, 25 Jan 2022 20:48:51 +0100 Subject: [PATCH 10/11] - added semaphore for server side RCB value access --- src/iec61850/inc_private/reporting.h | 7 +- src/iec61850/server/mms_mapping/mms_mapping.c | 13 + src/iec61850/server/mms_mapping/reporting.c | 369 +++++++++++++++++- src/mms/inc_private/mms_server_libinternal.h | 2 +- src/mms/iso_mms/server/mms_read_service.c | 22 +- 5 files changed, 383 insertions(+), 30 deletions(-) diff --git a/src/iec61850/inc_private/reporting.h b/src/iec61850/inc_private/reporting.h index 24537a56..80be1900 100644 --- a/src/iec61850/inc_private/reporting.h +++ b/src/iec61850/inc_private/reporting.h @@ -53,8 +53,13 @@ typedef struct { LogicalNode* parentLN; MmsValue* rcbValues; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore rcbValuesLock; +#endif + MmsValue* inclusionField; - MmsValue* confRev; + MmsValue* confRev; /* TODO Is this field required? */ DataSet* dataSet; bool isDynamicDataSet; diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index 4547a97d..424c6bb7 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -3097,11 +3097,24 @@ mmsReadHandler(void* parameter, MmsDomain* domain, char* variableId, MmsServerCo MmsValue* value = NULL; +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + if (elementName != NULL) value = ReportControl_getRCBValue(rc, elementName); else value = rc->rcbValues; + if (value) { + value = MmsValue_clone(value); + MmsValue_setDeletableRecursive(value); + } + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + retValue = value; goto exit_function; diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c index ac90581e..463b9570 100644 --- a/src/iec61850/server/mms_mapping/reporting.c +++ b/src/iec61850/server/mms_mapping/reporting.c @@ -101,6 +101,11 @@ ReportControl_create(bool buffered, LogicalNode* parentLN, int reportBufferSize, self->domain = NULL; self->parentLN = parentLN; self->rcbValues = NULL; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + self->rcbValuesLock = Semaphore_create(1); +#endif + self->confRev = NULL; self->subSeqVal = MmsValue_newUnsigned(16); self->segmented = false; @@ -234,6 +239,7 @@ ReportControl_destroy(ReportControl* self) #if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_destroy(self->createNotificationsMutex); + Semaphore_destroy(self->rcbValuesLock); #endif GLOBAL_FREEMEM(self->name); @@ -325,6 +331,10 @@ ReportControl_getRCBValue(ReportControl* rc, char* elementName) static void copyRCBValuesToTrackingObject(MmsMapping* self, ReportControl* rc) { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + if (rc->buffered) { if (self->brcbTrk) { BrcbTrkInstance trkInst = self->brcbTrk; @@ -441,6 +451,10 @@ copyRCBValuesToTrackingObject(MmsMapping* self, ReportControl* rc) MmsValue_update(trkInst->gi->mmsValue, ReportControl_getRCBValue(rc, "GI")); } } + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif } static void @@ -682,7 +696,6 @@ updateReportDataset(MmsMapping* mapping, ReportControl* rc, MmsValue* newDatSet, else dataSetValue = ReportControl_getRCBValue(rc, "DatSet"); - bool dataSetChanged = true; /* check if old and new data sets are the same */ @@ -725,7 +738,6 @@ updateReportDataset(MmsMapping* mapping, ReportControl* rc, MmsValue* newDatSet, } } - if (rc->isDynamicDataSet) { if (rc->dataSet && dataSetChanged) { deleteDataSetValuesShadowBuffer(rc); @@ -820,6 +832,7 @@ updateReportDataset(MmsMapping* mapping, ReportControl* rc, MmsValue* newDatSet, } exit_function: + return success; } @@ -886,6 +899,10 @@ createTrgOps(ReportControlBlock* reportControlBlock) { static void refreshTriggerOptions(ReportControl* rc) { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + rc->triggerOps = 0; MmsValue* trgOps = ReportControl_getRCBValue(rc, "TrgOps"); if (MmsValue_getBitStringBit(trgOps, 1)) @@ -902,14 +919,26 @@ refreshTriggerOptions(ReportControl* rc) if (MmsValue_getBitStringBit(trgOps, 5)) rc->triggerOps += TRG_OPT_GI; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif } static void refreshIntegrityPeriod(ReportControl* rc) { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* intgPd = ReportControl_getRCBValue(rc, "IntgPd"); rc->intgPd = MmsValue_toUint32(intgPd); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + if (rc->buffered == false) rc->nextIntgReportTime = Hal_getTimeInMs() + rc->intgPd; } @@ -917,8 +946,16 @@ refreshIntegrityPeriod(ReportControl* rc) static void refreshBufferTime(ReportControl* rc) { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* bufTm = ReportControl_getRCBValue(rc, "BufTm"); rc->bufTm = MmsValue_toUint32(bufTm); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif } static void @@ -1449,6 +1486,10 @@ updateOwner(ReportControl* rc, MmsServerConnection connection) { rc->clientConnection = connection; +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + if (rc->server->edition >= IEC_61850_EDITION_2 && rc->hasOwner) { MmsValue* owner = ReportControl_getRCBValue(rc, "Owner"); @@ -1510,6 +1551,10 @@ updateOwner(ReportControl* rc, MmsServerConnection connection) } } } + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif } static bool @@ -1581,9 +1626,16 @@ checkReservationTimeout(MmsMapping* self, ReportControl* rc) #if (CONFIG_IEC61850_BRCB_WITH_RESVTMS == 1) if (self->iedServer->enableBRCBResvTms) { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif MmsValue* resvTmsVal = ReportControl_getRCBValue(rc, "ResvTms"); if (resvTmsVal) MmsValue_setInt16(resvTmsVal, rc->resvTms); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif } #endif @@ -1626,34 +1678,53 @@ ReportControl_readAccess(ReportControl* rc, MmsMapping* mmsMapping, MmsServerCon static bool isIpAddressMatchingWithOwner(ReportControl* rc, const char* ipAddress) { + bool retVal = false; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* owner = ReportControl_getRCBValue(rc, "Owner"); if (owner != NULL) { - if (MmsValue_getOctetStringSize(owner) == 0) - return true; + if (MmsValue_getOctetStringSize(owner) == 0) { + retVal = true; + goto exit_function; + } if (strchr(ipAddress, '.') != NULL) { uint8_t ipV4Addr[4]; if (convertIPv4AddressStringToByteArray(ipAddress, ipV4Addr)) { - if (memcmp(ipV4Addr, MmsValue_getOctetStringBuffer(owner), 4) == 0) - return true; + if (memcmp(ipV4Addr, MmsValue_getOctetStringBuffer(owner), 4) == 0) { + retVal = true; + goto exit_function; + } } } else { uint8_t ipV6Addr[16]; if (StringUtils_convertIPv6AdddressStringToByteArray(ipAddress, ipV6Addr)) { - if (memcmp(ipV6Addr, MmsValue_getOctetStringBuffer(owner), 16) == 0) - return true; + if (memcmp(ipV6Addr, MmsValue_getOctetStringBuffer(owner), 16) == 0) { + retVal = true; + goto exit_function; + } + } + else { + goto exit_function; } - else - return false; } } - return false; +exit_function: + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + + return retVal; } static void @@ -1662,6 +1733,10 @@ reserveRcb(ReportControl* rc, MmsServerConnection connection) rc->reserved = true; rc->clientConnection = connection; +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + if (rc->buffered) { #if (CONFIG_IEC61850_BRCB_WITH_RESVTMS == 1) if (rc->server->enableBRCBResvTms) { @@ -1677,6 +1752,10 @@ reserveRcb(ReportControl* rc, MmsServerConnection connection) MmsValue_setBoolean(resvVal, true); } +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + updateOwner(rc, connection); } @@ -1814,10 +1893,17 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme updateOwner(rc, connection); - MmsValue* rptEna = ReportControl_getRCBValue(rc, "RptEna"); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* rptEna = ReportControl_getRCBValue(rc, "RptEna"); MmsValue_update(rptEna, value); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + if (rc->buffered) { if (rc->isResync == false) { @@ -1837,10 +1923,18 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme rc->sqNum = 0; +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* sqNum = ReportControl_getRCBValue(rc, "SqNum"); MmsValue_setUint32(sqNum, 0U); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + retVal = DATA_ACCESS_ERROR_SUCCESS; if (self->rcbEventHandler) { @@ -1968,12 +2062,23 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme } else if (strcmp(elementName, "DatSet") == 0) { + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* datSet = ReportControl_getRCBValue(rc, "DatSet"); if (!MmsValue_equals(datSet, value)) { if (updateReportDataset(self, rc, value, connection)) { + MmsValue_update(datSet, value); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + if (rc->buffered) { purgeBuf(rc); @@ -1982,26 +2087,42 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme } } - MmsValue_update(datSet, value); - increaseConfRev(rc); } else { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + retVal = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; goto exit_function; } } + else { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + } retVal = DATA_ACCESS_ERROR_SUCCESS; goto exit_function; } else if (strcmp(elementName, "IntgPd") == 0) { + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* intgPd = ReportControl_getRCBValue(rc, elementName); if (!MmsValue_equals(intgPd, value)) { MmsValue_update(intgPd, value); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + refreshIntegrityPeriod(rc); if (rc->buffered) { @@ -2013,15 +2134,29 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme } } } + else { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + } goto exit_function; } else if (strcmp(elementName, "TrgOps") == 0) { + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* trgOps = ReportControl_getRCBValue(rc, elementName); if (!MmsValue_equals(trgOps, value)) { MmsValue_update(trgOps, value); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + if (rc->buffered) { purgeBuf(rc); @@ -2032,6 +2167,11 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme refreshTriggerOptions(rc); } + else { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + } goto exit_function; } @@ -2062,18 +2202,34 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme rc->isResync = false; } +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif MmsValue* entryID = ReportControl_getRCBValue(rc, elementName); MmsValue_update(entryID, value); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + goto exit_function; } else if (strcmp(elementName, "BufTm") == 0) { + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* bufTm = ReportControl_getRCBValue(rc, elementName); if (!MmsValue_equals(bufTm, value)) { MmsValue_update(bufTm, value); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + if (rc->buffered) { purgeBuf(rc); @@ -2084,15 +2240,29 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme refreshBufferTime(rc); } + else { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + } goto exit_function; } else if (strcmp(elementName, "RptID") == 0) { + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* rptId = ReportControl_getRCBValue(rc, elementName); if (!MmsValue_equals(rptId, value)) { MmsValue_update(rptId, value); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + if (rc->buffered) { purgeBuf(rc); @@ -2101,6 +2271,11 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme } } } + else { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + } goto exit_function; } @@ -2183,14 +2358,26 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme goto exit_function; } +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* rcbValue = ReportControl_getRCBValue(rc, elementName); if (rcbValue) { if (dontUpdate == false) { MmsValue_update(rcbValue, value); } + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif } else { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + retVal = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; goto exit_function; @@ -2280,9 +2467,17 @@ Reporting_disableReportControlInstance(MmsMapping* self, ReportControl* rc) rc->enabled = false; rc->clientConnection = NULL; +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* rptEna = ReportControl_getRCBValue(rc, "RptEna"); MmsValue_setBoolean(rptEna, false); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + if (rc->reserved) { rc->reserved = false; @@ -2296,8 +2491,16 @@ Reporting_disableReportControlInstance(MmsMapping* self, ReportControl* rc) if (rc->buffered == false) { if (rc->resvTms != -1) { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* resv = ReportControl_getRCBValue(rc, "Resv"); MmsValue_setBoolean(resv, false); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif } if (rc->resvTms != -1) @@ -2461,7 +2664,9 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ ReportBuffer* buffer = reportControl->reportBuffer; +#if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_wait(buffer->lock); +#endif bool isBuffered = reportControl->buffered; bool overflow = false; @@ -2747,8 +2952,16 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_ #endif if (reportControl->enabled == false) { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(reportControl->rcbValuesLock); +#endif + MmsValue* entryIdValue = MmsValue_getElement(reportControl->rcbValues, 11); MmsValue_setOctetString(entryIdValue, (uint8_t*) entry->entryId, 8); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(reportControl->rcbValuesLock); +#endif } reportControl->lastEntryId = entryId; @@ -2851,7 +3064,9 @@ exit_function: /* TODO call user callback handler */ } +#if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_post(buffer->lock); +#endif return; } /* enqueuReport() */ @@ -2894,6 +3109,10 @@ sendNextReportEntrySegment(ReportControl* self) printf(" size: %i\n", report->entryLength); #endif +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->rcbValuesLock); +#endif + if (isBuffered) { MmsValue* entryIdValue = MmsValue_getElement(self->rcbValues, 11); MmsValue_setOctetString(entryIdValue, (uint8_t*) report->entryId, 8); @@ -3424,6 +3643,11 @@ sendNextReportEntrySegment(ReportControl* self) } exit_function: + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->rcbValuesLock); +#endif + self->segmented = segmented; return moreFollows; } @@ -3431,7 +3655,9 @@ exit_function: static void sendNextReportEntry(ReportControl* self) { +#if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_wait(self->reportBuffer->lock); +#endif int messageCount = 0; @@ -3445,7 +3671,9 @@ sendNextReportEntry(ReportControl* self) break; } +#if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_post(self->reportBuffer->lock); +#endif } void @@ -3457,10 +3685,18 @@ Reporting_activateBufferedReports(MmsMapping* self) ReportControl* rc = (ReportControl*) element->data; if (rc->buffered) { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + if (updateReportDataset(self, rc, NULL, NULL)) rc->isBuffering = true; else rc->isBuffering = false; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif } } } @@ -3686,9 +3922,19 @@ ReportControlBlock_getRptID(ReportControlBlock* self) if (self->trgOps & 64) { ReportControl* rc = (ReportControl*)(self->sibling); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* rptIdValue = ReportControl_getRCBValue(rc, "RptID"); - return strdup(MmsValue_toString(rptIdValue)); + char* rptIdStr = strdup(MmsValue_toString(rptIdValue)); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + + return rptIdStr; } else { return self->rptId; @@ -3701,9 +3947,19 @@ ReportControlBlock_getDataSet(ReportControlBlock* self) if (self->trgOps & 64) { ReportControl* rc = (ReportControl*)(self->sibling); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* dataSetValue = ReportControl_getRCBValue(rc, "DatSet"); - return strdup(MmsValue_toString(dataSetValue)); + char* dataSetStr = strdup(MmsValue_toString(dataSetValue)); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + + return dataSetStr; } else { return self->dataSetName; @@ -3716,10 +3972,18 @@ ReportControlBlock_getConfRev(ReportControlBlock* self) if (self->trgOps & 64) { ReportControl* rc = (ReportControl*)(self->sibling); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* confRevValue = ReportControl_getRCBValue(rc, "ConfRev"); uint32_t confRev = MmsValue_toUint32(confRevValue); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + return confRev; } else { @@ -3733,10 +3997,18 @@ ReportControlBlock_getOptFlds(ReportControlBlock* self) if (self->trgOps & 64) { ReportControl* rc = (ReportControl*)(self->sibling); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* optFldsValue = ReportControl_getRCBValue(rc, "OptFlds"); uint32_t optFlds = MmsValue_getBitStringAsInteger(optFldsValue) / 2; +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + return optFlds; } else { @@ -3750,10 +4022,18 @@ ReportControlBlock_getBufTm(ReportControlBlock* self) if (self->trgOps & 64) { ReportControl* rc = (ReportControl*)(self->sibling); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* bufTmValue = ReportControl_getRCBValue(rc, "BufTm"); uint32_t bufTm = MmsValue_toUint32(bufTmValue); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + return bufTm; } else { @@ -3767,10 +4047,18 @@ ReportControlBlock_getSqNum(ReportControlBlock* self) if (self->trgOps & 64) { ReportControl* rc = (ReportControl*)(self->sibling); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* sqNumValue = ReportControl_getRCBValue(rc, "SqNum"); uint16_t sqNum = (uint16_t)MmsValue_toUint32(sqNumValue); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + return sqNum; } else { @@ -3810,10 +4098,18 @@ ReportControlBlock_getGI(ReportControlBlock* self) if (self->trgOps & 64) { ReportControl* rc = (ReportControl*)(self->sibling); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* giValue = ReportControl_getRCBValue(rc, "GI"); bool gi = MmsValue_getBoolean(giValue); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + return gi; } else { @@ -3827,10 +4123,18 @@ ReportControlBlock_getPurgeBuf(ReportControlBlock* self) if (self->trgOps & 64) { ReportControl* rc = (ReportControl*)(self->sibling); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* purgeBufValue = ReportControl_getRCBValue(rc, "PurgeBuf"); bool purgeBuf = MmsValue_getBoolean(purgeBufValue); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + return purgeBuf; } else { @@ -3844,10 +4148,18 @@ ReportControlBlock_getEntryId(ReportControlBlock* self) if (self->trgOps & 64) { ReportControl* rc = (ReportControl*)(self->sibling); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* entryIdValue = ReportControl_getRCBValue(rc, "EntryID"); MmsValue* entryId = MmsValue_clone(entryIdValue); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + return entryId; } else { @@ -3861,10 +4173,18 @@ ReportControlBlock_getTimeofEntry(ReportControlBlock* self) if (self->trgOps & 64) { ReportControl* rc = (ReportControl*)(self->sibling); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* timeofEntryValue = ReportControl_getRCBValue(rc, "TimeofEntry"); uint64_t timeofEntry = MmsValue_getBinaryTimeAsUtcMs(timeofEntryValue); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + return timeofEntry; } else { @@ -3878,10 +4198,18 @@ ReportControlBlock_getResvTms(ReportControlBlock* self) if (self->trgOps & 64) { ReportControl* rc = (ReportControl*)(self->sibling); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* resvTmsValue = ReportControl_getRCBValue(rc, "ResvTms"); int16_t resvTms = (int16_t)MmsValue_toInt32(resvTmsValue); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + return resvTms; } else { @@ -3896,10 +4224,19 @@ ReportControlBlock_getOwner(ReportControlBlock* self) ReportControl* rc = (ReportControl*)(self->sibling); if (rc->hasOwner) { + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(rc->rcbValuesLock); +#endif + MmsValue* ownerValue = ReportControl_getRCBValue(rc, "Owner"); MmsValue* ownerValueCopy = MmsValue_clone(ownerValue); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(rc->rcbValuesLock); +#endif + return ownerValueCopy; } else diff --git a/src/mms/inc_private/mms_server_libinternal.h b/src/mms/inc_private/mms_server_libinternal.h index ef8f95f4..e44bb643 100644 --- a/src/mms/inc_private/mms_server_libinternal.h +++ b/src/mms/inc_private/mms_server_libinternal.h @@ -1,7 +1,7 @@ /* * mms_server_libinternal.h * - * Copyright 2013-2020 Michael Zillgith + * Copyright 2013-2022 Michael Zillgith * * This file is part of libIEC61850. * diff --git a/src/mms/iso_mms/server/mms_read_service.c b/src/mms/iso_mms/server/mms_read_service.c index 3fb97675..f933339c 100644 --- a/src/mms/iso_mms/server/mms_read_service.c +++ b/src/mms/iso_mms/server/mms_read_service.c @@ -1,7 +1,7 @@ /* * mms_read_service.c * - * Copyright 2013-2018 Michael Zillgith + * Copyright 2013-2022 Michael Zillgith * * This file is part of libIEC61850. * @@ -98,10 +98,9 @@ addComplexValueToResultList(MmsVariableSpecification* namedVariable, LinkedList typedValues, MmsServerConnection connection, MmsDomain* domain, char* nameIdStr) { - MmsValue* value = addNamedVariableValue(namedVariable, connection, domain, nameIdStr); - if (value != NULL) + if (value) LinkedList_add(typedValues, value); } @@ -109,9 +108,8 @@ addComplexValueToResultList(MmsVariableSpecification* namedVariable, static void appendValueToResultList(MmsValue* value, LinkedList values) { - - if (value != NULL ) - LinkedList_add(values, value); + if (value) + LinkedList_add(values, value); } static void @@ -126,15 +124,15 @@ deleteValueList(LinkedList values) { LinkedList value = LinkedList_getNext(values); - while (value != NULL ) { - MmsValue* typedValue = (MmsValue*) (value->data); + while (value) { + MmsValue* typedValue = (MmsValue*) (value->data); - MmsValue_deleteConditional(typedValue); + MmsValue_deleteConditional(typedValue); - value = LinkedList_getNext(value); - } + value = LinkedList_getNext(value); + } - LinkedList_destroyStatic(values); + LinkedList_destroyStatic(values); } static bool From 56847ec1718729241d5a7e9d1b5d09f88917cf3a Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Tue, 25 Jan 2022 20:59:26 +0100 Subject: [PATCH 11/11] - removed field in ReportControl --- src/iec61850/inc_private/reporting.h | 1 - src/iec61850/server/mms_mapping/reporting.c | 21 ++++++++++----------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/iec61850/inc_private/reporting.h b/src/iec61850/inc_private/reporting.h index 80be1900..a4e3433f 100644 --- a/src/iec61850/inc_private/reporting.h +++ b/src/iec61850/inc_private/reporting.h @@ -59,7 +59,6 @@ typedef struct { #endif MmsValue* inclusionField; - MmsValue* confRev; /* TODO Is this field required? */ DataSet* dataSet; bool isDynamicDataSet; diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c index 463b9570..aadeee7a 100644 --- a/src/iec61850/server/mms_mapping/reporting.c +++ b/src/iec61850/server/mms_mapping/reporting.c @@ -106,7 +106,6 @@ ReportControl_create(bool buffered, LogicalNode* parentLN, int reportBufferSize, self->rcbValuesLock = Semaphore_create(1); #endif - self->confRev = NULL; self->subSeqVal = MmsValue_newUnsigned(16); self->segmented = false; self->startIndexForNextSegment = 0; @@ -1070,8 +1069,6 @@ createUnbufferedReportControlBlock(ReportControlBlock* reportControlBlock, mmsValue->value.structure.components[4] = MmsValue_newUnsignedFromUint32(reportControlBlock->confRef); - reportControl->confRev = mmsValue->value.structure.components[4]; - namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); namedVariable->name = StringUtils_copyString("OptFlds"); namedVariable->type = MMS_BIT_STRING; @@ -1227,8 +1224,6 @@ createBufferedReportControlBlock(ReportControlBlock* reportControlBlock, mmsValue->value.structure.components[3] = MmsValue_newUnsignedFromUint32(reportControlBlock->confRef); - reportControl->confRev = mmsValue->value.structure.components[3]; - namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); namedVariable->name = StringUtils_copyString("OptFlds"); namedVariable->type = MMS_BIT_STRING; @@ -1601,14 +1596,16 @@ checkReportBufferForEntryID(ReportControl* rc, MmsValue* value) static void increaseConfRev(ReportControl* self) { - uint32_t confRev = MmsValue_toUint32(self->confRev); + MmsValue* confRevValue = ReportControl_getRCBValue(self, "ConfRev"); + + uint32_t confRev = MmsValue_toUint32(confRevValue); confRev++; if (confRev == 0) confRev = 1; - MmsValue_setUint32(self->confRev, confRev); + MmsValue_setUint32(confRevValue, confRev); } static void @@ -2075,6 +2072,8 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme MmsValue_update(datSet, value); + increaseConfRev(rc); + #if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_post(rc->rcbValuesLock); #endif @@ -2086,8 +2085,6 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme self->rcbEventHandler(self->rcbEventHandlerParameter, rc->rcb, clientConnection, RCB_EVENT_PURGEBUF, NULL, DATA_ACCESS_ERROR_SUCCESS); } } - - increaseConfRev(rc); } else { #if (CONFIG_MMS_THREADLESS_STACK != 1) @@ -3113,6 +3110,8 @@ sendNextReportEntrySegment(ReportControl* self) Semaphore_wait(self->rcbValuesLock); #endif + MmsValue* confRev = ReportControl_getRCBValue(self, "ConfRev"); + if (isBuffered) { MmsValue* entryIdValue = MmsValue_getElement(self->rcbValues, 11); MmsValue_setOctetString(entryIdValue, (uint8_t*) report->entryId, 8); @@ -3240,7 +3239,7 @@ sendNextReportEntrySegment(ReportControl* self) if (MmsValue_getBitStringBit(optFlds, 8)) { hasConfRev = true; - accessResultSize += MmsValue_encodeMmsData(self->confRev, NULL, 0, false); + accessResultSize += MmsValue_encodeMmsData(confRev, NULL, 0, false); } accessResultSize += MmsValue_encodeMmsData(self->inclusionField, NULL, 0, false); @@ -3441,7 +3440,7 @@ sendNextReportEntrySegment(ReportControl* self) bufPos = MmsValue_encodeMmsData(entryId, buffer, bufPos, true); if (hasConfRev) - bufPos = MmsValue_encodeMmsData(self->confRev, buffer, bufPos, true); + bufPos = MmsValue_encodeMmsData(confRev, buffer, bufPos, true); if (segmented) { bufPos = MmsValue_encodeMmsData(subSeqNum, buffer, bufPos, true);