From 9ab37e983685b34ddaad19bc029855480d835b0f 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 | 81 +++++++++---- 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, 264 insertions(+), 79 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 086011be..1422f79a 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 @@ -728,6 +729,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 09184a62..b109dafd 100644 --- a/src/iec61850/server/mms_mapping/mms_goose.c +++ b/src/iec61850/server/mms_mapping/mms_goose.c @@ -72,6 +72,8 @@ struct sMmsGooseControlBlock { char* dataSetRef; char* gooseInterfaceId; + + bool stateChangePending; }; #if (CONFIG_IEC61850_SERVICE_TRACKING == 1) @@ -357,43 +359,50 @@ 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; + self->goEna = true; #if (CONFIG_IEC61850_SERVICE_TRACKING == 1) - MmsDataAccessError retVal = DATA_ACCESS_ERROR_SUCCESS; - copyGCBValuesToTrackingObject(self); - updateGenericTrackingObjectValues(self, IEC61850_SERVICE_TYPE_SET_GOCB_VALUES, retVal); + MmsDataAccessError retVal = DATA_ACCESS_ERROR_SUCCESS; + copyGCBValuesToTrackingObject(self); + updateGenericTrackingObjectValues(self, IEC61850_SERVICE_TYPE_SET_GOCB_VALUES, retVal); #endif /* (CONFIG_IEC61850_SERVICE_TRACKING == 1) */ + } + else { + if (DEBUG_IED_SERVER) + printf("IED_SERVER: Failed to create GOOSE publisher!\n"); + } + } } @@ -475,8 +484,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 @@ -498,9 +514,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* @@ -608,6 +627,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) @@ -718,6 +751,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 253753b8..798c1d47 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -3509,6 +3509,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; @@ -3516,7 +3518,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 ec65eae5aa25d625e974f1d929fe189670011dc6..25fb74dffc431bf1e83a7168ab7cec2468e07b86 100644 GIT binary patch delta 18513 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 Ef8GP4pa1{> 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++; } }