diff --git a/examples/server_example_config_file/model.cfg b/examples/server_example_config_file/model.cfg index 02feeb04..ecfea166 100644 --- a/examples/server_example_config_file/model.cfg +++ b/examples/server_example_config_file/model.cfg @@ -2,6 +2,7 @@ MODEL(simpleIO){ LD(GenericIO){ LN(LLN0){ DO(Mod 0){ +DA(stVal 0 3 0 1 0); DA(q 0 23 0 2 0); DA(t 0 22 0 0 0); DA(ctlModel 0 12 4 0 0)=0; @@ -17,9 +18,9 @@ DA(q 0 23 0 2 0); DA(t 0 22 0 0 0); } DO(NamPlt 0){ -DA(vendor 0 20 5 0 0); -DA(swRev 0 20 5 0 0); -DA(d 0 20 5 0 0); +DA(vendor 0 20 5 0 0)="MZ Automation"; +DA(swRev 0 20 5 0 0)="0.7.3"; +DA(d 0 20 5 0 0)="libiec61850 server example"; DA(configRev 0 20 5 0 0); DA(ldNs 0 20 11 0 0); } @@ -29,24 +30,33 @@ DE(GGIO1$ST$SPCSO2$stVal); DE(GGIO1$ST$SPCSO3$stVal); DE(GGIO1$ST$SPCSO4$stVal); } -DS(AnalogValues){ -DE(GGIO1$MX$AnIn1); -DE(GGIO1$MX$AnIn2); -DE(GGIO1$MX$AnIn3); -DE(GGIO1$MX$AnIn4); -} -RC(EventsRCB01 Events 0 Events 1 24 111 50 1000); -RC(AnalogValuesRCB01 AnalogValues 0 AnalogValues 1 24 111 50 1000); -LC(EventLog Events GenericIO/LLN0$EventLog 19 0 0 1) -LC(GeneralLog - - 19 0 0 1) -LOG(GeneralLog) -LOG(EventLog) -GC(gcbEvents events Events 2 0 -1 -1 ){ -PA(4 273 4096 010ccd010001); -} -GC(gcbAnalogValues analog AnalogValues 2 0 -1 -1 ){ -PA(4 273 4096 010ccd010001); -} +DS(Events2){ +DE(GGIO1$ST$SPCSO1); +DE(GGIO1$ST$SPCSO2); +DE(GGIO1$ST$SPCSO3); +DE(GGIO1$ST$SPCSO4); +} +DS(Measurements){ +DE(GGIO1$MX$AnIn1$mag$f); +DE(GGIO1$MX$AnIn1$q); +DE(GGIO1$MX$AnIn2$mag$f); +DE(GGIO1$MX$AnIn2$q); +DE(GGIO1$MX$AnIn3$mag$f); +DE(GGIO1$MX$AnIn3$q); +DE(GGIO1$MX$AnIn4$mag$f); +DE(GGIO1$MX$AnIn4$q); +} +RC(EventsRCB01 Events1 0 Events 4294967295 24 111 50 1000); +RC(EventsIndexed01 Events2 0 Events 1 24 111 50 1000); +RC(EventsIndexed02 Events2 0 Events 1 24 111 50 1000); +RC(EventsIndexed03 Events2 0 Events 1 24 111 50 1000); +RC(Measurements01 Measurements 1 Measurements 1 16 111 50 1000); +RC(Measurements02 Measurements 1 Measurements 1 16 111 50 1000); +RC(Measurements03 Measurements 1 Measurements 1 16 111 50 1000); +LC(EventLog Events GenericIO/LLN0$EventLog 19 0 1 1); +LC(GeneralLog - - 19 0 1 1); +LOG(GeneralLog); +LOG(EventLog); } LN(LPHD1){ DO(PhyNam 0){ @@ -92,11 +102,11 @@ DA(q 0 23 1 2 0); DA(t 0 22 1 0 0); } DO(AnIn2 0){ -DA(mag 0 27 1 1 101){ +DA(mag 0 27 1 1 0){ DA(f 0 10 1 1 0); } DA(q 0 23 1 2 0); -DA(t 0 22 1 0 102); +DA(t 0 22 1 0 0); } DO(AnIn3 0){ DA(mag 0 27 1 1 0){ diff --git a/examples/sv_publisher/sv_publisher_example.c b/examples/sv_publisher/sv_publisher_example.c index 9d42d53a..b048befe 100644 --- a/examples/sv_publisher/sv_publisher_example.c +++ b/examples/sv_publisher/sv_publisher_example.c @@ -20,7 +20,7 @@ void sigint_handler(int signalId) int main(int argc, char** argv) { - SampledValuesPublisher svPublisher = SampledValuesPublisher_create("eth1"); + SampledValuesPublisher svPublisher = SampledValuesPublisher_create("vboxnet0"); SV_ASDU asdu1 = SampledValuesPublisher_addASDU(svPublisher, "svpub1", NULL, 1); @@ -51,7 +51,7 @@ main(int argc, char** argv) SampledValuesPublisher_publish(svPublisher); - Thread_sleep(50); + //Thread_sleep(50); } SampledValuesPublisher_destroy(svPublisher); diff --git a/src/iec61850/inc_private/ied_server_private.h b/src/iec61850/inc_private/ied_server_private.h index c32e43e8..df140828 100644 --- a/src/iec61850/inc_private/ied_server_private.h +++ b/src/iec61850/inc_private/ied_server_private.h @@ -42,6 +42,11 @@ struct sIedServer MmsMapping* mmsMapping; LinkedList clientConnections; uint8_t writeAccessPolicies; + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore dataModelLock; +#endif + bool running; }; diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index 32ebf60e..92725320 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -406,6 +406,10 @@ IedServer_create(IedModel* iedModel) // self->running = false; /* not required due to CALLOC */ +#if (CONFIG_MMS_THREADLESS_STACK != 1) + self->dataModelLock = Semaphore_create(1); +#endif + self->mmsMapping = MmsMapping_create(iedModel); self->mmsDevice = MmsMapping_getMmsDeviceModel(self->mmsMapping); @@ -477,6 +481,11 @@ IedServer_destroy(IedServer self) MmsMapping_destroy(self->mmsMapping); LinkedList_destroyDeep(self->clientConnections, (LinkedListValueDeleteFunction) private_ClientConnection_destroy); + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_destroy(self->dataModelLock); +#endif + GLOBAL_FREEMEM(self); } @@ -891,8 +900,17 @@ IedServer_updateAttributeValue(IedServer self, DataAttribute* dataAttribute, Mms if (MmsValue_equals(dataAttribute->mmsValue, value)) checkForUpdateTrigger(self, dataAttribute); else { + +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->dataModelLock); +#endif + MmsValue_update(dataAttribute->mmsValue, value); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->dataModelLock); +#endif + checkForChangedTriggers(self, dataAttribute); } } @@ -910,7 +928,13 @@ IedServer_updateFloatAttributeValue(IedServer self, DataAttribute* dataAttribute checkForUpdateTrigger(self, dataAttribute); } else { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->dataModelLock); +#endif MmsValue_setFloat(dataAttribute->mmsValue, value); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->dataModelLock); +#endif checkForChangedTriggers(self, dataAttribute); } } @@ -928,7 +952,13 @@ IedServer_updateInt32AttributeValue(IedServer self, DataAttribute* dataAttribute checkForUpdateTrigger(self, dataAttribute); } else { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->dataModelLock); +#endif MmsValue_setInt32(dataAttribute->mmsValue, value); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->dataModelLock); +#endif checkForChangedTriggers(self, dataAttribute); } @@ -947,7 +977,13 @@ IedServer_updateInt64AttributeValue(IedServer self, DataAttribute* dataAttribute checkForUpdateTrigger(self, dataAttribute); } else { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->dataModelLock); +#endif MmsValue_setInt64(dataAttribute->mmsValue, value); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->dataModelLock); +#endif checkForChangedTriggers(self, dataAttribute); } @@ -966,7 +1002,13 @@ IedServer_updateUnsignedAttributeValue(IedServer self, DataAttribute* dataAttrib checkForUpdateTrigger(self, dataAttribute); } else { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->dataModelLock); +#endif MmsValue_setUint32(dataAttribute->mmsValue, value); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->dataModelLock); +#endif checkForChangedTriggers(self, dataAttribute); } @@ -985,7 +1027,13 @@ IedServer_updateBitStringAttributeValue(IedServer self, DataAttribute* dataAttri checkForUpdateTrigger(self, dataAttribute); } else { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->dataModelLock); +#endif MmsValue_setBitStringFromInteger(dataAttribute->mmsValue, value); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->dataModelLock); +#endif checkForChangedTriggers(self, dataAttribute); } @@ -1005,7 +1053,13 @@ IedServer_updateBooleanAttributeValue(IedServer self, DataAttribute* dataAttribu checkForUpdateTrigger(self, dataAttribute); } else { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->dataModelLock); +#endif MmsValue_setBoolean(dataAttribute->mmsValue, value); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->dataModelLock); +#endif checkForChangedTriggers(self, dataAttribute); } @@ -1024,7 +1078,13 @@ IedServer_updateVisibleStringAttributeValue(IedServer self, DataAttribute* dataA checkForUpdateTrigger(self, dataAttribute); } else { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->dataModelLock); +#endif MmsValue_setVisibleString(dataAttribute->mmsValue, value); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->dataModelLock); +#endif checkForChangedTriggers(self, dataAttribute); } @@ -1043,7 +1103,13 @@ IedServer_updateUTCTimeAttributeValue(IedServer self, DataAttribute* dataAttribu checkForUpdateTrigger(self, dataAttribute); } else { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->dataModelLock); +#endif MmsValue_setUtcTimeMs(dataAttribute->mmsValue, value); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->dataModelLock); +#endif checkForChangedTriggers(self, dataAttribute); } @@ -1060,7 +1126,13 @@ IedServer_updateTimestampAttributeValue(IedServer self, DataAttribute* dataAttri checkForUpdateTrigger(self, dataAttribute); } else { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->dataModelLock); +#endif MmsValue_setUtcTimeByBuffer(dataAttribute->mmsValue, timestamp->val); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->dataModelLock); +#endif checkForChangedTriggers(self, dataAttribute); } @@ -1077,8 +1149,15 @@ IedServer_updateQuality(IedServer self, DataAttribute* dataAttribute, Quality qu uint32_t oldQuality = MmsValue_getBitStringAsInteger(dataAttribute->mmsValue); if (oldQuality != (uint32_t) quality) { +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_wait(self->dataModelLock); +#endif MmsValue_setBitStringFromInteger(dataAttribute->mmsValue, (uint32_t) quality); +#if (CONFIG_MMS_THREADLESS_STACK != 1) + Semaphore_post(self->dataModelLock); +#endif + #if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) MmsMapping_triggerGooseObservers(self->mmsMapping, dataAttribute->mmsValue); #endif diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c index a94d59da..9bd155ba 100644 --- a/src/iec61850/server/mms_mapping/reporting.c +++ b/src/iec61850/server/mms_mapping/reporting.c @@ -542,10 +542,7 @@ updateReportDataset(MmsMapping* mapping, ReportControl* rc, MmsValue* newDatSet, if (dataSet == NULL) { - /* check if association specific data set is requested */ - - if (dataSetName[0] == '@') { if (rc->buffered == false) { /* for buffered report non-permanent datasets are not allowed */ @@ -1643,8 +1640,6 @@ printReportId(ReportBufferEntry* report) static void removeAllGIReportsFromReportBuffer(ReportBuffer* reportBuffer) { - printf("removeAllGIReportsFromReportBuffer\n"); - ReportBufferEntry* currentReport = reportBuffer->oldestReport; ReportBufferEntry* lastReport = NULL; @@ -2393,8 +2388,6 @@ Reporting_activateBufferedReports(MmsMapping* self) static void processEventsForReport(ReportControl* rc, uint64_t currentTimeInMs) { - - if ((rc->enabled) || (rc->isBuffering)) { if (rc->triggerOps & TRG_OPT_GI) { diff --git a/src/sampled_values/sv_publisher.c b/src/sampled_values/sv_publisher.c index 7960a7c2..5f812fb2 100644 --- a/src/sampled_values/sv_publisher.c +++ b/src/sampled_values/sv_publisher.c @@ -545,6 +545,29 @@ SV_ASDU_setFLOAT(SV_ASDU self, int index, float value) } +int +SV_ASDU_addFLOAT64(SV_ASDU self) +{ + int index = self->dataSize; + self->dataSize += 8; + return index; +} + +void +SV_ASDU_setFLOAT64(SV_ASDU self, int index, double value) +{ + uint8_t* buf = (uint8_t*) &value; +#if (ORDER_LITTLE_ENDIAN == 1) + BerEncoder_revertByteOrder(buf, 8); +#endif + int i; + uint8_t* buffer = self->_dataBuffer + index; + for (i = 0; i < 8; i++) { + buffer[i] = buf[i]; + } +} + + void SV_ASDU_setSmpCnt(SV_ASDU self, uint16_t value) { diff --git a/src/sampled_values/sv_publisher.h b/src/sampled_values/sv_publisher.h index 13466405..5612aa96 100644 --- a/src/sampled_values/sv_publisher.h +++ b/src/sampled_values/sv_publisher.h @@ -80,6 +80,12 @@ SV_ASDU_addFLOAT(SV_ASDU self); void SV_ASDU_setFLOAT(SV_ASDU self, int index, float value); +int +SV_ASDU_addFLOAT64(SV_ASDU self); + +void +SV_ASDU_setFLOAT64(SV_ASDU self, int index, double value); + void SV_ASDU_setSmpCnt(SV_ASDU self, uint16_t value); diff --git a/src/vs/libiec61850-wo-goose.def b/src/vs/libiec61850-wo-goose.def index 1113aa2e..68873dbb 100644 --- a/src/vs/libiec61850-wo-goose.def +++ b/src/vs/libiec61850-wo-goose.def @@ -547,3 +547,5 @@ EXPORTS IedConnection_queryLogByTime IedConnection_queryLogAfter CDC_DPL_create + SV_ASDU_addFLOAT64 + SV_ASDU_setFLOAT64 diff --git a/src/vs/libiec61850.def b/src/vs/libiec61850.def index 7d0c71c2..157f2161 100644 --- a/src/vs/libiec61850.def +++ b/src/vs/libiec61850.def @@ -623,3 +623,5 @@ EXPORTS IedConnection_queryLogByTime IedConnection_queryLogAfter CDC_DPL_create + SV_ASDU_addFLOAT64 + SV_ASDU_setFLOAT64 diff --git a/tools/model_generator/gendyncode.jar b/tools/model_generator/gendyncode.jar index 3e9fff30..e25b642d 100644 Binary files a/tools/model_generator/gendyncode.jar and b/tools/model_generator/gendyncode.jar differ diff --git a/tools/model_generator/src/com/libiec61850/tools/DynamicCodeGenerator.java b/tools/model_generator/src/com/libiec61850/tools/DynamicCodeGenerator.java index c9629b73..1071242d 100644 --- a/tools/model_generator/src/com/libiec61850/tools/DynamicCodeGenerator.java +++ b/tools/model_generator/src/com/libiec61850/tools/DynamicCodeGenerator.java @@ -11,10 +11,13 @@ import java.util.LinkedList; import java.util.List; import java.util.Set; +import com.libiec61850.scl.DataAttributeDefinition; import com.libiec61850.scl.DataObjectDefinition; import com.libiec61850.scl.SclParser; import com.libiec61850.scl.SclParserException; +import com.libiec61850.scl.model.AttributeType; import com.libiec61850.scl.model.LogicalNode; +import com.libiec61850.scl.types.DataAttributeType; import com.libiec61850.scl.types.DataObjectType; import com.libiec61850.scl.types.LogicalNodeType; import com.libiec61850.scl.types.SclType; @@ -76,25 +79,48 @@ public class DynamicCodeGenerator { Set doTypeDefs = new HashSet(); Set lnTypeDefs = new HashSet(); + Set daTypeDefs = new HashSet(); List functionPrototypes = new LinkedList(); + - List types = declarations.getTypeDeclarations(); + /* Create type lists */ - for (SclType type : types) { + for (SclType type : declarations.getTypeDeclarations()) { if (type.getClass().equals(LogicalNodeType.class)) lnTypeDefs.add((LogicalNodeType) type); else if (type.getClass().equals(DataObjectType.class)) doTypeDefs.add((DataObjectType) type); - + else if (type.getClass().equals(DataAttributeType.class)) + daTypeDefs.add((DataAttributeType) type); } + /* Create function prototypes */ + for (LogicalNodeType lnType : lnTypeDefs) { String functionPrototype = "LogicalNode*\nLN_" + lnType.getId() + "_createInstance(char* lnName, LogicalDevice* parent);"; functionPrototypes.add(functionPrototype); + } + + for (DataObjectType doType : doTypeDefs) { + String functionPrototype = "DataObject*\nDO_" + doType.getId() + + "_createInstance(char* doName, ModelNode* parent);"; + + functionPrototypes.add(functionPrototype); + } + + for (DataAttributeType daType : daTypeDefs) { + String functionPrototype = "DataAttribute*\nDA_" + daType.getId() + + "_createInstance(char* daName, ModelNode* parent, FunctionalConstraint fc, uint8_t triggerOptions);"; + + functionPrototypes.add(functionPrototype); + } + + + for (LogicalNodeType lnType : lnTypeDefs) { out.println("/**"); out.printf(" * LN: %s ", lnType.getId()); @@ -109,7 +135,7 @@ public class DynamicCodeGenerator { List doDefs = lnType.getDataObjectDefinitions(); for (DataObjectDefinition objDef : doDefs) { - out.printf(" %s_createInstance(\"%s\", (ModelNode*) newLn);\n", objDef.getType(), objDef.getName()); + out.printf(" DO_%s_createInstance(\"%s\", (ModelNode*) newLn);\n", objDef.getType(), objDef.getName()); } out.println("\n return newLn;"); @@ -117,11 +143,6 @@ public class DynamicCodeGenerator { } for (DataObjectType doType : doTypeDefs) { - String functionPrototype = "DataObject*\nDO_" + doType.getId() - + "_createInstance(char* doName, ModelNode* parent);"; - - functionPrototypes.add(functionPrototype); - out.println("/**"); out.printf(" * DO: %s ", doType.getId()); if (doType.getDesc() != null) @@ -131,12 +152,70 @@ public class DynamicCodeGenerator { out.println("DataObject*"); out.printf("DO_%s_createInstance(char* doName, ModelNode* parent)\n", doType.getId()); out.println("{"); - out.println(" LogicalNode* newDo = DataObject_create(doName, parent);\n"); + out.println(" DataObject* newDo = DataObject_create(doName, parent);\n"); + + for (DataAttributeDefinition dad : doType.getDataAttributes()) { + + if (dad.getAttributeType() == AttributeType.CONSTRUCTED) { + out.print(" DA_" + dad.getType() + "_createInstance(\"" + dad.getName() + "\", "); + out.print("(ModelNode*) newDo, IEC61850_FC_" + dad.getFc().toString()); + out.print(", " + dad.getTriggerOptions().getIntValue()); + out.println(");"); + } + else { + out.print(" DataAttribute_create(\"" + dad.getName() + "\", "); + out.print("(ModelNode*) newDo, IEC61850_" + dad.getAttributeType()); + out.print(", IEC61850_FC_" + dad.getFc().toString()); + out.print(", " + dad.getTriggerOptions().getIntValue()); + out.print(", " + dad.getCount()); + out.print(", 0"); + out.println(");"); + } + + } + + + for (DataObjectDefinition dod : doType.getSubDataObjects()) { + out.print(" DO_" + dod.getType() + "_createInstance(\"" + dod.getName() + "\")"); + out.println("(ModelNode*) newDo);"); + } out.println("\n return newDo;"); out.println("}\n\n"); } + for (DataAttributeType daType : daTypeDefs) { + out.println("/**"); + out.printf(" * DA: %s ", daType.getId()); + if (daType.getDesc() != null) + out.printf("(%s)", daType.getDesc()); + out.println(); + out.println(" */"); + out.println("DataAttribute*"); + out.printf("DA_%s_createInstance(char* daName, ModelNode* parent, FunctionalConstraint fc, uint8_t triggerOptions)\n", daType.getId()); + out.println("{"); + out.println(" DataAttribute* newDa = DataAttribute_create(daName, parent, IEC61850_CONSTRUCTED, fc, triggerOptions, 0, 0);\n"); + + for (DataAttributeDefinition dad : daType.getSubDataAttributes()) { + if (dad.getAttributeType() == AttributeType.CONSTRUCTED) { + out.print(" DA_" + dad.getType() + "_createInstance(\"" + dad.getName() + "\", "); + out.println("(ModelNode*) newDo, fc, triggerOptions);"); + } + else { + out.print(" DataAttribute_create(\"" + dad.getName() + "\", "); + out.print("(ModelNode*) newDa, IEC61850_" + dad.getAttributeType()); + out.print(", fc"); + out.print(", triggerOptions"); + out.print(", " + dad.getCount()); + out.print(", 0"); + out.println(");"); + } + } + + out.println("\n return newDo;"); + out.println("}\n\n"); + + } } diff --git a/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java b/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java index 020339f7..b0500a70 100644 --- a/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java +++ b/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java @@ -706,10 +706,8 @@ public class StaticModelGenerator { cOut.println("};\n"); - if (dataAttribute.getSubDataAttributes() != null) - - - printDataAttributeDefinitions(daName, dataAttribute.getSubDataAttributes()); + if (dataAttribute.getSubDataAttributes() != null) + printDataAttributeDefinitions(daName, dataAttribute.getSubDataAttributes()); DataModelValue value = dataAttribute.getValue();