Merge branch 'v1.6_develop' into v1.6_develop_rgoose_sntp

v1.6_develop_rgoose_sntp
Michael Zillgith 2 years ago
commit 3d3b8c6982

@ -93,7 +93,7 @@ SCL.xsd">
</DataSet> </DataSet>
<SampledValueControl name="MSVCB01" datSet="PhsMeas1" <SampledValueControl name="MSVCB01" datSet="PhsMeas1"
smvID="xxxxMUnn01" smpRate="80" nofASDU="1" confRev="1"> smvID="xxxxMUnn01" smpRate="80" nofASDU="1" confRev="1" smpMod="SmpPerPeriod">
<SmvOpts refreshTime="false" sampleSynchronized="true" <SmvOpts refreshTime="false" sampleSynchronized="true"
security="false" dataRef="false" /> security="false" dataRef="false" />

@ -104,8 +104,8 @@ GoosePublisher_createEx(CommParameters* parameters, const char* interfaceID, boo
{ {
GoosePublisher self = (GoosePublisher) GLOBAL_CALLOC(1, sizeof(struct sGoosePublisher)); GoosePublisher self = (GoosePublisher) GLOBAL_CALLOC(1, sizeof(struct sGoosePublisher));
if (self) { if (self)
{
if (prepareGooseBuffer(self, parameters, interfaceID, useVlanTag)) { if (prepareGooseBuffer(self, parameters, interfaceID, useVlanTag)) {
self->timestamp = MmsValue_newUtcTimeByMsTime(Hal_getTimeInMs()); self->timestamp = MmsValue_newUtcTimeByMsTime(Hal_getTimeInMs());
@ -115,7 +115,6 @@ GoosePublisher_createEx(CommParameters* parameters, const char* interfaceID, boo
GoosePublisher_destroy(self); GoosePublisher_destroy(self);
self = NULL; self = NULL;
} }
} }
return self; return self;
@ -130,20 +129,21 @@ GoosePublisher_create(CommParameters* parameters, const char* interfaceID)
void void
GoosePublisher_destroy(GoosePublisher self) GoosePublisher_destroy(GoosePublisher self)
{ {
if (self) { if (self)
{
if (self->ethernetSocket) { if (self->ethernetSocket) {
Ethernet_destroySocket(self->ethernetSocket); Ethernet_destroySocket(self->ethernetSocket);
} }
MmsValue_delete(self->timestamp); MmsValue_delete(self->timestamp);
if (self->goID != NULL) if (self->goID)
GLOBAL_FREEMEM(self->goID); GLOBAL_FREEMEM(self->goID);
if (self->goCBRef != NULL) if (self->goCBRef)
GLOBAL_FREEMEM(self->goCBRef); GLOBAL_FREEMEM(self->goCBRef);
if (self->dataSetRef != NULL) if (self->dataSetRef)
GLOBAL_FREEMEM(self->dataSetRef); GLOBAL_FREEMEM(self->dataSetRef);
if (self->buffer) if (self->buffer)
@ -156,18 +156,27 @@ GoosePublisher_destroy(GoosePublisher self)
void void
GoosePublisher_setGoID(GoosePublisher self, char* goID) GoosePublisher_setGoID(GoosePublisher self, char* goID)
{ {
if (self->goID)
GLOBAL_FREEMEM(self->goID);
self->goID = StringUtils_copyString(goID); self->goID = StringUtils_copyString(goID);
} }
void void
GoosePublisher_setGoCbRef(GoosePublisher self, char* goCbRef) GoosePublisher_setGoCbRef(GoosePublisher self, char* goCbRef)
{ {
if (self->goCBRef)
GLOBAL_FREEMEM(self->goCBRef);
self->goCBRef = StringUtils_copyString(goCbRef); self->goCBRef = StringUtils_copyString(goCbRef);
} }
void void
GoosePublisher_setDataSetRef(GoosePublisher self, char* dataSetRef) GoosePublisher_setDataSetRef(GoosePublisher self, char* dataSetRef)
{ {
if (self->dataSetRef)
GLOBAL_FREEMEM(self->dataSetRef);
self->dataSetRef = StringUtils_copyString(dataSetRef); self->dataSetRef = StringUtils_copyString(dataSetRef);
} }
@ -236,7 +245,7 @@ prepareGooseBuffer(GoosePublisher self, CommParameters* parameters, const char*
{ {
uint8_t srcAddr[6]; uint8_t srcAddr[6];
if (interfaceID != NULL) if (interfaceID)
Ethernet_getInterfaceMACAddress(interfaceID, srcAddr); Ethernet_getInterfaceMACAddress(interfaceID, srcAddr);
else else
Ethernet_getInterfaceMACAddress(CONFIG_ETHERNET_INTERFACE_ID, srcAddr); Ethernet_getInterfaceMACAddress(CONFIG_ETHERNET_INTERFACE_ID, srcAddr);
@ -248,7 +257,7 @@ prepareGooseBuffer(GoosePublisher self, CommParameters* parameters, const char*
uint16_t vlanId; uint16_t vlanId;
uint16_t appId; uint16_t appId;
if (parameters == NULL) { if (parameters) {
dstAddr = defaultDstAddr; dstAddr = defaultDstAddr;
priority = CONFIG_GOOSE_DEFAULT_PRIORITY; priority = CONFIG_GOOSE_DEFAULT_PRIORITY;
vlanId = CONFIG_GOOSE_DEFAULT_VLAN_ID; vlanId = CONFIG_GOOSE_DEFAULT_VLAN_ID;
@ -261,7 +270,7 @@ prepareGooseBuffer(GoosePublisher self, CommParameters* parameters, const char*
appId = parameters->appId; appId = parameters->appId;
} }
if (interfaceID != NULL) if (interfaceID)
self->ethernetSocket = Ethernet_createSocket(interfaceID, dstAddr); self->ethernetSocket = Ethernet_createSocket(interfaceID, dstAddr);
else else
self->ethernetSocket = Ethernet_createSocket(CONFIG_ETHERNET_INTERFACE_ID, dstAddr); self->ethernetSocket = Ethernet_createSocket(CONFIG_ETHERNET_INTERFACE_ID, dstAddr);
@ -333,7 +342,7 @@ createGoosePayload(GoosePublisher self, LinkedList dataSetValues, uint8_t* buffe
goosePduLength += BerEncoder_determineEncodedStringSize(self->dataSetRef); goosePduLength += BerEncoder_determineEncodedStringSize(self->dataSetRef);
if (self->goID != NULL) if (self->goID)
goosePduLength += BerEncoder_determineEncodedStringSize(self->goID); goosePduLength += BerEncoder_determineEncodedStringSize(self->goID);
else else
goosePduLength += BerEncoder_determineEncodedStringSize(self->goCBRef); goosePduLength += BerEncoder_determineEncodedStringSize(self->goCBRef);
@ -356,7 +365,7 @@ createGoosePayload(GoosePublisher self, LinkedList dataSetValues, uint8_t* buffe
LinkedList element = LinkedList_getNext(dataSetValues); LinkedList element = LinkedList_getNext(dataSetValues);
while (element != NULL) { while (element) {
MmsValue* dataSetEntry = (MmsValue*) element->data; MmsValue* dataSetEntry = (MmsValue*) element->data;
if (dataSetEntry) { if (dataSetEntry) {
@ -397,7 +406,7 @@ createGoosePayload(GoosePublisher self, LinkedList dataSetValues, uint8_t* buffe
bufPos = BerEncoder_encodeStringWithTag(0x82, self->dataSetRef, buffer, bufPos); bufPos = BerEncoder_encodeStringWithTag(0x82, self->dataSetRef, buffer, bufPos);
/* Encode goID */ /* Encode goID */
if (self->goID != NULL) if (self->goID)
bufPos = BerEncoder_encodeStringWithTag(0x83, self->goID, buffer, bufPos); bufPos = BerEncoder_encodeStringWithTag(0x83, self->goID, buffer, bufPos);
else else
bufPos = BerEncoder_encodeStringWithTag(0x83, self->goCBRef, buffer, bufPos); bufPos = BerEncoder_encodeStringWithTag(0x83, self->goCBRef, buffer, bufPos);
@ -429,7 +438,7 @@ createGoosePayload(GoosePublisher self, LinkedList dataSetValues, uint8_t* buffe
/* Encode data set entries */ /* Encode data set entries */
element = LinkedList_getNext(dataSetValues); element = LinkedList_getNext(dataSetValues);
while (element != NULL) { while (element) {
MmsValue* dataSetEntry = (MmsValue*) element->data; MmsValue* dataSetEntry = (MmsValue*) element->data;
if (dataSetEntry) { if (dataSetEntry) {

@ -186,7 +186,7 @@ GoosePublisher_setStNum(GoosePublisher self, uint32_t stNum);
* NOTE: Only for testing! The sequence number is increase manually whenever \ref GoosePublisher_publish is called. * NOTE: Only for testing! The sequence number is increase manually whenever \ref GoosePublisher_publish is called.
* *
* \param self GoosePublisher instance * \param self GoosePublisher instance
* \param stNum the state number of the next GOOSE message to send * \param sqNum the sequence number of the next GOOSE message to send
*/ */
LIB61850_API void LIB61850_API void
GoosePublisher_setSqNum(GoosePublisher self, uint32_t sqNum); GoosePublisher_setSqNum(GoosePublisher self, uint32_t sqNum);

@ -3,7 +3,7 @@
* *
* Helper functions for the dynamic creation of Common Data Classes (CDCs) * Helper functions for the dynamic creation of Common Data Classes (CDCs)
* *
* Copyright 2014 Michael Zillgith * Copyright 2014-2023 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -35,7 +35,7 @@ DataAttribute*
CAC_AnalogueValue_create(const char* name, ModelNode* parent, FunctionalConstraint fc, uint8_t triggerOptions, CAC_AnalogueValue_create(const char* name, ModelNode* parent, FunctionalConstraint fc, uint8_t triggerOptions,
bool isIntegerNotFloat) bool isIntegerNotFloat)
{ {
DataAttribute* analogeValue = DataAttribute_create(name, parent, IEC61850_CONSTRUCTED, fc, triggerOptions, 0, 0); DataAttribute* analogeValue = (name == NULL) ? (DataAttribute*)parent : DataAttribute_create(name, parent, IEC61850_CONSTRUCTED, fc, triggerOptions, 0, 0);
if (isIntegerNotFloat) if (isIntegerNotFloat)
DataAttribute_create("i", (ModelNode*) analogeValue, IEC61850_INT32, fc, triggerOptions, 0, 0); DataAttribute_create("i", (ModelNode*) analogeValue, IEC61850_INT32, fc, triggerOptions, 0, 0);
@ -48,7 +48,7 @@ CAC_AnalogueValue_create(const char* name, ModelNode* parent, FunctionalConstrai
DataAttribute* DataAttribute*
CAC_ValWithTrans_create(const char* name, ModelNode* parent, FunctionalConstraint fc, uint8_t triggerOptions, bool hasTransientIndicator) CAC_ValWithTrans_create(const char* name, ModelNode* parent, FunctionalConstraint fc, uint8_t triggerOptions, bool hasTransientIndicator)
{ {
DataAttribute* valWithTrans = DataAttribute_create(name, parent, IEC61850_CONSTRUCTED, fc, triggerOptions, 0, 0); DataAttribute* valWithTrans = (name == NULL) ? (DataAttribute*)parent : DataAttribute_create(name, parent, IEC61850_CONSTRUCTED, fc, triggerOptions, 0, 0);
DataAttribute_create("posVal", (ModelNode*) valWithTrans, IEC61850_INT8, fc, triggerOptions, 0, 0); DataAttribute_create("posVal", (ModelNode*) valWithTrans, IEC61850_INT8, fc, triggerOptions, 0, 0);
@ -64,7 +64,7 @@ CAC_ValWithTrans_create(const char* name, ModelNode* parent, FunctionalConstrain
DataAttribute* DataAttribute*
CAC_Vector_create(const char* name, ModelNode* parent, uint32_t options, FunctionalConstraint fc, uint8_t triggerOptions) CAC_Vector_create(const char* name, ModelNode* parent, uint32_t options, FunctionalConstraint fc, uint8_t triggerOptions)
{ {
DataAttribute* vector = DataAttribute_create(name, parent, IEC61850_CONSTRUCTED, fc, triggerOptions, 0, 0); DataAttribute* vector = (name == NULL) ? (DataAttribute*)parent : DataAttribute_create(name, parent, IEC61850_CONSTRUCTED, fc, triggerOptions, 0, 0);
CAC_AnalogueValue_create("mag", (ModelNode*) vector, fc, triggerOptions, false); CAC_AnalogueValue_create("mag", (ModelNode*) vector, fc, triggerOptions, false);
@ -77,7 +77,7 @@ CAC_Vector_create(const char* name, ModelNode* parent, uint32_t options, Functio
DataAttribute* DataAttribute*
CAC_Point_create(const char* name, ModelNode* parent, FunctionalConstraint fc, uint8_t triggerOptions, bool hasZVal) CAC_Point_create(const char* name, ModelNode* parent, FunctionalConstraint fc, uint8_t triggerOptions, bool hasZVal)
{ {
DataAttribute* point = DataAttribute_create(name, parent, IEC61850_CONSTRUCTED, fc, triggerOptions, 0, 0); DataAttribute* point = (name == NULL) ? (DataAttribute*)parent : DataAttribute_create(name, parent, IEC61850_CONSTRUCTED, fc, triggerOptions, 0, 0);
DataAttribute_create("xVal", (ModelNode*) point, IEC61850_FLOAT32, fc, triggerOptions, 0, 0); DataAttribute_create("xVal", (ModelNode*) point, IEC61850_FLOAT32, fc, triggerOptions, 0, 0);
DataAttribute_create("yVal", (ModelNode*) point, IEC61850_FLOAT32, fc, triggerOptions, 0, 0); DataAttribute_create("yVal", (ModelNode*) point, IEC61850_FLOAT32, fc, triggerOptions, 0, 0);
@ -91,7 +91,7 @@ CAC_Point_create(const char* name, ModelNode* parent, FunctionalConstraint fc, u
DataAttribute* DataAttribute*
CAC_ScaledValueConfig_create(const char* name, ModelNode* parent) CAC_ScaledValueConfig_create(const char* name, ModelNode* parent)
{ {
DataAttribute* scaling = DataAttribute_create(name, parent, IEC61850_CONSTRUCTED, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0); DataAttribute* scaling = (name == NULL) ? (DataAttribute*)parent : DataAttribute_create(name, parent, IEC61850_CONSTRUCTED, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0);
DataAttribute_create("scaleFactor", (ModelNode*) scaling, IEC61850_FLOAT32, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0); DataAttribute_create("scaleFactor", (ModelNode*) scaling, IEC61850_FLOAT32, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0);
DataAttribute_create("offset", (ModelNode*) scaling, IEC61850_FLOAT32, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0); DataAttribute_create("offset", (ModelNode*) scaling, IEC61850_FLOAT32, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0);
@ -102,7 +102,7 @@ CAC_ScaledValueConfig_create(const char* name, ModelNode* parent)
DataAttribute* DataAttribute*
CAC_Unit_create(const char* name, ModelNode* parent, bool hasMagnitude) CAC_Unit_create(const char* name, ModelNode* parent, bool hasMagnitude)
{ {
DataAttribute* unit = DataAttribute_create(name, parent, IEC61850_CONSTRUCTED, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0); DataAttribute* unit = (name == NULL) ? (DataAttribute*)parent : DataAttribute_create(name, parent, IEC61850_CONSTRUCTED, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0);
DataAttribute_create("SIUnit", (ModelNode*) unit, IEC61850_ENUMERATED, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0); DataAttribute_create("SIUnit", (ModelNode*) unit, IEC61850_ENUMERATED, IEC61850_FC_CF, TRG_OPT_DATA_CHANGED, 0, 0);
@ -255,7 +255,7 @@ CDC_addStandardOptions(DataObject* dataObject, uint32_t options)
DataObject* DataObject*
CDC_SPS_create(const char* dataObjectName, ModelNode* parent, uint32_t options) CDC_SPS_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
{ {
DataObject* newSPS = DataObject_create(dataObjectName, parent, 0); DataObject* newSPS = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
CDC_addStatusToDataObject(newSPS, IEC61850_BOOLEAN); CDC_addStatusToDataObject(newSPS, IEC61850_BOOLEAN);
@ -273,7 +273,7 @@ CDC_SPS_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
DataObject* DataObject*
CDC_DPS_create(const char* dataObjectName, ModelNode* parent, uint32_t options) CDC_DPS_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
{ {
DataObject* newDPS = DataObject_create(dataObjectName, parent, 0); DataObject* newDPS = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
CDC_addStatusToDataObject(newDPS, IEC61850_CODEDENUM); CDC_addStatusToDataObject(newDPS, IEC61850_CODEDENUM);
@ -291,7 +291,7 @@ CDC_DPS_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
DataObject* DataObject*
CDC_INS_create(const char* dataObjectName, ModelNode* parent, uint32_t options) CDC_INS_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
{ {
DataObject* newINS = DataObject_create(dataObjectName, parent, 0); DataObject* newINS = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
CDC_addStatusToDataObject(newINS, IEC61850_INT32); CDC_addStatusToDataObject(newINS, IEC61850_INT32);
@ -310,7 +310,7 @@ CDC_INS_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
DataObject* DataObject*
CDC_ENS_create(const char* dataObjectName, ModelNode* parent, uint32_t options) CDC_ENS_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
{ {
DataObject* newENS = DataObject_create(dataObjectName, parent, 0); DataObject* newENS = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
CDC_addStatusToDataObject(newENS, IEC61850_ENUMERATED); CDC_addStatusToDataObject(newENS, IEC61850_ENUMERATED);
@ -328,7 +328,7 @@ CDC_ENS_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
DataObject* DataObject*
CDC_BCR_create(const char* dataObjectName, ModelNode* parent, uint32_t options) CDC_BCR_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
{ {
DataObject* newBCR = DataObject_create(dataObjectName, parent, 0); DataObject* newBCR = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
DataAttribute_create("actVal", (ModelNode*) newBCR, IEC61850_INT64, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0); DataAttribute_create("actVal", (ModelNode*) newBCR, IEC61850_INT64, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0);
@ -359,7 +359,7 @@ CDC_BCR_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
DataObject* DataObject*
CDC_SEC_create(const char* dataObjectName, ModelNode* parent, uint32_t options) CDC_SEC_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
{ {
DataObject* newSEC = DataObject_create(dataObjectName, parent, 0); DataObject* newSEC = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
DataAttribute_create("cnt", (ModelNode*) newSEC, IEC61850_INT32U, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0); DataAttribute_create("cnt", (ModelNode*) newSEC, IEC61850_INT32U, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0);
DataAttribute_create("sev", (ModelNode*) newSEC, IEC61850_ENUMERATED, IEC61850_FC_ST, 0, 0, 0); DataAttribute_create("sev", (ModelNode*) newSEC, IEC61850_ENUMERATED, IEC61850_FC_ST, 0, 0, 0);
@ -380,7 +380,7 @@ CDC_SEC_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
DataObject* DataObject*
CDC_VSS_create(const char* dataObjectName, ModelNode* parent, uint32_t options) CDC_VSS_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
{ {
DataObject* newSPS = DataObject_create(dataObjectName, parent, 0); DataObject* newSPS = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
CDC_addStatusToDataObject(newSPS, IEC61850_VISIBLE_STRING_255); CDC_addStatusToDataObject(newSPS, IEC61850_VISIBLE_STRING_255);
@ -403,7 +403,7 @@ CDC_VSS_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
DataObject* DataObject*
CDC_MV_create(const char* dataObjectName, ModelNode* parent, uint32_t options, bool isIntegerNotFloat) CDC_MV_create(const char* dataObjectName, ModelNode* parent, uint32_t options, bool isIntegerNotFloat)
{ {
DataObject* newMV = DataObject_create(dataObjectName, parent, 0); DataObject* newMV = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
if (options & CDC_OPTION_INST_MAG) if (options & CDC_OPTION_INST_MAG)
CAC_AnalogueValue_create("instMag", (ModelNode*) newMV, IEC61850_FC_MX, 0, isIntegerNotFloat); CAC_AnalogueValue_create("instMag", (ModelNode*) newMV, IEC61850_FC_MX, 0, isIntegerNotFloat);
@ -432,7 +432,7 @@ CDC_MV_create(const char* dataObjectName, ModelNode* parent, uint32_t options, b
DataObject* DataObject*
CDC_CMV_create(const char* dataObjectName, ModelNode* parent, uint32_t options) CDC_CMV_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
{ {
DataObject* newMV = DataObject_create(dataObjectName, parent, 0); DataObject* newMV = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
if (options & CDC_OPTION_INST_MAG) if (options & CDC_OPTION_INST_MAG)
CAC_Vector_create("instCVal", (ModelNode*) newMV, options, IEC61850_FC_MX, 0); CAC_Vector_create("instCVal", (ModelNode*) newMV, options, IEC61850_FC_MX, 0);
@ -465,7 +465,7 @@ CDC_CMV_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
DataObject* DataObject*
CDC_SAV_create(const char* dataObjectName, ModelNode* parent, uint32_t options, bool isIntegerNotFloat) CDC_SAV_create(const char* dataObjectName, ModelNode* parent, uint32_t options, bool isIntegerNotFloat)
{ {
DataObject* newSAV = DataObject_create(dataObjectName, parent, 0); DataObject* newSAV = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
CAC_AnalogueValue_create("instMag", (ModelNode*) newSAV, IEC61850_FC_MX, 0, isIntegerNotFloat); CAC_AnalogueValue_create("instMag", (ModelNode*) newSAV, IEC61850_FC_MX, 0, isIntegerNotFloat);
@ -491,7 +491,7 @@ CDC_SAV_create(const char* dataObjectName, ModelNode* parent, uint32_t options,
DataObject* DataObject*
CDC_HST_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint16_t maxPts) CDC_HST_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint16_t maxPts)
{ {
DataObject* newHST = DataObject_create(dataObjectName, parent, 0); DataObject* newHST = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
DataAttribute_create("hstVal", (ModelNode*) newHST, IEC61850_INT32, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED | TRG_OPT_DATA_UPDATE, maxPts, 0); DataAttribute_create("hstVal", (ModelNode*) newHST, IEC61850_INT32, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED | TRG_OPT_DATA_UPDATE, maxPts, 0);
@ -577,7 +577,7 @@ addCommonControlAttributes(DataObject* dobj, uint32_t controlOptions)
DataObject* DataObject*
CDC_SPC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions) CDC_SPC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions)
{ {
DataObject* newSPC = DataObject_create(dataObjectName, parent, 0); DataObject* newSPC = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
addOriginatorAndCtlNumOptions((ModelNode*) newSPC, controlOptions); addOriginatorAndCtlNumOptions((ModelNode*) newSPC, controlOptions);
@ -613,7 +613,7 @@ CDC_SPC_create(const char* dataObjectName, ModelNode* parent, uint32_t options,
DataObject* DataObject*
CDC_DPC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions) CDC_DPC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions)
{ {
DataObject* newDPC = DataObject_create(dataObjectName, parent, 0); DataObject* newDPC = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
addOriginatorAndCtlNumOptions((ModelNode*) newDPC, controlOptions); addOriginatorAndCtlNumOptions((ModelNode*) newDPC, controlOptions);
@ -695,7 +695,7 @@ addControlStatusAttributesForAnalogControl(DataObject* dobj, uint32_t controlOpt
DataObject* DataObject*
CDC_APC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions, bool isIntegerNotFloat) CDC_APC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions, bool isIntegerNotFloat)
{ {
DataObject* newAPC = DataObject_create(dataObjectName, parent, 0); DataObject* newAPC = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
addControlStatusAttributesForAnalogControl(newAPC, controlOptions); addControlStatusAttributesForAnalogControl(newAPC, controlOptions);
@ -728,7 +728,7 @@ CDC_APC_create(const char* dataObjectName, ModelNode* parent, uint32_t options,
DataObject* DataObject*
CDC_INC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions) CDC_INC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions)
{ {
DataObject* newINC = DataObject_create(dataObjectName, parent, 0); DataObject* newINC = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
addOriginatorAndCtlNumOptions((ModelNode*) newINC, controlOptions); addOriginatorAndCtlNumOptions((ModelNode*) newINC, controlOptions);
@ -764,7 +764,7 @@ CDC_INC_create(const char* dataObjectName, ModelNode* parent, uint32_t options,
DataObject* DataObject*
CDC_ENC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions) CDC_ENC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions)
{ {
DataObject* newENC = DataObject_create(dataObjectName, parent, 0); DataObject* newENC = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
addOriginatorAndCtlNumOptions((ModelNode*) newENC, controlOptions); addOriginatorAndCtlNumOptions((ModelNode*) newENC, controlOptions);
@ -791,7 +791,7 @@ CDC_ENC_create(const char* dataObjectName, ModelNode* parent, uint32_t options,
DataObject* DataObject*
CDC_BSC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions, bool hasTransientIndicator) CDC_BSC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions, bool hasTransientIndicator)
{ {
DataObject* newBSC = DataObject_create(dataObjectName, parent, 0); DataObject* newBSC = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
addOriginatorAndCtlNumOptions((ModelNode*) newBSC, controlOptions); addOriginatorAndCtlNumOptions((ModelNode*) newBSC, controlOptions);
@ -821,7 +821,7 @@ CDC_BSC_create(const char* dataObjectName, ModelNode* parent, uint32_t options,
DataObject* DataObject*
CDC_ISC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions, bool hasTransientIndicator) CDC_ISC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions, bool hasTransientIndicator)
{ {
DataObject* newISC = DataObject_create(dataObjectName, parent, 0); DataObject* newISC = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
addOriginatorAndCtlNumOptions((ModelNode*) newISC, controlOptions); addOriginatorAndCtlNumOptions((ModelNode*) newISC, controlOptions);
@ -855,7 +855,7 @@ CDC_ISC_create(const char* dataObjectName, ModelNode* parent, uint32_t options,
DataObject* DataObject*
CDC_BAC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions, bool isIntegerNotFloat) CDC_BAC_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions, bool isIntegerNotFloat)
{ {
DataObject* newBAC = DataObject_create(dataObjectName, parent, 0); DataObject* newBAC = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
addControlStatusAttributesForAnalogControl(newBAC, controlOptions); addControlStatusAttributesForAnalogControl(newBAC, controlOptions);
@ -899,7 +899,7 @@ CDC_BAC_create(const char* dataObjectName, ModelNode* parent, uint32_t options,
DataObject* DataObject*
CDC_LPL_create(const char* dataObjectName, ModelNode* parent, uint32_t options) CDC_LPL_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
{ {
DataObject* newLPL = DataObject_create(dataObjectName, parent, 0); DataObject* newLPL = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
DataAttribute_create("vendor", (ModelNode*) newLPL, IEC61850_VISIBLE_STRING_255, IEC61850_FC_DC, 0, 0, 0); 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); DataAttribute_create("swRev", (ModelNode*) newLPL, IEC61850_VISIBLE_STRING_255, IEC61850_FC_DC, 0, 0, 0);
@ -921,7 +921,7 @@ CDC_LPL_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
DataObject* DataObject*
CDC_DPL_create(const char* dataObjectName, ModelNode* parent, uint32_t options) CDC_DPL_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
{ {
DataObject* newDPL = DataObject_create(dataObjectName, parent, 0); DataObject* newDPL = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
DataAttribute_create("vendor", (ModelNode*) newDPL, IEC61850_VISIBLE_STRING_255, IEC61850_FC_DC, 0, 0, 0); DataAttribute_create("vendor", (ModelNode*) newDPL, IEC61850_VISIBLE_STRING_255, IEC61850_FC_DC, 0, 0, 0);
@ -949,7 +949,7 @@ CDC_DPL_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
DataObject* DataObject*
CDC_ACD_create(const char* dataObjectName, ModelNode* parent, uint32_t options) CDC_ACD_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
{ {
DataObject* newACD = DataObject_create(dataObjectName, parent, 0); DataObject* newACD = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
DataAttribute_create("general", (ModelNode*) newACD, IEC61850_BOOLEAN, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0); DataAttribute_create("general", (ModelNode*) newACD, IEC61850_BOOLEAN, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0);
DataAttribute_create("dirGeneral", (ModelNode*) newACD, IEC61850_ENUMERATED, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0); DataAttribute_create("dirGeneral", (ModelNode*) newACD, IEC61850_ENUMERATED, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0);
@ -984,7 +984,7 @@ CDC_ACD_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
DataObject* DataObject*
CDC_ACT_create(const char* dataObjectName, ModelNode* parent, uint32_t options) CDC_ACT_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
{ {
DataObject* newACT = DataObject_create(dataObjectName, parent, 0); DataObject* newACT = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
DataAttribute_create("general", (ModelNode*) newACT, IEC61850_BOOLEAN, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0); DataAttribute_create("general", (ModelNode*) newACT, IEC61850_BOOLEAN, IEC61850_FC_ST, TRG_OPT_DATA_CHANGED, 0, 0);
@ -1010,7 +1010,7 @@ CDC_ACT_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
DataObject* DataObject*
CDC_WYE_create(const char* dataObjectName, ModelNode* parent, uint32_t options) CDC_WYE_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
{ {
DataObject* newWYE = DataObject_create(dataObjectName, parent, 0); DataObject* newWYE = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
/* TODO check if some options should be masked */ /* TODO check if some options should be masked */
/* TODO take care for GC_1 */ /* TODO take care for GC_1 */
@ -1033,7 +1033,7 @@ CDC_WYE_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
DataObject* DataObject*
CDC_DEL_create(const char* dataObjectName, ModelNode* parent, uint32_t options) CDC_DEL_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
{ {
DataObject* newDEL = DataObject_create(dataObjectName, parent, 0); DataObject* newDEL = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
/* TODO check if some options should be masked */ /* TODO check if some options should be masked */
CDC_CMV_create("phsAB", (ModelNode*) newDEL, options); CDC_CMV_create("phsAB", (ModelNode*) newDEL, options);
@ -1052,7 +1052,7 @@ CDC_DEL_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
DataObject* DataObject*
CDC_SPG_create(const char* dataObjectName, ModelNode* parent, uint32_t options) CDC_SPG_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
{ {
DataObject* newSPG = DataObject_create(dataObjectName, parent, 0); DataObject* newSPG = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
DataAttribute_create("setVal", (ModelNode*) newSPG, IEC61850_BOOLEAN, IEC61850_FC_SP, TRG_OPT_DATA_CHANGED, 0, 0); DataAttribute_create("setVal", (ModelNode*) newSPG, IEC61850_BOOLEAN, IEC61850_FC_SP, TRG_OPT_DATA_CHANGED, 0, 0);
@ -1064,7 +1064,7 @@ CDC_SPG_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
DataObject* DataObject*
CDC_VSG_create(const char* dataObjectName, ModelNode* parent, uint32_t options) CDC_VSG_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
{ {
DataObject* newSPG = DataObject_create(dataObjectName, parent, 0); DataObject* newSPG = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
DataAttribute_create("setVal", (ModelNode*) newSPG, IEC61850_VISIBLE_STRING_255, IEC61850_FC_SP, TRG_OPT_DATA_CHANGED, 0, 0); DataAttribute_create("setVal", (ModelNode*) newSPG, IEC61850_VISIBLE_STRING_255, IEC61850_FC_SP, TRG_OPT_DATA_CHANGED, 0, 0);
@ -1077,7 +1077,7 @@ CDC_VSG_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
DataObject* DataObject*
CDC_ENG_create(const char* dataObjectName, ModelNode* parent, uint32_t options) CDC_ENG_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
{ {
DataObject* newENG = DataObject_create(dataObjectName, parent, 0); DataObject* newENG = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
DataAttribute_create("setVal", (ModelNode*) newENG, IEC61850_ENUMERATED, IEC61850_FC_SP, TRG_OPT_DATA_CHANGED, 0, 0); DataAttribute_create("setVal", (ModelNode*) newENG, IEC61850_ENUMERATED, IEC61850_FC_SP, TRG_OPT_DATA_CHANGED, 0, 0);
@ -1089,7 +1089,7 @@ CDC_ENG_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
DataObject* DataObject*
CDC_ING_create(const char* dataObjectName, ModelNode* parent, uint32_t options) CDC_ING_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
{ {
DataObject* newING = DataObject_create(dataObjectName, parent, 0); DataObject* newING = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
DataAttribute_create("setVal", (ModelNode*) newING, IEC61850_INT32, IEC61850_FC_SP, TRG_OPT_DATA_CHANGED, 0, 0); DataAttribute_create("setVal", (ModelNode*) newING, IEC61850_INT32, IEC61850_FC_SP, TRG_OPT_DATA_CHANGED, 0, 0);
@ -1114,7 +1114,7 @@ CDC_ING_create(const char* dataObjectName, ModelNode* parent, uint32_t options)
DataObject* DataObject*
CDC_ASG_create(const char* dataObjectName, ModelNode* parent, uint32_t options, bool isIntegerNotFloat) CDC_ASG_create(const char* dataObjectName, ModelNode* parent, uint32_t options, bool isIntegerNotFloat)
{ {
DataObject* newASG = DataObject_create(dataObjectName, parent, 0); DataObject* newASG = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
CAC_AnalogueValue_create("setMag", (ModelNode*) newASG, IEC61850_FC_SP, TRG_OPT_DATA_CHANGED, isIntegerNotFloat); CAC_AnalogueValue_create("setMag", (ModelNode*) newASG, IEC61850_FC_SP, TRG_OPT_DATA_CHANGED, isIntegerNotFloat);
@ -1145,7 +1145,7 @@ CDC_ASG_create(const char* dataObjectName, ModelNode* parent, uint32_t options,
DataObject* DataObject*
CDC_SPV_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions, uint32_t wpOptions, bool hasChaManRs) CDC_SPV_create(const char* dataObjectName, ModelNode* parent, uint32_t options, uint32_t controlOptions, uint32_t wpOptions, bool hasChaManRs)
{ {
DataObject* newSPV = DataObject_create(dataObjectName, parent, 0); DataObject* newSPV = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
if (hasChaManRs) if (hasChaManRs)
CDC_SPC_create("chaManRs", (ModelNode*) newSPV, 0, CDC_CTL_MODEL_DIRECT_NORMAL); CDC_SPC_create("chaManRs", (ModelNode*) newSPV, 0, CDC_CTL_MODEL_DIRECT_NORMAL);
@ -1196,7 +1196,7 @@ CDC_STV_create(const char* dataObjectName, ModelNode* parent,
(void)controlOptions; /* TODO implement */ (void)controlOptions; /* TODO implement */
(void)wpOptions; /* TODO implement */ (void)wpOptions; /* TODO implement */
DataObject* newSTV = DataObject_create(dataObjectName, parent, 0); DataObject* newSTV = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
CDC_INS_create("actSt", (ModelNode*) newSTV, 0); CDC_INS_create("actSt", (ModelNode*) newSTV, 0);
@ -1218,7 +1218,7 @@ CDC_ALM_create(const char* dataObjectName, ModelNode* parent,
(void)controlOptions; /* TODO implement */ (void)controlOptions; /* TODO implement */
(void)wpOptions; /* TODO implement */ (void)wpOptions; /* TODO implement */
DataObject* newALM = DataObject_create(dataObjectName, parent, 0); DataObject* newALM = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
CDC_SPC_create("almAck", (ModelNode*) newALM, 0, CDC_CTL_MODEL_DIRECT_NORMAL | CDC_CTL_OPTION_ORIGIN); CDC_SPC_create("almAck", (ModelNode*) newALM, 0, CDC_CTL_MODEL_DIRECT_NORMAL | CDC_CTL_OPTION_ORIGIN);
@ -1244,7 +1244,7 @@ CDC_CMD_create(const char* dataObjectName, ModelNode* parent,
(void)hasCmTm; /* TODO implement */ (void)hasCmTm; /* TODO implement */
(void)hasCmCt; /* TODO implement */ (void)hasCmCt; /* TODO implement */
DataObject* newCMD = DataObject_create(dataObjectName, parent, 0); DataObject* newCMD = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
CDC_INC_create("actSt", (ModelNode*) newCMD, 0, controlOptions); CDC_INC_create("actSt", (ModelNode*) newCMD, 0, controlOptions);
@ -1272,7 +1272,7 @@ CDC_CTE_create(const char* dataObjectName, ModelNode* parent,
{ {
(void)controlOptions; /* TODO implement */ (void)controlOptions; /* TODO implement */
DataObject* newCTE = DataObject_create(dataObjectName, parent, 0); DataObject* newCTE = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
CDC_SPC_create("manRs", (ModelNode*) newCTE, 0, CDC_CTL_MODEL_DIRECT_NORMAL | CDC_CTL_OPTION_ORIGIN); CDC_SPC_create("manRs", (ModelNode*) newCTE, 0, CDC_CTL_MODEL_DIRECT_NORMAL | CDC_CTL_OPTION_ORIGIN);
@ -1313,7 +1313,7 @@ CDC_TMS_create(const char* dataObjectName, ModelNode* parent,
{ {
(void)controlOptions; /* TODO implement */ (void)controlOptions; /* TODO implement */
DataObject* newTMS = DataObject_create(dataObjectName, parent, 0); DataObject* newTMS = (dataObjectName == NULL) ? (DataObject*)parent : DataObject_create(dataObjectName, parent, 0);
CDC_SPC_create("manRs", (ModelNode*) newTMS, 0, CDC_CTL_MODEL_DIRECT_NORMAL | CDC_CTL_OPTION_ORIGIN); CDC_SPC_create("manRs", (ModelNode*) newTMS, 0, CDC_CTL_MODEL_DIRECT_NORMAL | CDC_CTL_OPTION_ORIGIN);
@ -1344,4 +1344,3 @@ CDC_TMS_create(const char* dataObjectName, ModelNode* parent,
return newTMS; return newTMS;
} }

@ -166,7 +166,6 @@ IedModel_addSettingGroupControlBlock(IedModel* self, SettingGroupControlBlock* s
} }
#endif /* (CONFIG_IEC61850_SETTING_GROUPS == 1) */ #endif /* (CONFIG_IEC61850_SETTING_GROUPS == 1) */
static void static void
IedModel_addGSEControlBlock(IedModel* self, GSEControlBlock* gcb) IedModel_addGSEControlBlock(IedModel* self, GSEControlBlock* gcb)
{ {
@ -175,13 +174,29 @@ IedModel_addGSEControlBlock(IedModel* self, GSEControlBlock* gcb)
else { else {
GSEControlBlock* lastGcb = self->gseCBs; GSEControlBlock* lastGcb = self->gseCBs;
while (lastGcb->sibling != NULL) while (lastGcb->sibling)
lastGcb = lastGcb->sibling; lastGcb = lastGcb->sibling;
lastGcb->sibling = gcb; lastGcb->sibling = gcb;
} }
} }
static void
IedModel_addSMVControlBlock(IedModel* self, SVControlBlock* smvcb)
{
if (self->svCBs == NULL) {
self->svCBs = smvcb;
}
else {
SVControlBlock* lastSvCB = self->svCBs;
while (lastSvCB->sibling)
lastSvCB = lastSvCB->sibling;
lastSvCB->sibling = smvcb;
}
}
LogicalDevice* LogicalDevice*
LogicalDevice_createEx(const char* inst, IedModel* parent, const char* ldName) LogicalDevice_createEx(const char* inst, IedModel* parent, const char* ldName)
{ {
@ -512,6 +527,14 @@ GSEControlBlock_create(const char* name, LogicalNode* parent, const char* appId,
return self; return self;
} }
static void
LogicalNode_addSMVControlBlock(LogicalNode* self, SVControlBlock* smvcb)
{
IedModel* model = (IedModel*) self->parent->parent;
IedModel_addSMVControlBlock(model, smvcb);
}
SVControlBlock* SVControlBlock*
SVControlBlock_create(const char* name, LogicalNode* parent, const char* svID, const char* dataSet, uint32_t confRev, uint8_t smpMod, SVControlBlock_create(const char* name, LogicalNode* parent, const char* svID, const char* dataSet, uint32_t confRev, uint8_t smpMod,
uint16_t smpRate, uint8_t optFlds, bool isUnicast) uint16_t smpRate, uint8_t optFlds, bool isUnicast)
@ -536,6 +559,12 @@ SVControlBlock_create(const char* name, LogicalNode* parent, const char* svID, c
self->optFlds = optFlds; self->optFlds = optFlds;
self->isUnicast = isUnicast; self->isUnicast = isUnicast;
self->dstAddress = NULL;
self->sibling = NULL;
if (parent)
LogicalNode_addSMVControlBlock(parent, self);
} }
return self; return self;

@ -147,7 +147,7 @@ parseInitResponseDetail(MmsConnection self, uint8_t* buffer, int bufPos, int max
int i; int i;
for (i = 0; i < 11; i++) for (i = 0; i < 11; i++)
self->parameters.servicesSupported[i] = buffer[bufPos + i]; self->parameters.servicesSupported[i] = buffer[bufPos + i + 1]; /* add 1 to skip padding */
} }
break; break;

@ -291,6 +291,25 @@ public class SclParser
SclParser sclParser = new SclParser(stream); SclParser sclParser = new SclParser(stream);
} }
public List<ConnectedAP> getConnectedAPs()
{
List<ConnectedAP> aps = new LinkedList<ConnectedAP>();
if (communication != null) {
List<SubNetwork> subNetworks = communication.getSubNetworks();
for (SubNetwork subNetwork : subNetworks) {
List<ConnectedAP> connectedAPs = subNetwork.getConnectedAPs();
for (ConnectedAP connectedAP : connectedAPs) {
aps.add(connectedAP);
}
}
}
return aps;
}
public ConnectedAP getConnectedAP(IED ied, String accessPointName) { public ConnectedAP getConnectedAP(IED ied, String accessPointName) {
communication = this.getCommunication(); communication = this.getCommunication();

@ -98,6 +98,18 @@ public class ConnectedAP {
return null; return null;
} }
public SMV lookupSMV(String logicalDeviceName, String name) {
for (SMV smv : this.getSmvs()) {
if (smv.getLdInst().equals(logicalDeviceName)) {
if (smv.getCbName().equals(name))
return smv;
}
}
return null;
}
public PhyComAddress lookupSMVAddress(String logicalDeviceName, String name) { public PhyComAddress lookupSMVAddress(String logicalDeviceName, String name) {
for (SMV smv : this.getSmvs()) { for (SMV smv : this.getSmvs()) {

@ -16,8 +16,7 @@ public class SampledValueControl {
private int nofASDU; private int nofASDU;
private boolean multicast = false; private boolean multicast = false;
private SmvOpts smvOpts; private SmvOpts smvOpts;
private SmpMod smpMod = SmpMod.SMP_PER_PERIOD;
public SampledValueControl(Node smvControlNode) throws SclParserException { public SampledValueControl(Node smvControlNode) throws SclParserException {
this.name = ParserUtils.parseAttribute(smvControlNode, "name"); this.name = ParserUtils.parseAttribute(smvControlNode, "name");
@ -49,9 +48,24 @@ public class SampledValueControl {
Node smvOptsNode = ParserUtils.getChildNodeWithTag(smvControlNode, "SmvOpts"); Node smvOptsNode = ParserUtils.getChildNodeWithTag(smvControlNode, "SmvOpts");
this.smvOpts = new SmvOpts(smvOptsNode); this.smvOpts = new SmvOpts(smvOptsNode);
}
String smpModString = ParserUtils.parseAttribute(smvControlNode, "smpMod");
if (smpModString != null) {
if (smpModString.equals("SmpPerPeriod")) {
smpMod = SmpMod.SMP_PER_PERIOD;
}
else if (smpModString.equals("SmpPerSec")) {
smpMod = SmpMod.SMP_PER_SECOND;
}
else if (smpModString.equals("SecPerSmp")) {
smpMod = SmpMod.SEC_PER_SMP;
}
else {
throw new SclParserException(smvControlNode, "Invalid smpMod value " + smpModString);
}
}
}
public String getName() { public String getName() {
return name; return name;
@ -89,4 +103,7 @@ public class SampledValueControl {
return smvOpts; return smvOpts;
} }
public SmpMod getSmpMod() {
return smpMod;
}
} }

@ -0,0 +1,56 @@
package com.libiec61850.scl.model;
/*
* Copyright 2023 Michael Zillgith
*
* This file is part of libIEC61850.
*
* libIEC61850 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* libIEC61850 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with libIEC61850. If not, see <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/
public enum SmpMod
{
SMP_PER_PERIOD(0),
SMP_PER_SECOND(1),
SEC_PER_SMP(2);
private int value;
private SmpMod(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public boolean compare(int i)
{
return (value == i);
}
public static SmpMod fromValue(int val)
{
SmpMod[] errors = SmpMod.values();
for (int i = 0; i < errors.length; i++) {
if (errors[i].compare(val))
return errors[i];
}
return SmpMod.SMP_PER_PERIOD;
}
}

@ -37,6 +37,7 @@ import com.libiec61850.scl.SclParserException;
import com.libiec61850.scl.communication.ConnectedAP; import com.libiec61850.scl.communication.ConnectedAP;
import com.libiec61850.scl.communication.GSE; import com.libiec61850.scl.communication.GSE;
import com.libiec61850.scl.communication.PhyComAddress; import com.libiec61850.scl.communication.PhyComAddress;
import com.libiec61850.scl.communication.SMV;
import com.libiec61850.scl.model.AccessPoint; import com.libiec61850.scl.model.AccessPoint;
import com.libiec61850.scl.model.DataAttribute; import com.libiec61850.scl.model.DataAttribute;
import com.libiec61850.scl.model.DataModelValue; import com.libiec61850.scl.model.DataModelValue;
@ -51,6 +52,7 @@ import com.libiec61850.scl.model.LogicalDevice;
import com.libiec61850.scl.model.LogicalNode; import com.libiec61850.scl.model.LogicalNode;
import com.libiec61850.scl.model.ReportControlBlock; import com.libiec61850.scl.model.ReportControlBlock;
import com.libiec61850.scl.model.ReportSettings; import com.libiec61850.scl.model.ReportSettings;
import com.libiec61850.scl.model.SampledValueControl;
import com.libiec61850.scl.model.Services; import com.libiec61850.scl.model.Services;
import com.libiec61850.scl.model.SettingControl; import com.libiec61850.scl.model.SettingControl;
@ -59,6 +61,7 @@ public class DynamicModelGenerator {
private ConnectedAP connectedAP; private ConnectedAP connectedAP;
private IED ied = null; private IED ied = null;
private boolean hasOwner = false; private boolean hasOwner = false;
private List<ConnectedAP> connectedAPs;
public DynamicModelGenerator(InputStream stream, String icdFile, PrintStream output, String iedName, String accessPointName) public DynamicModelGenerator(InputStream stream, String icdFile, PrintStream output, String iedName, String accessPointName)
throws SclParserException { throws SclParserException {
@ -95,6 +98,8 @@ public class DynamicModelGenerator {
this.connectedAP = sclParser.getConnectedAP(ied, accessPoint.getName()); this.connectedAP = sclParser.getConnectedAP(ied, accessPoint.getName());
this.connectedAPs = sclParser.getConnectedAPs();
List<LogicalDevice> logicalDevices = accessPoint.getServer().getLogicalDevices(); List<LogicalDevice> logicalDevices = accessPoint.getServer().getLogicalDevices();
output.println("MODEL(" + ied.getName() + "){"); output.println("MODEL(" + ied.getName() + "){");
@ -167,6 +172,64 @@ public class DynamicModelGenerator {
for (Log log : logicalNode.getLogs()) for (Log log : logicalNode.getLogs())
output.println("LOG(" + log.getName() + ");"); output.println("LOG(" + log.getName() + ");");
for (SampledValueControl svcb : logicalNode.getSampledValueControlBlocks()) {
LogicalDevice ld = logicalNode.getParentLogicalDevice();
SMV smv = null;
PhyComAddress smvAddress = null;
if (connectedAP != null) {
smv = connectedAP.lookupSMV(ld.getInst(), svcb.getName());
if (smv == null) {
for (ConnectedAP ap : connectedAPs) {
smv = ap.lookupSMV(ld.getInst(), svcb.getName());
if (smv != null)
break;
}
}
if (smv == null)
System.out.println("ConnectedAP not found for SMV");
if (smv != null)
smvAddress = smv.getAddress();
}
else
System.out.println("WARNING: IED \"" + ied.getName() + "\" has no connected access point!");
output.print("SMVC(");
output.print(svcb.getName() + " ");
output.print(svcb.getSmvID() + " ");
output.print(svcb.getDatSet() + " ");
output.print(svcb.getConfRev() + " ");
output.print(svcb.getSmpMod().getValue() + " ");
output.print(svcb.getSmpRate() + " ");
output.print(svcb.getSmvOpts().getIntValue() + " ");
output.print(svcb.isMulticast() ? "0" : "1");
output.print(")");
if (smvAddress != null) {
output.println("{");
output.print("PA(");
output.print(smvAddress.getVlanPriority() + " ");
output.print(smvAddress.getVlanId() + " ");
output.print(smvAddress.getAppId() + " ");
for (int i = 0; i < 6; i++)
output.printf("%02x", smvAddress.getMacAddress()[i]);
output.println(");");
output.println("}");
}
else {
output.println(";");
}
}
for (GSEControl gcb : logicalNode.getGSEControlBlocks()) { for (GSEControl gcb : logicalNode.getGSEControlBlocks()) {
LogicalDevice ld = logicalNode.getParentLogicalDevice(); LogicalDevice ld = logicalNode.getParentLogicalDevice();
@ -176,6 +239,18 @@ public class DynamicModelGenerator {
if (connectedAP != null) { if (connectedAP != null) {
gse = connectedAP.lookupGSE(ld.getInst(), gcb.getName()); gse = connectedAP.lookupGSE(ld.getInst(), gcb.getName());
if (gse == null) {
for (ConnectedAP ap : connectedAPs) {
gse = ap.lookupGSE(ld.getInst(), gcb.getName());
if (gse != null)
break;
}
}
if (gse == null)
System.out.println("ConnectedAP not found for GSE");
if (gse != null) if (gse != null)
gseAddress = gse.getAddress(); gseAddress = gse.getAddress();
} }

@ -1248,7 +1248,9 @@ public class StaticModelGenerator {
svString += svCB.getSmvOpts().getIntValue() + ", "; svString += svCB.getSmvOpts().getIntValue() + ", ";
svString += "0, " + svCB.getSmpRate() + ", "; svString += svCB.getSmpMod().getValue() + ", ";
svString += svCB.getSmpRate() + ", ";
svString += svCB.getConfRev() + ", "; svString += svCB.getConfRev() + ", ";

Loading…
Cancel
Save