diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index 670f5c85..78ada2bf 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -96,6 +96,9 @@ struct sIedServerConfig /** RCB has owner attribute (default: true) */ bool enableOwnerForRCB; + + /** integrity report start times will by synchronized with straight numbers (default: false) */ + bool syncIntegrityReportTimes; }; /** @@ -179,6 +182,30 @@ IedServerConfig_setMaxMmsConnections(IedServerConfig self, int maxConnections); LIB61850_API int IedServerConfig_getMaxMmsConnections(IedServerConfig self); +/** + * \brief Enable synchronized integrity report times + * + * NOTE: When this flag is enabled the integrity report generation times are + * aligned with the UTC epoch. Then the unix time stamps are straight multiples of the + * integrity interval. + * + * \param enable when true synchronized integrity report times are enabled + */ +void +IedServerConfig_setSyncIntegrityReportTimes(IedServerConfig self, bool enable); + +/** + * \brief Check if synchronized integrity report times are enabled + * + * NOTE: When this flag is enabled the integrity report generation times are + * aligned with the UTC epoch. Then the unix time stamps are straight multiples of the + * integrity interval. + * + * \return true, when enabled, false otherwise + */ +bool +IedServerConfig_getSyncIntegrityReportTimes(IedServerConfig self); + /** * \brief Set the basepath of the file services * diff --git a/src/iec61850/inc_private/ied_server_private.h b/src/iec61850/inc_private/ied_server_private.h index ed6af512..14a694b1 100644 --- a/src/iec61850/inc_private/ied_server_private.h +++ b/src/iec61850/inc_private/ied_server_private.h @@ -49,6 +49,7 @@ struct sIedServer int reportBufferSizeURCBs; bool enableBRCBResvTms; bool enableOwnerForRCB; + bool syncIntegrityReportTimes; #endif #if (CONFIG_MMS_THREADLESS_STACK != 1) diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index 9d750ddf..8acd6e62 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -484,11 +484,13 @@ IedServer_createWithConfig(IedModel* dataModel, TLSConfiguration tlsConfiguratio self->reportBufferSizeURCBs = serverConfiguration->reportBufferSizeURCBs; self->enableBRCBResvTms = serverConfiguration->enableResvTmsForBRCB; self->enableOwnerForRCB = serverConfiguration->enableOwnerForRCB; + self->syncIntegrityReportTimes = serverConfiguration->syncIntegrityReportTimes; } else { self->reportBufferSizeBRCBs = CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE; self->reportBufferSizeURCBs = CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE; self->enableOwnerForRCB = false; + self->syncIntegrityReportTimes = false; #if (CONFIG_IEC61850_BRCB_WITH_RESVTMS == 1) self->enableBRCBResvTms = true; #else diff --git a/src/iec61850/server/impl/ied_server_config.c b/src/iec61850/server/impl/ied_server_config.c index c87e1200..fdc38f8e 100644 --- a/src/iec61850/server/impl/ied_server_config.c +++ b/src/iec61850/server/impl/ied_server_config.c @@ -58,6 +58,7 @@ IedServerConfig_create() self->enableResvTmsForSGCB = true; self->enableResvTmsForBRCB = true; self->enableOwnerForRCB = false; + self->syncIntegrityReportTimes = false; } return self; @@ -251,3 +252,15 @@ IedServerConfig_getMaxMmsConnections(IedServerConfig self) { return self->maxMmsConnections; } + +void +IedServerConfig_setSyncIntegrityReportTimes(IedServerConfig self, bool enable) +{ + self->syncIntegrityReportTimes = enable; +} + +bool +IedServerConfig_getSyncIntegrityReportTimes(IedServerConfig self) +{ + return self->syncIntegrityReportTimes; +} diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c index 27dd05fc..ec076d0b 100644 --- a/src/iec61850/server/mms_mapping/reporting.c +++ b/src/iec61850/server/mms_mapping/reporting.c @@ -929,6 +929,21 @@ refreshTriggerOptions(ReportControl* rc) #endif } +static uint64_t +getNextRoundedStartTime(uint64_t currentTime, uint64_t intgPd) +{ + uint64_t modTime = currentTime % intgPd; + uint64_t delta = 0; + + if (modTime != 0) { + delta = intgPd - modTime; + } + + uint64_t nextTime = currentTime + delta; + + return nextTime; +} + static void refreshIntegrityPeriod(ReportControl* rc) { @@ -943,8 +958,14 @@ refreshIntegrityPeriod(ReportControl* rc) Semaphore_post(rc->rcbValuesLock); #endif - if (rc->buffered == false) - rc->nextIntgReportTime = Hal_getTimeInMs() + rc->intgPd; + if (rc->buffered == false) { + if (rc->server->syncIntegrityReportTimes) { + rc->nextIntgReportTime = getNextRoundedStartTime(Hal_getTimeInMs(), rc->intgPd); + } + else { + rc->nextIntgReportTime = Hal_getTimeInMs() + rc->intgPd; + } + } } static void @@ -2128,7 +2149,14 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme refreshIntegrityPeriod(rc); if (rc->buffered) { - rc->nextIntgReportTime = 0; + + if (rc->server->syncIntegrityReportTimes) { + rc->nextIntgReportTime = getNextRoundedStartTime(Hal_getTimeInMs(), rc->intgPd); + } + else { + rc->nextIntgReportTime = 0; + } + purgeBuf(rc); if (self->rcbEventHandler) { @@ -3784,7 +3812,13 @@ processEventsForReport(ReportControl* rc, uint64_t currentTimeInMs) /* check for system time change effects */ if ((rc->nextIntgReportTime < currentTimeInMs) || (rc->nextIntgReportTime > currentTimeInMs + rc->intgPd)) { - rc->nextIntgReportTime = currentTimeInMs + rc->intgPd; + + if (rc->server->syncIntegrityReportTimes) { + rc->nextIntgReportTime = getNextRoundedStartTime(currentTimeInMs, rc->intgPd); + } + else { + rc->nextIntgReportTime = currentTimeInMs + rc->intgPd; + } } enqueueReport(rc, true, false, currentTimeInMs); @@ -3794,7 +3828,12 @@ processEventsForReport(ReportControl* rc, uint64_t currentTimeInMs) else { /* check for system time change effects */ if ((rc->nextIntgReportTime < currentTimeInMs) || (rc->nextIntgReportTime > currentTimeInMs + rc->intgPd)) { - rc->nextIntgReportTime = currentTimeInMs + rc->intgPd; + if (rc->server->syncIntegrityReportTimes) { + rc->nextIntgReportTime = getNextRoundedStartTime(currentTimeInMs, rc->intgPd); + } + else { + rc->nextIntgReportTime = currentTimeInMs + rc->intgPd; + } } } @@ -4169,6 +4208,8 @@ ReportControlBlock_getGI(ReportControlBlock* self) bool ReportControlBlock_getPurgeBuf(ReportControlBlock* self) { + bool purgeBuf = false; + if (self->trgOps & 64) { ReportControl* rc = (ReportControl*)(self->sibling); @@ -4178,22 +4219,23 @@ ReportControlBlock_getPurgeBuf(ReportControlBlock* self) MmsValue* purgeBufValue = ReportControl_getRCBValue(rc, "PurgeBuf"); - bool purgeBuf = MmsValue_getBoolean(purgeBufValue); + if (purgeBufValue) { + purgeBuf = MmsValue_getBoolean(purgeBufValue); + } #if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_post(rc->rcbValuesLock); #endif - - return purgeBuf; - } - else { - return false; } + + return purgeBuf; } MmsValue* ReportControlBlock_getEntryId(ReportControlBlock* self) { + MmsValue* entryId = NULL; + if (self->trgOps & 64) { ReportControl* rc = (ReportControl*)(self->sibling); @@ -4203,22 +4245,21 @@ ReportControlBlock_getEntryId(ReportControlBlock* self) MmsValue* entryIdValue = ReportControl_getRCBValue(rc, "EntryID"); - MmsValue* entryId = MmsValue_clone(entryIdValue); + entryId = MmsValue_clone(entryIdValue); #if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_post(rc->rcbValuesLock); #endif - - return entryId; - } - else { - return NULL; } + + return entryId; } uint64_t ReportControlBlock_getTimeofEntry(ReportControlBlock* self) { + uint64_t timeofEntry = 0; + if (self->trgOps & 64) { ReportControl* rc = (ReportControl*)(self->sibling); @@ -4228,22 +4269,23 @@ ReportControlBlock_getTimeofEntry(ReportControlBlock* self) MmsValue* timeofEntryValue = ReportControl_getRCBValue(rc, "TimeofEntry"); - uint64_t timeofEntry = MmsValue_getBinaryTimeAsUtcMs(timeofEntryValue); + if (timeofEntryValue) { + timeofEntry = MmsValue_getBinaryTimeAsUtcMs(timeofEntryValue); + } #if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_post(rc->rcbValuesLock); #endif - - return timeofEntry; - } - else { - return 0; } + + return timeofEntry; } int16_t ReportControlBlock_getResvTms(ReportControlBlock* self) { + int16_t resvTms = 0; + if (self->trgOps & 64) { ReportControl* rc = (ReportControl*)(self->sibling); @@ -4253,22 +4295,23 @@ ReportControlBlock_getResvTms(ReportControlBlock* self) MmsValue* resvTmsValue = ReportControl_getRCBValue(rc, "ResvTms"); - int16_t resvTms = (int16_t)MmsValue_toInt32(resvTmsValue); + if (resvTmsValue) { + resvTms = (int16_t)MmsValue_toInt32(resvTmsValue); + } #if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_post(rc->rcbValuesLock); #endif - - return resvTms; - } - else { - return 0; } + + return resvTms; } bool ReportControlBlock_getResv(ReportControlBlock* self) { + bool resv = false; + if (self->trgOps & 64) { ReportControl* rc = (ReportControl*)(self->sibling); @@ -4278,17 +4321,16 @@ ReportControlBlock_getResv(ReportControlBlock* self) MmsValue* resvValue = ReportControl_getRCBValue(rc, "Resv"); - bool resv = MmsValue_getBoolean(resvValue); + if (resvValue) { + resv = MmsValue_getBoolean(resvValue); + } #if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_post(rc->rcbValuesLock); #endif - - return resv; - } - else { - return false; } + + return resv; } MmsValue*