diff --git a/src/iec61850/inc/iec61850_cdc.h b/src/iec61850/inc/iec61850_cdc.h index 6144bea5..139f0182 100644 --- a/src/iec61850/inc/iec61850_cdc.h +++ b/src/iec61850/inc/iec61850_cdc.h @@ -46,12 +46,20 @@ extern "C" { */ #define CDC_OPTION_PICS_SUBST (1 << 0) #define CDC_OPTION_BLK_ENA (1 << 1) + +/** Add d (description) data attribute */ #define CDC_OPTION_DESC (1 << 2) + +/** Add dU (unicode description) data attribute */ #define CDC_OPTION_DESC_UNICODE (1 << 3) +/** Add cdcNs and cdcName required when a CDC is an extension to the standard */ #define CDC_OPTION_AC_DLNDA (1 << 4) + +/** Add dataNs (data namespace) required for extended CDCs */ #define CDC_OPTION_AC_DLN (1 << 5) +/** Add the unit data attribute */ #define CDC_OPTION_UNIT (1 << 6) #define CDC_OPTION_FROZEN_VALUE (1 << 7) @@ -87,6 +95,17 @@ extern "C" { #define CDC_OPTION_ANGLE_REF (1 << 23) +/** Options that are only valid for DPL CDC */ +#define CDC_OPTION_DPL_HWREV (1 << 17) +#define CDC_OPTION_DPL_SWREV (1 << 18) +#define CDC_OPTION_DPL_SERNUM (1 << 19) +#define CDC_OPTION_DPL_MODEL (1 << 20) +#define CDC_OPTION_DPL_LOCATION (1 << 21) + +/** Add mandatory data attributes for LLN0 (e.g. LBL configRef) */ +#define CDC_OPTION_AC_LN0_M (1 << 24) +#define CDC_OPTION_AC_LN0_EX (1 << 25) +#define CDC_OPTION_AC_DLD_M (1 << 26) /** * \brief Control model types @@ -233,10 +252,54 @@ CDC_CMV_create(const char* dataObjectName, ModelNode* parent, uint32_t options); DataObject* CDC_SAV_create(const char* dataObjectName, ModelNode* parent, uint32_t options, bool isIntegerNotFloat); - +/** + * \brief create a new LPL (Logical node name plate) CDC instance (data object) + * + * Allowed parent type is LogicalNode + * + * possible options: + * CDC_OPTION_AC_LN0_M (includes "configRev") + * CDC_OPTION_AC_LN0_EX (includes "ldNs") + * CDC_OPTION_AC_DLD_M (includes "lnNs") + * standard options: + * CDC_OPTION_DESC (includes "d") + * CDC_OPTION_DESC_UNICODE (include "du") + * CDC_OPTION_AC_DLNDA (include "cdcNs" and "cdcName") + * CDC_OPTION_AC_DLN (includes "dataNs") + * + * \param dataObjectName the name of the new object + * \param parent the parent of the new data object (either a LogicalNode or another DataObject) + * \param options bit mask to encode required optional elements + * + * \return new DataObject instance + */ DataObject* CDC_LPL_create(const char* dataObjectName, ModelNode* parent, uint32_t options); +/** + * \brief create a new DPL (Device name plate) CDC instance (data object) + * + * Allowed parent type is LogicalNode + * + * possible options: + * CDC_OPTION_DPL_HWREV (includes "hwRev") + * CDC_OPTION_DPL_SWREV (includes "swRev") + * CDC_OPTION_DPL_SERNUM (includes "serNum") + * CDC_OPTION_DPL_MODEL (includes "model") + * CDC_OPTION_DPL_LOCATION (includes "location") + * standard options: + * CDC_OPTION_AC_DLNDA (include "cdcNs" and "cdcName") + * CDC_OPTION_AC_DLN (includes "dataNs") + * + * \param dataObjectName the name of the new object + * \param parent the parent of the new data object (either a LogicalNode or another DataObject) + * \param options bit mask to encode required optional elements + * + * \return new DataObject instance + */ +DataObject* +CDC_DPL_create(const char* dataObjectName, ModelNode* parent, uint32_t options); + DataObject* CDC_HST_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint16_t maxPts); diff --git a/src/iec61850/inc/iec61850_dynamic_model.h b/src/iec61850/inc/iec61850_dynamic_model.h index bb82faa5..ee011dbe 100644 --- a/src/iec61850/inc/iec61850_dynamic_model.h +++ b/src/iec61850/inc/iec61850_dynamic_model.h @@ -169,7 +169,7 @@ ReportControlBlock_create(const char* name, LogicalNode* parent, char* rptId, bo * \param parent the parent LN. * \param dataSetName name (object reference) of the default data set or NULL if no data set * is set by default - * \param logRef name (object reference) of the default log or NULL if no log is set by default + * \param logRef name (object reference) of the default log or NULL if no log is set by default. THe LDname doesn't contain the IED name! * \param trgOps the trigger options supported by this LCB (bit set) * \param intgPd integrity period in milliseconds * \param logEna if true the log will be enabled by default, false otherwise diff --git a/src/iec61850/inc/iec61850_model.h b/src/iec61850/inc/iec61850_model.h index 961e640d..3a99b086 100644 --- a/src/iec61850/inc/iec61850_model.h +++ b/src/iec61850/inc/iec61850_model.h @@ -1,7 +1,7 @@ /* * model.h * - * Copyright 2013, 2014, 2015 Michael Zillgith + * Copyright 2013-2016 Michael Zillgith * * This file is part of libIEC61850. * diff --git a/src/iec61850/server/model/cdc.c b/src/iec61850/server/model/cdc.c index eb6806e9..acbcaadd 100644 --- a/src/iec61850/server/model/cdc.c +++ b/src/iec61850/server/model/cdc.c @@ -774,11 +774,47 @@ CDC_LPL_create(const char* dataObjectName, ModelNode* parent, uint32_t options) DataAttribute_create("vendor", (ModelNode*) newLPL, IEC61850_VISIBLE_STRING_255, IEC61850_FC_DC, 0, 0, 0); DataAttribute_create("swRev", (ModelNode*) newLPL, IEC61850_VISIBLE_STRING_255, IEC61850_FC_DC, 0, 0, 0); + if (options & CDC_OPTION_AC_LN0_M) + DataAttribute_create("configRev", (ModelNode*) newLPL, IEC61850_VISIBLE_STRING_255, IEC61850_FC_DC, 0, 0, 0); + + if (options & CDC_OPTION_AC_LN0_EX) + DataAttribute_create("ldNs", (ModelNode*) newLPL, IEC61850_VISIBLE_STRING_255, IEC61850_FC_EX, 0, 0, 0); + + if (options & CDC_OPTION_AC_DLD_M) + DataAttribute_create("lnNs", (ModelNode*) newLPL, IEC61850_VISIBLE_STRING_255, IEC61850_FC_EX, 0, 0, 0); + CDC_addStandardOptions(newLPL, options); return newLPL; } +DataObject* +CDC_DPL_create(const char* dataObjectName, ModelNode* parent, uint32_t options) +{ + DataObject* newDPL = DataObject_create(dataObjectName, parent, 0); + + DataAttribute_create("vendor", (ModelNode*) newDPL, IEC61850_VISIBLE_STRING_255, IEC61850_FC_DC, 0, 0, 0); + + if (options & CDC_OPTION_DPL_HWREV) + DataAttribute_create("hwRev", (ModelNode*) newDPL, IEC61850_VISIBLE_STRING_255, IEC61850_FC_DC, 0, 0, 0); + + if (options & CDC_OPTION_DPL_SWREV) + DataAttribute_create("swRev", (ModelNode*) newDPL, IEC61850_VISIBLE_STRING_255, IEC61850_FC_DC, 0, 0, 0); + + if (options & CDC_OPTION_DPL_SERNUM) + DataAttribute_create("serNum", (ModelNode*) newDPL, IEC61850_VISIBLE_STRING_255, IEC61850_FC_DC, 0, 0, 0); + + if (options & CDC_OPTION_DPL_MODEL) + DataAttribute_create("model", (ModelNode*) newDPL, IEC61850_VISIBLE_STRING_255, IEC61850_FC_DC, 0, 0, 0); + + if (options & CDC_OPTION_DPL_LOCATION) + DataAttribute_create("location", (ModelNode*) newDPL, IEC61850_VISIBLE_STRING_255, IEC61850_FC_DC, 0, 0, 0); + + CDC_addStandardOptions(newDPL, options); + + return newDPL; +} + /* Directional protection activation information (ACD) */ DataObject* CDC_ACD_create(const char* dataObjectName, ModelNode* parent, uint32_t options) diff --git a/src/iec61850/server/model/config_file_parser.c b/src/iec61850/server/model/config_file_parser.c index e34258dc..a1ba90bb 100644 --- a/src/iec61850/server/model/config_file_parser.c +++ b/src/iec61850/server/model/config_file_parser.c @@ -215,6 +215,34 @@ ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle) ReportControlBlock_create(nameString, currentLN, rptId, (bool) isBuffered, dataSetName, confRef, trgOps, options, bufTm, intgPd); } + else if (StringUtils_startsWith((char*) lineBuffer, "LC")) { + uint32_t trgOps; + uint32_t intgPd; + int logEna; + int withReasonCode; + + int matchedItems = sscanf((char*) lineBuffer, "LC(%s %s %s %u %u %i %i)", + nameString, nameString2, nameString3, &trgOps, &intgPd, &logEna, &withReasonCode); + + if (matchedItems < 7) goto exit_error; + + char* dataSet = NULL; + if (strcmp(nameString2, "-") != 0) + dataSet = nameString2; + + char* logRef = NULL; + if (strcmp(nameString3, "-") != 0) + logRef = nameString3; + + LogControlBlock_create(nameString, currentLN, dataSet, logRef, trgOps, intgPd, logEna, withReasonCode); + } + else if (StringUtils_startsWith((char*) lineBuffer, "LOG")) { + int matchedItems = sscanf((char*) lineBuffer, "LOG(%s)", nameString); + + if (matchedItems < 1) goto exit_error; + + Log_create(nameString, currentLN); + } else if (StringUtils_startsWith((char*) lineBuffer, "GC")) { uint32_t confRef; int fixedOffs; diff --git a/src/vs/libiec61850-wo-goose.def b/src/vs/libiec61850-wo-goose.def index b1b511f5..7411d01a 100644 --- a/src/vs/libiec61850-wo-goose.def +++ b/src/vs/libiec61850-wo-goose.def @@ -547,3 +547,4 @@ EXPORTS Log_create IedConnection_queryLogByTime IedConnection_queryLogAfter + CDC_DPL_create diff --git a/src/vs/libiec61850.def b/src/vs/libiec61850.def index 26594733..d80f83e4 100644 --- a/src/vs/libiec61850.def +++ b/src/vs/libiec61850.def @@ -623,4 +623,4 @@ EXPORTS Log_create IedConnection_queryLogByTime IedConnection_queryLogAfter - + CDC_DPL_create diff --git a/tools/model_generator/genconfig.jar b/tools/model_generator/genconfig.jar index 9e3e43d5..eaf73e39 100644 Binary files a/tools/model_generator/genconfig.jar and b/tools/model_generator/genconfig.jar differ diff --git a/tools/model_generator/genmodel.jar b/tools/model_generator/genmodel.jar index b90d292c..cd7d60b7 100644 Binary files a/tools/model_generator/genmodel.jar and b/tools/model_generator/genmodel.jar differ diff --git a/tools/model_generator/src/com/libiec61850/tools/DynamicModelGenerator.java b/tools/model_generator/src/com/libiec61850/tools/DynamicModelGenerator.java index a7fd6606..f936fab2 100644 --- a/tools/model_generator/src/com/libiec61850/tools/DynamicModelGenerator.java +++ b/tools/model_generator/src/com/libiec61850/tools/DynamicModelGenerator.java @@ -44,6 +44,8 @@ import com.libiec61850.scl.model.DataSet; import com.libiec61850.scl.model.FunctionalConstraintData; import com.libiec61850.scl.model.GSEControl; import com.libiec61850.scl.model.IED; +import com.libiec61850.scl.model.Log; +import com.libiec61850.scl.model.LogControl; import com.libiec61850.scl.model.LogicalDevice; import com.libiec61850.scl.model.LogicalNode; import com.libiec61850.scl.model.ReportControlBlock; @@ -97,7 +99,7 @@ public class DynamicModelGenerator { for (LogicalNode logicalNode : logicalDevice.getLogicalNodes()) { output.print("LN(" + logicalNode.getName() + "){\n"); - exportLogicalNode(output, logicalNode); + exportLogicalNode(output, logicalNode, logicalDevice); output.println("}"); } @@ -107,7 +109,7 @@ public class DynamicModelGenerator { return iecString.replace('.', '$'); } - private void exportLogicalNode(PrintStream output, LogicalNode logicalNode) { + private void exportLogicalNode(PrintStream output, LogicalNode logicalNode, LogicalDevice logicalDevice) { for (SettingControl sgcb : logicalNode.getSettingGroupControlBlocks()) { output.print("SG(" + sgcb.getActSG() + " " + sgcb.getNumOfSGs() + ")\n"); @@ -142,6 +144,12 @@ public class DynamicModelGenerator { printRCBInstance(output, rcb, ""); } + for (LogControl lcb : logicalNode.getLogControlBlocks()) + printLCB(output, lcb, logicalNode, logicalDevice); + + for (Log log : logicalNode.getLogs()) + output.println("LOG(" + log.getName() + ")"); + for (GSEControl gcb : logicalNode.getGSEControlBlocks()) { LogicalDevice ld = logicalNode.getParentLogicalDevice(); @@ -187,6 +195,36 @@ public class DynamicModelGenerator { } } } + + private void printLCB(PrintStream output, LogControl lcb, LogicalNode ln, LogicalDevice logicalDevice) { + output.print("LC("); + output.print(lcb.getName() + " "); + + if (lcb.getDataSet() != null) + output.print(lcb.getDataSet() + " "); + else + output.print("- "); + + if (lcb.getLogName() != null) { + String logRef = logicalDevice.getInst() + "/" + ln.getName() + "$" + lcb.getLogName(); + output.print(logRef + " "); + } + else + output.print("- "); + + output.print(lcb.getTriggerOptions().getIntValue() + " "); + output.print(lcb.getIntgPd() + " "); + + if (lcb.isLogEna()) + output.print("1 "); + else + output.print("0 "); + + if (lcb.isReasonCode()) + output.println("1)"); + else + output.println("0)"); + } private void printRCBInstance(PrintStream output, ReportControlBlock rcb, String index) { output.print("RC(");