From 44872d3a3eec58a75453fa30e5770988562093e6 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Mon, 24 Aug 2020 19:20:26 +0200 Subject: [PATCH] - IED Server/GOOSE: Don't send GOOSE message with new event while data model is locked --- .../server_example_goose.c | 17 +++ .../simpleIO_direct_control_goose.cid | 13 ++- examples/server_example_goose/static_model.c | 100 +++++++++++++++- src/iec61850/inc_private/mms_goose.h | 8 +- src/iec61850/server/impl/ied_server.c | 6 + src/iec61850/server/mms_mapping/mms_goose.c | 73 +++++++++--- src/iec61850/server/mms_mapping/mms_mapping.c | 8 +- tools/model_generator/genmodel.jar | Bin 94594 -> 94643 bytes .../tools/StaticModelGenerator.java | 110 +++++++++--------- 9 files changed, 260 insertions(+), 75 deletions(-) diff --git a/examples/server_example_goose/server_example_goose.c b/examples/server_example_goose/server_example_goose.c index 2fe77f47..d6548c35 100644 --- a/examples/server_example_goose/server_example_goose.c +++ b/examples/server_example_goose/server_example_goose.c @@ -104,6 +104,8 @@ int main(int argc, char** argv) { float anIn1 = 0.f; + int eventCount = 10; + while (running) { IedServer_lockDataModel(iedServer); @@ -111,6 +113,21 @@ int main(int argc, char** argv) { IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_t, Hal_getTimeInMs()); IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f, anIn1); + if (eventCount) { + IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_t, Hal_getTimeInMs()); + + if (eventCount % 2) { + IedServer_updateQuality(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_q, QUALITY_VALIDITY_GOOD); + IedServer_updateBooleanAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal, true); + } + else { + IedServer_updateQuality(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_q, QUALITY_VALIDITY_INVALID); + IedServer_updateBooleanAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal, false); + } + + eventCount--; + } + IedServer_unlockDataModel(iedServer); anIn1 += 0.1; diff --git a/examples/server_example_goose/simpleIO_direct_control_goose.cid b/examples/server_example_goose/simpleIO_direct_control_goose.cid index 8f443989..1701b9fe 100644 --- a/examples/server_example_goose/simpleIO_direct_control_goose.cid +++ b/examples/server_example_goose/simpleIO_direct_control_goose.cid @@ -68,6 +68,17 @@ + + + + + + + + + + + @@ -88,7 +99,7 @@ - + diff --git a/examples/server_example_goose/static_model.c b/examples/server_example_goose/static_model.c index e57b0596..245575f0 100644 --- a/examples/server_example_goose/static_model.c +++ b/examples/server_example_goose/static_model.c @@ -9,6 +9,7 @@ static void initializeValues(); extern DataSet iedModelds_GenericIO_LLN0_Events; extern DataSet iedModelds_GenericIO_LLN0_Events2; +extern DataSet iedModelds_GenericIO_LLN0_Events3; extern DataSet iedModelds_GenericIO_LLN0_AnalogValues; @@ -115,6 +116,103 @@ DataSet iedModelds_GenericIO_LLN0_Events2 = { "LLN0$Events2", 4, &iedModelds_GenericIO_LLN0_Events2_fcda0, + &iedModelds_GenericIO_LLN0_Events3 +}; + +extern DataSetEntry iedModelds_GenericIO_LLN0_Events3_fcda0; +extern DataSetEntry iedModelds_GenericIO_LLN0_Events3_fcda1; +extern DataSetEntry iedModelds_GenericIO_LLN0_Events3_fcda2; +extern DataSetEntry iedModelds_GenericIO_LLN0_Events3_fcda3; +extern DataSetEntry iedModelds_GenericIO_LLN0_Events3_fcda4; +extern DataSetEntry iedModelds_GenericIO_LLN0_Events3_fcda5; +extern DataSetEntry iedModelds_GenericIO_LLN0_Events3_fcda6; +extern DataSetEntry iedModelds_GenericIO_LLN0_Events3_fcda7; + +DataSetEntry iedModelds_GenericIO_LLN0_Events3_fcda0 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO1$stVal", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Events3_fcda1 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Events3_fcda1 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO1$q", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Events3_fcda2 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Events3_fcda2 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO2$stVal", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Events3_fcda3 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Events3_fcda3 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO2$q", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Events3_fcda4 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Events3_fcda4 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO3$stVal", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Events3_fcda5 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Events3_fcda5 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO3$q", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Events3_fcda6 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Events3_fcda6 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO4$stVal", + -1, + NULL, + NULL, + &iedModelds_GenericIO_LLN0_Events3_fcda7 +}; + +DataSetEntry iedModelds_GenericIO_LLN0_Events3_fcda7 = { + "GenericIO", + false, + "GGIO1$ST$SPCSO4$q", + -1, + NULL, + NULL, + NULL +}; + +DataSet iedModelds_GenericIO_LLN0_Events3 = { + "GenericIO", + "LLN0$Events3", + 8, + &iedModelds_GenericIO_LLN0_Events3_fcda0, &iedModelds_GenericIO_LLN0_AnalogValues }; @@ -1896,7 +1994,7 @@ static PhyComAddress iedModel_GenericIO_LLN0_gse0_address = { {0x1, 0xc, 0xcd, 0x1, 0x0, 0x1} }; -GSEControlBlock iedModel_GenericIO_LLN0_gse0 = {&iedModel_GenericIO_LLN0, "gcbEvents", "events", "Events", 2, false, &iedModel_GenericIO_LLN0_gse0_address, 1000, 3000, &iedModel_GenericIO_LLN0_gse1}; +GSEControlBlock iedModel_GenericIO_LLN0_gse0 = {&iedModel_GenericIO_LLN0, "gcbEvents", "events", "Events3", 2, false, &iedModel_GenericIO_LLN0_gse0_address, 1000, 3000, &iedModel_GenericIO_LLN0_gse1}; static PhyComAddress iedModel_GenericIO_LLN0_gse1_address = { 4, diff --git a/src/iec61850/inc_private/mms_goose.h b/src/iec61850/inc_private/mms_goose.h index 0b1a22d5..326e35dc 100644 --- a/src/iec61850/inc_private/mms_goose.h +++ b/src/iec61850/inc_private/mms_goose.h @@ -69,7 +69,10 @@ LIB61850_INTERNAL void MmsGooseControlBlock_checkAndPublish(MmsGooseControlBlock self, uint64_t currentTime); LIB61850_INTERNAL void -MmsGooseControlBlock_observedObjectChanged(MmsGooseControlBlock self); +MmsGooseControlBlock_setStateChangePending(MmsGooseControlBlock self); + +LIB61850_INTERNAL void +MmsGooseControlBlock_publishNewState(MmsGooseControlBlock self); LIB61850_INTERNAL void MmsGooseControlBlock_enable(MmsGooseControlBlock self); @@ -77,6 +80,9 @@ MmsGooseControlBlock_enable(MmsGooseControlBlock self); LIB61850_INTERNAL void MmsGooseControlBlock_disable(MmsGooseControlBlock self); +LIB61850_INTERNAL void +GOOSE_sendPendingEvents(MmsMapping* self); + LIB61850_INTERNAL MmsVariableSpecification* GOOSE_createGOOSEControlBlocks(MmsMapping* self, MmsDomain* domain, LogicalNode* logicalNode, int gseCount); diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index 83e5e2ab..38428134 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -34,6 +34,7 @@ #include "libiec61850_platform_includes.h" #include "mms_sv.h" +#include "mms_goose.h" #ifndef DEBUG_IED_SERVER #define DEBUG_IED_SERVER 0 @@ -717,6 +718,11 @@ IedServer_lockDataModel(IedServer self) void IedServer_unlockDataModel(IedServer self) { +#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + /* check if GOOSE messages have to be sent */ + GOOSE_sendPendingEvents(self->mmsMapping); +#endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */ + /* check if reports have to be sent! */ Reporting_processReportEventsAfterUnlock(self->mmsMapping); diff --git a/src/iec61850/server/mms_mapping/mms_goose.c b/src/iec61850/server/mms_mapping/mms_goose.c index 91d8748d..4df50074 100644 --- a/src/iec61850/server/mms_mapping/mms_goose.c +++ b/src/iec61850/server/mms_mapping/mms_goose.c @@ -71,6 +71,8 @@ struct sMmsGooseControlBlock { char* dataSetRef; char* gooseInterfaceId; + + bool stateChangePending; }; MmsGooseControlBlock @@ -257,37 +259,44 @@ MmsGooseControlBlock_enable(MmsGooseControlBlock self) else self->publisher = GoosePublisher_createEx(&commParameters, self->mmsMapping->gooseInterfaceId, self->useVlanTag); - self->minTime = MmsValue_toUint32(MmsValue_getElement(self->mmsValue, 6)); - self->maxTime = MmsValue_toUint32(MmsValue_getElement(self->mmsValue, 7)); + if (self->publisher) { + self->minTime = MmsValue_toUint32(MmsValue_getElement(self->mmsValue, 6)); + self->maxTime = MmsValue_toUint32(MmsValue_getElement(self->mmsValue, 7)); - GoosePublisher_setTimeAllowedToLive(self->publisher, self->maxTime * 3); + GoosePublisher_setTimeAllowedToLive(self->publisher, self->maxTime * 3); - GoosePublisher_setDataSetRef(self->publisher, self->dataSetRef); + GoosePublisher_setDataSetRef(self->publisher, self->dataSetRef); - GoosePublisher_setGoCbRef(self->publisher, self->goCBRef); + GoosePublisher_setGoCbRef(self->publisher, self->goCBRef); - uint32_t confRev = MmsValue_toUint32(MmsValue_getElement(self->mmsValue, 3)); + uint32_t confRev = MmsValue_toUint32(MmsValue_getElement(self->mmsValue, 3)); - GoosePublisher_setConfRev(self->publisher, confRev); + GoosePublisher_setConfRev(self->publisher, confRev); - bool needsCom = MmsValue_getBoolean(MmsValue_getElement(self->mmsValue, 4)); + bool needsCom = MmsValue_getBoolean(MmsValue_getElement(self->mmsValue, 4)); - GoosePublisher_setNeedsCommission(self->publisher, needsCom); + GoosePublisher_setNeedsCommission(self->publisher, needsCom); - if (self->goId != NULL) - GoosePublisher_setGoID(self->publisher, self->goId); + if (self->goId != NULL) + GoosePublisher_setGoID(self->publisher, self->goId); - /* prepare data set values */ - self->dataSetValues = LinkedList_create(); + /* prepare data set values */ + self->dataSetValues = LinkedList_create(); - DataSetEntry* dataSetEntry = self->dataSet->fcdas; + DataSetEntry* dataSetEntry = self->dataSet->fcdas; - while (dataSetEntry != NULL) { - LinkedList_add(self->dataSetValues, dataSetEntry->value); - dataSetEntry = dataSetEntry->sibling; + while (dataSetEntry != NULL) { + LinkedList_add(self->dataSetValues, dataSetEntry->value); + dataSetEntry = dataSetEntry->sibling; + } + + self->goEna = true; + } + else { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: Failed to create GOOSE publisher!\n"); } - self->goEna = true; } } @@ -363,8 +372,15 @@ MmsGooseControlBlock_checkAndPublish(MmsGooseControlBlock self, uint64_t current } void -MmsGooseControlBlock_observedObjectChanged(MmsGooseControlBlock self) +MmsGooseControlBlock_setStateChangePending(MmsGooseControlBlock self) { + self->stateChangePending = true; +} + +void +MmsGooseControlBlock_publishNewState(MmsGooseControlBlock self) +{ + if (self->stateChangePending) { #if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_wait(self->publisherMutex); #endif @@ -386,9 +402,12 @@ MmsGooseControlBlock_observedObjectChanged(MmsGooseControlBlock self) GoosePublisher_publish(self->publisher, self->dataSetValues); + self->stateChangePending = false; + #if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore_post(self->publisherMutex); #endif + } } static MmsVariableSpecification* @@ -496,6 +515,20 @@ createDataSetReference(char* domainName, char* lnName, char* dataSetName) return dataSetReference; } +void +GOOSE_sendPendingEvents(MmsMapping* self) +{ + LinkedList element = self->gseControls; + + while ((element = LinkedList_getNext(element)) != NULL) { + MmsGooseControlBlock gcb = (MmsGooseControlBlock) element->data; + + if (MmsGooseControlBlock_isEnabled(gcb)) { + MmsGooseControlBlock_publishNewState(gcb); + } + } +} + MmsVariableSpecification* GOOSE_createGOOSEControlBlocks(MmsMapping* self, MmsDomain* domain, LogicalNode* logicalNode, int gseCount) @@ -606,6 +639,8 @@ GOOSE_createGOOSEControlBlocks(MmsMapping* self, MmsDomain* domain, mmsGCB->mmsMapping = self; + mmsGCB->stateChangePending = false; + LinkedList_add(self->gseControls, mmsGCB); currentGCB++; diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index 71759e49..aa9ed330 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -2921,6 +2921,8 @@ MmsMapping_triggerGooseObservers(MmsMapping* self, MmsValue* value) { LinkedList element = self->gseControls; + bool modelLocked = self->isModelLocked; + while ((element = LinkedList_getNext(element)) != NULL) { MmsGooseControlBlock gcb = (MmsGooseControlBlock) element->data; @@ -2928,7 +2930,11 @@ MmsMapping_triggerGooseObservers(MmsMapping* self, MmsValue* value) DataSet* dataSet = MmsGooseControlBlock_getDataSet(gcb); if (DataSet_isMemberValue(dataSet, value, NULL)) { - MmsGooseControlBlock_observedObjectChanged(gcb); + MmsGooseControlBlock_setStateChangePending(gcb); + + if (modelLocked == false) { + MmsGooseControlBlock_publishNewState(gcb); + } } } } diff --git a/tools/model_generator/genmodel.jar b/tools/model_generator/genmodel.jar index 54d838df521fb660348fae7e4dfe4fff3c2a14bb..cbe2108bd08b45433a49327babdc14b358e1e699 100644 GIT binary patch delta 18513 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 delta 18562 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 diff --git a/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java b/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java index 6f0a41b3..4e1ae291 100644 --- a/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java +++ b/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java @@ -1028,77 +1028,83 @@ public class StaticModelGenerator { for (GSEControl gseControlBlock : gseControlBlocks) { GSE gse = connectedAP.lookupGSE(logicalDeviceName, gseControlBlock.getName()); - - PhyComAddress gseAddress = gse.getAddress(); - String gseString = ""; + if (gse != null) { + PhyComAddress gseAddress = gse.getAddress(); + + String gseString = ""; - String phyComAddrName = ""; + String phyComAddrName = ""; - if (gseAddress != null) { - phyComAddrName = lnPrefix + "_gse" + gseControlNumber + "_address"; + if (gseAddress != null) { + phyComAddrName = lnPrefix + "_gse" + gseControlNumber + "_address"; - gseString += "\nstatic PhyComAddress " + phyComAddrName + " = {\n"; - gseString += " " + gseAddress.getVlanPriority() + ",\n"; - gseString += " " + gseAddress.getVlanId() + ",\n"; - gseString += " " + gseAddress.getAppId() + ",\n"; - gseString += " {"; + gseString += "\nstatic PhyComAddress " + phyComAddrName + " = {\n"; + gseString += " " + gseAddress.getVlanPriority() + ",\n"; + gseString += " " + gseAddress.getVlanId() + ",\n"; + gseString += " " + gseAddress.getAppId() + ",\n"; + gseString += " {"; - for (int i = 0; i < 6; i++) { - gseString += "0x" + Integer.toHexString(gseAddress.getMacAddress()[i]); - if (i == 5) - gseString += "}\n"; - else - gseString += ", "; + for (int i = 0; i < 6; i++) { + gseString += "0x" + Integer.toHexString(gseAddress.getMacAddress()[i]); + if (i == 5) + gseString += "}\n"; + else + gseString += ", "; + } + + gseString += "};\n\n"; } - gseString += "};\n\n"; - } + String gseVariableName = lnPrefix + "_gse" + gseControlNumber; - String gseVariableName = lnPrefix + "_gse" + gseControlNumber; + gseString += "GSEControlBlock " + gseVariableName + " = {"; + gseString += "&" + lnPrefix + ", "; - gseString += "GSEControlBlock " + gseVariableName + " = {"; - gseString += "&" + lnPrefix + ", "; + gseString += "\"" + gseControlBlock.getName() + "\", "; - gseString += "\"" + gseControlBlock.getName() + "\", "; + if (gseControlBlock.getAppID() == null) + gseString += "NULL, "; + else + gseString += "\"" + gseControlBlock.getAppID() + "\", "; - if (gseControlBlock.getAppID() == null) - gseString += "NULL, "; - else - gseString += "\"" + gseControlBlock.getAppID() + "\", "; + if (gseControlBlock.getDataSet() != null) + gseString += "\"" + gseControlBlock.getDataSet() + "\", "; + else + gseString += "NULL, "; - if (gseControlBlock.getDataSet() != null) - gseString += "\"" + gseControlBlock.getDataSet() + "\", "; - else - gseString += "NULL, "; + gseString += gseControlBlock.getConfRev() + ", "; - gseString += gseControlBlock.getConfRev() + ", "; + if (gseControlBlock.isFixedOffs()) + gseString += "true, "; + else + gseString += "false, "; - if (gseControlBlock.isFixedOffs()) - gseString += "true, "; - else - gseString += "false, "; + if (gseAddress != null) + gseString += "&" + phyComAddrName + ", "; + else + gseString += "NULL, "; + + gseString += gse.getMinTime() + ", "; + gseString += gse.getMaxTime() + ", "; - if (gseAddress != null) - gseString += "&" + phyComAddrName + ", "; - else - gseString += "NULL, "; - - gseString += gse.getMinTime() + ", "; - gseString += gse.getMaxTime() + ", "; + currentGseVariableNumber++; + + if (currentGseVariableNumber < gseVariableNames.size()) + gseString += "&" + gseVariableNames.get(currentGseVariableNumber); + else + gseString += "NULL"; - currentGseVariableNumber++; - - if (currentGseVariableNumber < gseVariableNames.size()) - gseString += "&" + gseVariableNames.get(currentGseVariableNumber); - else - gseString += "NULL"; + gseString += "};\n"; - gseString += "};\n"; + this.gseControlBlocks.append(gseString); - this.gseControlBlocks.append(gseString); + gseControlNumber++; + } + else { + System.out.println("GSE not found for GoCB " + gseControlBlock.getName()); + } - gseControlNumber++; } }