diff --git a/config/stack_config.h b/config/stack_config.h
index 26207ee5..e6a12ed1 100644
--- a/config/stack_config.h
+++ b/config/stack_config.h
@@ -67,12 +67,14 @@
/* Ethernet interface ID for GOOSE and SV */
#define CONFIG_ETHERNET_INTERFACE_ID "eth0"
//#define CONFIG_ETHERNET_INTERFACE_ID "vboxnet0"
-//#define CONFIG_ETHERNET_INTERFACE_ID "eth-f"
//#define CONFIG_ETHERNET_INTERFACE_ID "en0" // OS X uses enX in place of ethX as ethernet NIC names.
/* Set to 1 to include GOOSE support in the build. Otherwise set to 0 */
#define CONFIG_INCLUDE_GOOSE_SUPPORT 1
+/* Set to 1 to include Sampled Values support in the build. Otherwise set to 0 */
+#define CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT 1
+
#ifdef _WIN32
/* GOOSE will be disabled for Windows if ethernet support (winpcap) is not available */
diff --git a/config/stack_config.h.cmake b/config/stack_config.h.cmake
index 011cbf82..36b7ff3e 100644
--- a/config/stack_config.h.cmake
+++ b/config/stack_config.h.cmake
@@ -71,6 +71,9 @@
/* Set to 1 to include GOOSE support in the build. Otherwise set to 0 */
#cmakedefine01 CONFIG_INCLUDE_GOOSE_SUPPORT
+/* Set to 1 to include Sampled Values support in the build. Otherwise set to 0 */
+#cmakedefine01 CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT
+
#ifdef _WIN32
/* GOOSE will be disabled for Windows if ethernet support (winpcap) is not available */
diff --git a/dotnet/reporting/Settings.cs b/dotnet/reporting/Settings.cs
new file mode 100644
index 00000000..99fcfeb5
--- /dev/null
+++ b/dotnet/reporting/Settings.cs
@@ -0,0 +1,28 @@
+namespace reporting.Properties {
+
+
+ // This class allows you to handle specific events on the settings class:
+ // The SettingChanging event is raised before a setting's value is changed.
+ // The PropertyChanged event is raised after a setting's value is changed.
+ // The SettingsLoaded event is raised after the setting values are loaded.
+ // The SettingsSaving event is raised before the setting values are saved.
+ internal sealed partial class Settings {
+
+ public Settings() {
+ // // To add event handlers for saving and changing settings, uncomment the lines below:
+ //
+ // this.SettingChanging += this.SettingChangingEventHandler;
+ //
+ // this.SettingsSaving += this.SettingsSavingEventHandler;
+ //
+ }
+
+ private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) {
+ // Add code to handle the SettingChangingEvent event here.
+ }
+
+ private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) {
+ // Add code to handle the SettingsSaving event here.
+ }
+ }
+}
diff --git a/src/common/inc/libiec61850_platform_includes.h b/src/common/inc/libiec61850_platform_includes.h
index 9a9f9097..f4de6b94 100644
--- a/src/common/inc/libiec61850_platform_includes.h
+++ b/src/common/inc/libiec61850_platform_includes.h
@@ -15,7 +15,7 @@
#include "platform_endian.h"
-#define LIBIEC61850_VERSION "0.8.7"
+#define LIBIEC61850_VERSION "0.9.0"
#ifndef CONFIG_DEFAULT_MMS_VENDOR_NAME
#define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com"
@@ -29,6 +29,10 @@
#define CONFIG_DEFAULT_MMS_REVISION LIBIEC61850_VERSION
#endif
+#ifndef CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT
+#define CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT 0
+#endif
+
#if (DEBUG != 1)
#define NDEBUG 1
#endif
diff --git a/src/iec61850/inc/iec61850_dynamic_model.h b/src/iec61850/inc/iec61850_dynamic_model.h
index 77725334..967c764f 100644
--- a/src/iec61850/inc/iec61850_dynamic_model.h
+++ b/src/iec61850/inc/iec61850_dynamic_model.h
@@ -183,7 +183,7 @@ SettingGroupControlBlock_create(LogicalNode* parent, uint8_t actSG, uint8_t numO
* \param parent the parent LN
* \param appId the application ID of the GoCB
* \param dataSet the data set reference to be used by the GoCB
- * \param confRef the configuration revision
+ * \param confRev the configuration revision
* \param fixedOffs indicates if GOOSE publisher shall use fixed offsets (NOT YET SUPPORTED)
* \param minTime minimum GOOSE retransmission time (-1 if not specified - uses stack default then)
* \param maxTime GOOSE retransmission time in stable state (-1 if not specified - uses stack default then)
@@ -191,15 +191,40 @@ SettingGroupControlBlock_create(LogicalNode* parent, uint8_t actSG, uint8_t numO
* \return the new GoCB instance
*/
GSEControlBlock*
-GSEControlBlock_create(const char* name, LogicalNode* parent, char* appId, char* dataSet, uint32_t confRef,
+GSEControlBlock_create(const char* name, LogicalNode* parent, char* appId, char* dataSet, uint32_t confRev,
bool fixedOffs, int minTime, int maxTime);
/**
- * \brief create a PhyComAddress object and add it to a GoCB
+ * \brief create a new Multicast/Unicast Sampled Value (SV) control block (SvCB)
+ *
+ * Create a new Sampled Value control block (SvCB) and add it to the given logical node (LN)
+ *
+ * \param name name of the SvCB relative to the parent LN
+ * \param parent the parent LN
+ * \param svID the application ID of the SvCB
+ * \param dataSet the data set reference to be used by the SVCB
+ * \param confRev the configuration revision
+ * \param smpMod the sampling mode used
+ * \param smpRate the sampling rate used
+ * \param optFlds the optional element configuration
+ *
+ * \return the new SvCB instance
+ */
+SVControlBlock*
+SVControlBlock_create(const char* name, LogicalNode* parent, char* svID, char* dataSet, uint32_t confRev, uint8_t smpMod,
+ uint16_t smpRate, uint8_t optFlds, bool isUnicast);
+
+void
+SVControlBlock_addPhyComAddress(SVControlBlock* self, PhyComAddress* phyComAddress);
+
+void
+GSEControlBlock_addPhyComAddress(GSEControlBlock* self, PhyComAddress* phyComAddress);
+
+/**
+ * \brief create a PhyComAddress object
*
- * A PhyComAddress object contains all required addressing informations for a GOOSE publisher.
+ * A PhyComAddress object contains all required addressing information for a GOOSE publisher.
*
- * \param parent the parent GSEControlBlock object
* \param vlanPriority the priority field of the VLAN tag
* \param vlanId the ID field of the VLAN tag
* \param appId the application identifier
@@ -208,7 +233,7 @@ GSEControlBlock_create(const char* name, LogicalNode* parent, char* appId, char*
* \return the new PhyComAddress object
*/
PhyComAddress*
-PhyComAddress_create(GSEControlBlock* parent, uint8_t vlanPriority, uint16_t vlanId, uint16_t appId, uint8_t dstAddress[]);
+PhyComAddress_create(uint8_t vlanPriority, uint16_t vlanId, uint16_t appId, uint8_t dstAddress[]);
/**
* \brief create a new data set
diff --git a/src/iec61850/inc/iec61850_model.h b/src/iec61850/inc/iec61850_model.h
index a94204d7..258c9b10 100644
--- a/src/iec61850/inc/iec61850_model.h
+++ b/src/iec61850/inc/iec61850_model.h
@@ -80,6 +80,8 @@ typedef struct sSettingGroupControlBlock SettingGroupControlBlock;
typedef struct sGSEControlBlock GSEControlBlock;
+typedef struct sSVControlBlock SVControlBlock;
+
typedef enum {
IEC61850_BOOLEAN = 0,/* int */
@@ -162,6 +164,7 @@ struct sIedModel {
DataSet* dataSets;
ReportControlBlock* rcbs;
GSEControlBlock* gseCBs;
+ SVControlBlock* svCBs;
SettingGroupControlBlock* sgcbs;
void (*initializer) (void);
};
@@ -279,7 +282,7 @@ struct sGSEControlBlock {
char* name;
char* appId;
char* dataSetName; /* pre loaded with relative name in logical node */
- uint32_t confRef; /* ConfRef - configuration revision */
+ uint32_t confRev; /* ConfRev - configuration revision */
bool fixedOffs; /* fixed offsets */
PhyComAddress* address; /* GSE communication parameters */
int minTime; /* optional minTime parameter --> -1 if not present */
@@ -287,6 +290,29 @@ struct sGSEControlBlock {
GSEControlBlock* sibling; /* next control block in list or NULL if this is the last entry */
};
+struct sSVControlBlock {
+ LogicalNode* parent;
+ char* name;
+
+ char* svId; /* MsvUD/UsvID */
+ char* dataSetName; /* pre loaded with relative name in logical node */
+
+ uint8_t optFlds;
+
+ uint8_t smpMod;
+ uint16_t smpRate;
+
+ uint32_t confRev; /* ConfRev - configuration revision */
+
+ PhyComAddress* dstAddress; /* SV communication parameters */
+
+ bool isUnicast;
+
+ int noASDU;
+
+ SVControlBlock* sibling; /* next control block in list or NULL if this is the last entry */
+};
+
/**
* \brief get the number of direct children of a model node
*
diff --git a/src/iec61850/inc_private/mms_mapping_internal.h b/src/iec61850/inc_private/mms_mapping_internal.h
index a23fe8e9..ef09bb24 100644
--- a/src/iec61850/inc_private/mms_mapping_internal.h
+++ b/src/iec61850/inc_private/mms_mapping_internal.h
@@ -40,6 +40,11 @@ struct sMmsMapping {
const char* gooseInterfaceId;
#endif
+#if (CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT == 1)
+ LinkedList svControls;
+ const char* svInterfaceId;
+#endif
+
LinkedList controlObjects;
LinkedList observedObjects;
LinkedList attributeAccessHandlers;
diff --git a/src/iec61850/inc_private/mms_sv.h b/src/iec61850/inc_private/mms_sv.h
new file mode 100644
index 00000000..4af77fe5
--- /dev/null
+++ b/src/iec61850/inc_private/mms_sv.h
@@ -0,0 +1,31 @@
+/*
+ * mms_sv.h
+ *
+ * Copyright 2015 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 .
+ *
+ * See COPYING file for the complete license text.
+ */
+
+#ifndef LIBIEC61850_SRC_IEC61850_INC_PRIVATE_MMS_SV_H_
+#define LIBIEC61850_SRC_IEC61850_INC_PRIVATE_MMS_SV_H_
+
+MmsVariableSpecification*
+LIBIEC61850_SV_createSVControlBlocks(MmsMapping* self, MmsDomain* domain,
+ LogicalNode* logicalNode, int svCount, bool unicast);
+
+#endif /* LIBIEC61850_SRC_IEC61850_INC_PRIVATE_MMS_SV_H_ */
diff --git a/src/iec61850/server/mms_mapping/mms_goose.c b/src/iec61850/server/mms_mapping/mms_goose.c
index 85428f30..4df30eba 100644
--- a/src/iec61850/server/mms_mapping/mms_goose.c
+++ b/src/iec61850/server/mms_mapping/mms_goose.c
@@ -550,7 +550,7 @@ GOOSE_createGOOSEControlBlocks(MmsMapping* self, MmsDomain* domain,
MmsValue* confRef = MmsValue_getElement(gseValues, 3);
- MmsValue_setUint32(confRef, gooseControlBlock->confRef);
+ MmsValue_setUint32(confRef, gooseControlBlock->confRev);
mmsGCB->dataSet = NULL;
@@ -587,5 +587,5 @@ GOOSE_createGOOSEControlBlocks(MmsMapping* self, MmsDomain* domain,
return namedVariable;
}
-#endif
+#endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */
diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c
index 40064194..0a488866 100644
--- a/src/iec61850/server/mms_mapping/mms_mapping.c
+++ b/src/iec61850/server/mms_mapping/mms_mapping.c
@@ -766,9 +766,8 @@ countGSEControlBlocksForLogicalNode(MmsMapping* self, LogicalNode* logicalNode)
GSEControlBlock* gcb = self->model->gseCBs;
while (gcb != NULL) {
- if (gcb->parent == logicalNode) {
+ if (gcb->parent == logicalNode)
gseCount++;
- }
gcb = gcb->sibling;
}
@@ -778,6 +777,27 @@ countGSEControlBlocksForLogicalNode(MmsMapping* self, LogicalNode* logicalNode)
#endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */
+#if (CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT == 1)
+
+static int
+countSVControlBlocksForLogicalNode(MmsMapping* self, LogicalNode* logicalNode, bool unicast)
+{
+ int svCount = 0;
+
+ SVControlBlock* svCb = self->model->svCBs;
+
+ while (svCb != NULL) {
+ if ((svCb->parent == logicalNode) && (svCb->isUnicast == unicast))
+ svCount++;
+
+ svCb = svCb->sibling;
+ }
+
+ return svCount;
+}
+
+#endif /* (CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT == 1) */
+
static SettingGroupControlBlock*
checkForSgcb(MmsMapping* self, LogicalNode* logicalNode)
{
@@ -862,6 +882,28 @@ createNamedVariableFromLogicalNode(MmsMapping* self, MmsDomain* domain,
#endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */
+#if (CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT == 1)
+
+ int msvcbCount = countSVControlBlocksForLogicalNode(self, logicalNode, false);
+
+ if (msvcbCount > 0) {
+ if (DEBUG_IED_SERVER)
+ printf(" and %i MSV control blocks\n", msvcbCount);
+
+ componentCount++;
+ }
+
+ int usvcbCount = countSVControlBlocksForLogicalNode(self, logicalNode, true);
+
+ if (usvcbCount > 0) {
+ if (DEBUG_IED_SERVER)
+ printf(" and %i USV control blocks\n", usvcbCount);
+
+ componentCount++;
+ }
+
+#endif /* (CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT == 1) */
+
namedVariable->typeSpec.structure.elements = (MmsVariableSpecification**) GLOBAL_CALLOC(componentCount,
sizeof(MmsVariableSpecification*));
@@ -961,6 +1003,24 @@ createNamedVariableFromLogicalNode(MmsMapping* self, MmsDomain* domain,
currentComponent++;
}
+#if (CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT == 1)
+
+ /* Add MS and US named variables */
+ if (msvcbCount > 0) {
+ namedVariable->typeSpec.structure.elements[currentComponent] =
+ LIBIEC61850_SV_creatSVControlBlocks(self, domain, logicalNode, msvcbCount, false);
+
+ currentComponent++;
+ }
+
+ if (usvcbCount > 0) {
+ namedVariable->typeSpec.structure.elements[currentComponent] =
+ LIBIEC61850_SV_creatSVControlBlocks(self, domain, logicalNode, msvcbCount, true);
+
+ currentComponent++;
+ }
+#endif
+
if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_EX)) {
namedVariable->typeSpec.structure.elements[currentComponent] =
createFCNamedVariable(logicalNode, IEC61850_FC_EX);
@@ -1138,6 +1198,11 @@ MmsMapping_create(IedModel* model)
self->gooseInterfaceId = NULL;
#endif
+#if (CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT == 1)
+ self->svControls = LinkedList_create();
+ self->svInterfaceId = NULL;
+#endif
+
#if (CONFIG_IEC61850_CONTROL_SERVICE == 1)
self->controlObjects = LinkedList_create();
#endif
@@ -1177,6 +1242,10 @@ MmsMapping_destroy(MmsMapping* self)
LinkedList_destroyDeep(self->gseControls, (LinkedListValueDeleteFunction) MmsGooseControlBlock_destroy);
#endif
+#if (CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT == 1)
+ LinkedList_destroyDeep(self->svControls, (LinkedListValueDeleteFunction) MmsSvControlBlock_destroy);
+#endif
+
#if (CONFIG_IEC61850_CONTROL_SERVICE == 1)
LinkedList_destroyDeep(self->controlObjects, (LinkedListValueDeleteFunction) ControlObject_destroy);
#endif
diff --git a/src/iec61850/server/mms_mapping/mms_sv.c b/src/iec61850/server/mms_mapping/mms_sv.c
new file mode 100644
index 00000000..56e8674b
--- /dev/null
+++ b/src/iec61850/server/mms_mapping/mms_sv.c
@@ -0,0 +1,251 @@
+/*
+ * mms_sv.c
+ *
+ * Copyright 2015 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 .
+ *
+ * See COPYING file for the complete license text.
+ */
+
+#include "stack_config.h"
+
+#if (CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT == 1)
+
+#include "libiec61850_platform_includes.h"
+#include "mms_mapping.h"
+#include "linked_list.h"
+#include "array_list.h"
+
+#include "mms_mapping_internal.h"
+
+
+static GSEControlBlock*
+getSVCBForLogicalNodeWithIndex(MmsMapping* self, LogicalNode* logicalNode, int index, bool isUnicast)
+{
+ int svCount = 0;
+
+ SVControlBlock* svcb = self->model->svCBs;
+
+ /* Iterate list of SvCBs */
+ while (svcb != NULL ) {
+ if ((svcb->parent == logicalNode) && (svcb->isUnicast == isUnicast)) {
+ if (svCount == index)
+ return svcb;
+
+ svCount++;
+ }
+
+ svcb = svcb->sibling;
+ }
+
+ return NULL ;
+}
+
+
+static MmsVariableSpecification*
+createSVControlBlockMmsStructure(char* gcbName, bool isUnicast)
+{
+ MmsVariableSpecification* gcb = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification));
+ gcb->name = copyString(gcbName);
+ gcb->type = MMS_STRUCTURE;
+
+ int elementCount;
+
+ if (isUnicast)
+ elementCount = 10;
+ else
+ elementCount = 9;
+
+ gcb->typeSpec.structure.elementCount = elementCount;
+ gcb->typeSpec.structure.elements = (MmsVariableSpecification**)
+ GLOBAL_CALLOC(elementCount, sizeof(MmsVariableSpecification*));
+
+ int currentElement = 0;
+
+ MmsVariableSpecification* namedVariable;
+
+ namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification));
+ namedVariable->name = copyString("SvEna");
+ namedVariable->type = MMS_BOOLEAN;
+
+ gcb->typeSpec.structure.elements[currentElement++] = namedVariable;
+
+ if (isUnicast) {
+ namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification));
+ namedVariable->name = copyString("Resv");
+ namedVariable->type = MMS_BOOLEAN;
+ }
+
+ namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification));
+ if (isUnicast)
+ namedVariable->name = copyString("UsvID");
+ else
+ namedVariable->name = copyString("MsvID");
+ namedVariable->typeSpec.visibleString = -129;
+ namedVariable->type = MMS_VISIBLE_STRING;
+
+ gcb->typeSpec.structure.elements[currentElement++] = namedVariable;
+
+ namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification));
+ namedVariable->name = copyString("DatSet");
+ namedVariable->typeSpec.visibleString = -129;
+ namedVariable->type = MMS_VISIBLE_STRING;
+
+ gcb->typeSpec.structure.elements[currentElement++] = namedVariable;
+
+ namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification));
+ namedVariable->name = copyString("ConfRev");
+ namedVariable->type = MMS_INTEGER;
+ namedVariable->typeSpec.integer = 32;
+
+ gcb->typeSpec.structure.elements[currentElement++] = namedVariable;
+
+ namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification));
+ namedVariable->name = copyString("SmpRate");
+ namedVariable->type = MMS_INTEGER;
+ namedVariable->typeSpec.unsignedInteger = 32;
+
+ gcb->typeSpec.structure.elements[currentElement++] = namedVariable;
+
+ namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification));
+ namedVariable->name = copyString("OptFlds");
+ namedVariable->type = MMS_BIT_STRING;
+ namedVariable->typeSpec.bitString = 5;
+
+ gcb->typeSpec.structure.elements[currentElement++] = namedVariable;
+
+ namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification));
+ namedVariable->name = copyString("DstAddress");
+ MmsMapping_createPhyComAddrStructure(namedVariable);
+
+ gcb->typeSpec.structure.elements[currentElement++] = namedVariable;
+
+ namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification));
+ namedVariable->name = copyString("noASDU");
+ namedVariable->type = MMS_INTEGER;
+ namedVariable->typeSpec.integer = 32;
+
+ gcb->typeSpec.structure.elements[currentElement++] = namedVariable;
+
+ return gcb;
+}
+
+
+
+MmsVariableSpecification*
+LIBIEC61850_SV_createSVControlBlocks(MmsMapping* self, MmsDomain* domain,
+ LogicalNode* logicalNode, int svCount, bool unicast)
+{
+ MmsVariableSpecification* namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1,
+ sizeof(MmsVariableSpecification));
+
+ if (unicast)
+ namedVariable->name = copyString("US");
+ else
+ namedVariable->name = copyString("MS");
+
+ namedVariable->type = MMS_STRUCTURE;
+
+ namedVariable->typeSpec.structure.elementCount = svCount;
+ namedVariable->typeSpec.structure.elements = (MmsVariableSpecification**) GLOBAL_CALLOC(svCount,
+ sizeof(MmsVariableSpecification*));
+
+ int currentSVCB = 0;
+
+ while (currentSVCB < svCount) {
+ SVControlBlock* svControlBlock = getSVCBForLogicalNodeWithIndex(
+ self, logicalNode, currentSVCB, unicast);
+
+ MmsVariableSpecification* svTypeSpec = createSVControlBlockMmsStructure(svControlBlock->name, unicast);
+
+ MmsValue* svValues = MmsValue_newStructure(svTypeSpec);
+
+ namedVariable->typeSpec.structure.elements[currentSVCB] = svTypeSpec;
+
+ int currentIndex;
+
+ if (unicast)
+ currentIndex = 2;
+ else
+ currentIndex = 1;
+
+ /* SvID */
+ MmsValue* svID = MmsValue_getElement(svValues, currentIndex++);
+ MmsValue_setVisibleString(svID, svControlBlock->svId);
+
+ /* DatSet */
+ MmsValue* dataSetRef = MmsValue_getElement(svValues, currentIndex++);
+ MmsValue_setVisibleString(dataSetRef, svControlBlock->dataSetName);
+
+ /* ConfRev */
+ MmsValue* confRev = MmsValue_getElement(svValues, currentIndex++);
+ MmsValue_setInt32(confRev, svControlBlock->confRev);
+
+ /* SmpRate */
+ MmsValue* smpRate = MmsValue_getElement(svValues, currentIndex++);
+ MmsValue_setInt32(smpRate, svControlBlock->smpRate);
+
+ /* OptFlds */
+ MmsValue* optFlds = MmsValue_getElement(svValues, currentIndex++);
+ MmsValue_setBitStringFromInteger(optFlds, svControlBlock->optFlds);
+
+ /* SmpMod */
+ MmsValue* smpMod = MmsValue_getElement(svValues, currentIndex++);
+ MmsValue_setInt32(smpRate, svControlBlock->smpMod);
+
+ /* Set communication parameters - DstAddress */
+ uint8_t priority = CONFIG_GOOSE_DEFAULT_PRIORITY;
+ uint8_t dstAddr[] = CONFIG_GOOSE_DEFAULT_DST_ADDRESS;
+ uint16_t vid = CONFIG_GOOSE_DEFAULT_VLAN_ID;
+ uint16_t appId = CONFIG_GOOSE_DEFAULT_APPID;
+
+ if (svControlBlock->dstAddress != NULL) {
+ priority = svControlBlock->dstAddress->vlanPriority;
+ vid = svControlBlock->dstAddress->vlanId;
+ appId = svControlBlock->dstAddress->appId;
+
+ int i;
+ for (i = 0; i < 6; i++) {
+ dstAddr[i] = svControlBlock->dstAddress->dstAddress[i];
+ }
+ }
+
+ MmsValue* dstAddress = MmsValue_getElement(svValues, currentIndex++);
+
+ MmsValue* addr = MmsValue_getElement(dstAddress, 0);
+ MmsValue_setOctetString(addr, dstAddr, 6);
+
+ MmsValue* prio = MmsValue_getElement(dstAddress, 1);
+ MmsValue_setUint8(prio, priority);
+
+ MmsValue* vlanId = MmsValue_getElement(dstAddress, 2);
+ MmsValue_setUint16(vlanId, vid);
+
+ MmsValue* appIdVal = MmsValue_getElement(dstAddress, 3);
+ MmsValue_setUint16(appIdVal, appId);
+
+ /* noASDU */
+ MmsValue* noASDU = MmsValue_getElement(svValues, currentIndex++);
+ MmsValue_setInt32(noASDU, svControlBlock->noASDU);
+
+ currentSVCB++;
+ }
+
+ return namedVariable;
+}
+
+#endif /* (CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT == 1) */
diff --git a/src/iec61850/server/model/config_file_parser.c b/src/iec61850/server/model/config_file_parser.c
index 1157ec6a..e34258dc 100644
--- a/src/iec61850/server/model/config_file_parser.c
+++ b/src/iec61850/server/model/config_file_parser.c
@@ -395,8 +395,12 @@ ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle)
if (StringUtils_createBufferFromHexString(nameString, (uint8_t*) nameString2) != 6)
goto exit_error;
- PhyComAddress_create(currentGoCB, (uint8_t) vlanPrio, (uint16_t) vlanId, (uint16_t) appId,
- (uint8_t*) nameString2);
+
+ PhyComAddress* dstAddress =
+ PhyComAddress_create((uint8_t) vlanPrio, (uint16_t) vlanId, (uint16_t) appId,
+ (uint8_t*) nameString2);
+
+ GSEControlBlock_addPhyComAddress(currentGoCB, dstAddress);
}
else
diff --git a/src/iec61850/server/model/dynamic_model.c b/src/iec61850/server/model/dynamic_model.c
index 09a719e9..206e7b87 100644
--- a/src/iec61850/server/model/dynamic_model.c
+++ b/src/iec61850/server/model/dynamic_model.c
@@ -327,7 +327,7 @@ GSEControlBlock_create(const char* name, LogicalNode* parent, char* appId, char*
else
self->dataSetName = NULL;
- self->confRef = confRef;
+ self->confRev = confRef;
self->fixedOffs = fixedOffs;
self->minTime = minTime;
self->maxTime = maxTime;
@@ -342,14 +342,47 @@ GSEControlBlock_create(const char* name, LogicalNode* parent, char* appId, char*
return self;
}
-static void
+SVControlBlock*
+SVControlBlock_create(const char* name, LogicalNode* parent, char* svID, char* dataSet, uint32_t confRev, uint8_t smpMod,
+ uint16_t smpRate, uint8_t optFlds, bool isUnicast)
+{
+ SVControlBlock* self = (SVControlBlock*) GLOBAL_MALLOC(sizeof(SVControlBlock));
+
+ self->name = copyString(name);
+ self->parent = parent;
+
+ self->svId = copyString(svID); /* Is there a default value? */
+
+ if (dataSet)
+ self->dataSetName = copyString(dataSet);
+ else
+ self->dataSetName = NULL;
+
+ self->confRev = confRev;
+
+ self->smpMod = smpMod;
+ self->smpRate = smpRate;
+
+ self->optFlds = optFlds;
+ self->isUnicast = isUnicast;
+
+ return self;
+}
+
+void
+SVControlBlock_addPhyComAddress(SVControlBlock* self, PhyComAddress* phyComAddress)
+{
+ self->dstAddress = phyComAddress;
+}
+
+void
GSEControlBlock_addPhyComAddress(GSEControlBlock* self, PhyComAddress* phyComAddress)
{
self->address = phyComAddress;
}
PhyComAddress*
-PhyComAddress_create(GSEControlBlock* parent, uint8_t vlanPriority, uint16_t vlanId, uint16_t appId, uint8_t dstAddress[])
+PhyComAddress_create(uint8_t vlanPriority, uint16_t vlanId, uint16_t appId, uint8_t dstAddress[])
{
PhyComAddress* self = (PhyComAddress*) GLOBAL_MALLOC(sizeof(PhyComAddress));
@@ -359,9 +392,6 @@ PhyComAddress_create(GSEControlBlock* parent, uint8_t vlanPriority, uint16_t vla
memcpy(self->dstAddress, dstAddress, 6);
- if (parent != NULL)
- GSEControlBlock_addPhyComAddress(parent, self);
-
return self;
}
diff --git a/src/vs/libiec61850-wo-goose.def b/src/vs/libiec61850-wo-goose.def
index 9b30b7d0..f1cdcb39 100644
--- a/src/vs/libiec61850-wo-goose.def
+++ b/src/vs/libiec61850-wo-goose.def
@@ -494,4 +494,7 @@ EXPORTS
LogicalDevice_getChildByMmsVariableName
LogicalNode_getDataSet
ClientReport_getDataSetName
- MmsValue_getStringSize
\ No newline at end of file
+ MmsValue_getStringSize
+ SVControlBlock_create
+ SVControlBlock_addPhyComAddress
+ GSEControlBlock_addPhyComAddress
diff --git a/src/vs/libiec61850.def b/src/vs/libiec61850.def
index a88a7fc5..aca168eb 100644
--- a/src/vs/libiec61850.def
+++ b/src/vs/libiec61850.def
@@ -519,3 +519,6 @@ EXPORTS
LogicalNode_getDataSet
ClientReport_getDataSetName
MmsValue_getStringSize
+ SVControlBlock_create
+ SVControlBlock_addPhyComAddress
+ GSEControlBlock_addPhyComAddress
diff --git a/tools/model_generator/src/com/libiec61850/scl/communication/ConnectedAP.java b/tools/model_generator/src/com/libiec61850/scl/communication/ConnectedAP.java
index 46579aaf..2aceca49 100644
--- a/tools/model_generator/src/com/libiec61850/scl/communication/ConnectedAP.java
+++ b/tools/model_generator/src/com/libiec61850/scl/communication/ConnectedAP.java
@@ -35,6 +35,7 @@ public class ConnectedAP {
private String apName;
private List gses;
+ private List smvs;
public ConnectedAP(Node node) throws SclParserException {
iedName = ParserUtils.parseAttribute(node, "iedName");
@@ -50,6 +51,14 @@ public class ConnectedAP {
for (Node gseNode : gseNodes) {
gses.add(new GSE(gseNode));
}
+
+ smvs = new LinkedList();
+
+ List smvNodes = ParserUtils.getChildNodesWithTag(node, "SMV");
+
+ for (Node smvNode : smvNodes) {
+ smvs.add(new SMV(smvNode));
+ }
}
public String getIedName() {
@@ -64,7 +73,11 @@ public class ConnectedAP {
return gses;
}
- public GSEAddress lookupGSEAddress(String logicalDeviceName, String name) {
+ public List getSmvs() {
+ return smvs;
+ }
+
+ public PhyComAddress lookupGSEAddress(String logicalDeviceName, String name) {
for (GSE gse : this.getGses()) {
if (gse.getLdInst().equals(logicalDeviceName)) {
@@ -75,5 +88,17 @@ public class ConnectedAP {
return null;
}
+
+ public PhyComAddress lookupSMVAddress(String logicalDeviceName, String name) {
+
+ for (SMV smv : this.getSmvs()) {
+ if (smv.getLdInst().equals(logicalDeviceName)) {
+ if (smv.getCbName().equals(name))
+ return smv.getAddress();
+ }
+ }
+
+ return null;
+ }
}
diff --git a/tools/model_generator/src/com/libiec61850/scl/communication/GSE.java b/tools/model_generator/src/com/libiec61850/scl/communication/GSE.java
index 1bb0427b..eb56e1bf 100644
--- a/tools/model_generator/src/com/libiec61850/scl/communication/GSE.java
+++ b/tools/model_generator/src/com/libiec61850/scl/communication/GSE.java
@@ -31,7 +31,7 @@ public class GSE {
private String ldInst;
private String cbName;
- private GSEAddress address;
+ private PhyComAddress address;
public GSE(Node gseNode) throws SclParserException {
ldInst = ParserUtils.parseAttribute(gseNode, "ldInst");
@@ -45,7 +45,7 @@ public class GSE {
if (addressNode == null)
throw new SclParserException(gseNode, "GSE is missing address definition!");
- address = new GSEAddress(addressNode);
+ address = new PhyComAddress(addressNode);
}
public String getLdInst() {
@@ -56,7 +56,7 @@ public class GSE {
return cbName;
}
- public GSEAddress getAddress() {
+ public PhyComAddress getAddress() {
return address;
}
diff --git a/tools/model_generator/src/com/libiec61850/scl/communication/GSEAddress.java b/tools/model_generator/src/com/libiec61850/scl/communication/PhyComAddress.java
similarity index 96%
rename from tools/model_generator/src/com/libiec61850/scl/communication/GSEAddress.java
rename to tools/model_generator/src/com/libiec61850/scl/communication/PhyComAddress.java
index 151033ea..c4ff7e10 100644
--- a/tools/model_generator/src/com/libiec61850/scl/communication/GSEAddress.java
+++ b/tools/model_generator/src/com/libiec61850/scl/communication/PhyComAddress.java
@@ -29,14 +29,14 @@ import org.w3c.dom.Node;
import com.libiec61850.scl.ParserUtils;
import com.libiec61850.scl.SclParserException;
-public class GSEAddress {
+public class PhyComAddress {
private Integer vlanId = null;
private Integer vlanPriority = null;
private Integer appId = null;
private int[] macAddress = null;
- public GSEAddress(Node addressNode) throws DOMException, SclParserException {
+ public PhyComAddress(Node addressNode) throws DOMException, SclParserException {
List pNodes = ParserUtils.getChildNodesWithTag(addressNode, "P");
diff --git a/tools/model_generator/src/com/libiec61850/scl/communication/SMV.java b/tools/model_generator/src/com/libiec61850/scl/communication/SMV.java
new file mode 100644
index 00000000..71012cf8
--- /dev/null
+++ b/tools/model_generator/src/com/libiec61850/scl/communication/SMV.java
@@ -0,0 +1,61 @@
+package com.libiec61850.scl.communication;
+
+import org.w3c.dom.Node;
+
+import com.libiec61850.scl.ParserUtils;
+import com.libiec61850.scl.SclParserException;
+
+/*
+ * Copyright 2015 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 .
+ *
+ * See COPYING file for the complete license text.
+ */
+
+public class SMV {
+ private String ldInst;
+ private String cbName;
+
+ private PhyComAddress address;
+
+ public SMV(Node gseNode) throws SclParserException {
+ ldInst = ParserUtils.parseAttribute(gseNode, "ldInst");
+ cbName = ParserUtils.parseAttribute(gseNode, "cbName");
+
+ if ((ldInst == null) || (cbName == null))
+ throw new SclParserException(gseNode, "SMV is missing required attribute");
+
+ Node addressNode = ParserUtils.getChildNodeWithTag(gseNode, "Address");
+
+ if (addressNode == null)
+ throw new SclParserException(gseNode, "SMV is missing address definition!");
+
+ address = new PhyComAddress(addressNode);
+ }
+
+ public String getLdInst() {
+ return ldInst;
+ }
+
+ public String getCbName() {
+ return cbName;
+ }
+
+ public PhyComAddress getAddress() {
+ return address;
+ }
+}
diff --git a/tools/model_generator/src/com/libiec61850/scl/model/GSEControl.java b/tools/model_generator/src/com/libiec61850/scl/model/GSEControl.java
index 40ee837e..73309921 100644
--- a/tools/model_generator/src/com/libiec61850/scl/model/GSEControl.java
+++ b/tools/model_generator/src/com/libiec61850/scl/model/GSEControl.java
@@ -36,40 +36,45 @@ public class GSEControl {
private boolean fixedOffs = false;
private int minTime = -1;
private int maxTime = -1;
-
+
public GSEControl(Node gseControlNode) throws SclParserException {
this.name = ParserUtils.parseAttribute(gseControlNode, "name");
this.desc = ParserUtils.parseAttribute(gseControlNode, "desc");
this.dataSet = ParserUtils.parseAttribute(gseControlNode, "datSet");
-
- String confRevString = ParserUtils.parseAttribute(gseControlNode, "confRev");
-
+
+ String confRevString = ParserUtils.parseAttribute(gseControlNode,
+ "confRev");
+
if (confRevString != null)
this.confRev = new Integer(confRevString);
-
+
this.appID = ParserUtils.parseAttribute(gseControlNode, "appID");
-
- Boolean fixedOffs = ParserUtils.parseBooleanAttribute(gseControlNode, "fixedOffs");
-
- if (fixedOffs != null)
- this.fixedOffs = fixedOffs;
-
- String minTimeStr = ParserUtils.parseAttribute(gseControlNode, "minTime");
- String maxTimeStr = ParserUtils.parseAttribute(gseControlNode, "maxTime");
-
- if (minTimeStr != null)
- minTime = new Integer(minTimeStr);
-
- if (maxTimeStr != null)
- maxTime = new Integer(maxTimeStr);
-
- String typeString = ParserUtils.parseAttribute(gseControlNode, "type");
-
- if (typeString != null)
- if (!typeString.equals("GOOSE"))
- throw new SclParserException(gseControlNode, "GSEControl of type " + typeString + " not supported!");
-
+
+ Boolean fixedOffs = ParserUtils.parseBooleanAttribute(gseControlNode,
+ "fixedOffs");
+
+ if (fixedOffs != null)
+ this.fixedOffs = fixedOffs;
+
+ String minTimeStr = ParserUtils.parseAttribute(gseControlNode,
+ "minTime");
+ String maxTimeStr = ParserUtils.parseAttribute(gseControlNode,
+ "maxTime");
+
+ if (minTimeStr != null)
+ minTime = new Integer(minTimeStr);
+
+ if (maxTimeStr != null)
+ maxTime = new Integer(maxTimeStr);
+
+ String typeString = ParserUtils.parseAttribute(gseControlNode, "type");
+
+ if (typeString != null)
+ if (!typeString.equals("GOOSE"))
+ throw new SclParserException(gseControlNode,
+ "GSEControl of type " + typeString + " not supported!");
+
}
public String getName() {
diff --git a/tools/model_generator/src/com/libiec61850/scl/model/LogicalNode.java b/tools/model_generator/src/com/libiec61850/scl/model/LogicalNode.java
index 8fa7c58c..5d34675f 100644
--- a/tools/model_generator/src/com/libiec61850/scl/model/LogicalNode.java
+++ b/tools/model_generator/src/com/libiec61850/scl/model/LogicalNode.java
@@ -47,6 +47,7 @@ public class LogicalNode implements DataModelNode {
private List dataSets;
private List reportControlBlocks;
private List gseControlBlocks;
+ private List smvControlBlocks;
private List logControlBlocks;
private List logs;
private List settingGroupControlBlocks;
@@ -113,6 +114,10 @@ public class LogicalNode implements DataModelNode {
for (Node gseControlNode : gseControlNodes)
gseControlBlocks.add(new GSEControl(gseControlNode));
+ /* Parse Sampled Values (SV) control block definitions */
+ smvControlBlocks = new LinkedList();
+
+
/* Parse log control block definitions */
logControlBlocks = new LinkedList();
@@ -261,6 +266,10 @@ public class LogicalNode implements DataModelNode {
return gseControlBlocks;
}
+ public List getSampledValueControlBlocks() {
+ return smvControlBlocks;
+ }
+
public List getSettingGroupControlBlocks() {
return settingGroupControlBlocks;
}
diff --git a/tools/model_generator/src/com/libiec61850/scl/model/SampledValueControl.java b/tools/model_generator/src/com/libiec61850/scl/model/SampledValueControl.java
new file mode 100644
index 00000000..77993e77
--- /dev/null
+++ b/tools/model_generator/src/com/libiec61850/scl/model/SampledValueControl.java
@@ -0,0 +1,89 @@
+package com.libiec61850.scl.model;
+
+import org.w3c.dom.Node;
+
+import com.libiec61850.scl.ParserUtils;
+import com.libiec61850.scl.SclParserException;
+
+public class SampledValueControl {
+
+ private String name;
+ private String desc = null;
+ private String datSet;
+ private int confRev = 1;
+ private String smvID;
+ private int smpRate;
+ private int nofASDU;
+ private boolean multicast;
+ private SmvOpts smvOpts;
+
+
+
+ public SampledValueControl(Node smvControlNode) throws SclParserException {
+ this.name = ParserUtils.parseAttribute(smvControlNode, "name");
+ this.desc = ParserUtils.parseAttribute(smvControlNode, "desc");
+ this.datSet = ParserUtils.parseAttribute(smvControlNode, "datSet");
+
+ String confRevString = ParserUtils.parseAttribute(smvControlNode, "confRev");
+
+ if (confRevString != null)
+ this.confRev = new Integer(confRevString);
+
+ this.smvID = ParserUtils.parseAttribute(smvControlNode, "smvID");
+
+ this.multicast = ParserUtils.parseBooleanAttribute(smvControlNode, "multicast");
+
+ String smpRateString = ParserUtils.parseAttribute(smvControlNode, "smpRate");
+
+ if (smpRateString != null)
+ this.smpRate = new Integer(smpRateString);
+
+ String nofASDUString = ParserUtils.parseAttribute(smvControlNode, "nofASDU");
+
+ if (nofASDUString != null)
+ this.nofASDU = new Integer(nofASDUString);
+
+ Node smvOptsNode = ParserUtils.getChildNodeWithTag(smvControlNode, "SmvOpts");
+
+ this.smvOpts = new SmvOpts(smvOptsNode);
+ }
+
+
+
+ public String getName() {
+ return name;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public String getDatSet() {
+ return datSet;
+ }
+
+ public int getConfRev() {
+ return confRev;
+ }
+
+ public String getSmvID() {
+ return smvID;
+ }
+
+ public int getSmpRate() {
+ return smpRate;
+ }
+
+ public int getNofASDI() {
+ return nofASDU;
+ }
+
+ public boolean isMulticast() {
+ return multicast;
+ }
+
+ public SmvOpts getSmvOpts() {
+ return smvOpts;
+ }
+
+}
diff --git a/tools/model_generator/src/com/libiec61850/scl/model/SmvOpts.java b/tools/model_generator/src/com/libiec61850/scl/model/SmvOpts.java
new file mode 100644
index 00000000..1dcd59ad
--- /dev/null
+++ b/tools/model_generator/src/com/libiec61850/scl/model/SmvOpts.java
@@ -0,0 +1,41 @@
+package com.libiec61850.scl.model;
+
+import org.w3c.dom.Node;
+
+import com.libiec61850.scl.ParserUtils;
+import com.libiec61850.scl.SclParserException;
+
+public class SmvOpts {
+
+
+ private boolean refreshTime = false;
+ private boolean sampleRate = false;
+ private boolean dataSet = false;
+ private boolean security = false;
+ private boolean sampleSynchronized = false;
+
+ public SmvOpts(Node smvOptsNode) throws SclParserException {
+
+ Boolean refreshTime = ParserUtils.parseBooleanAttribute(smvOptsNode, "refreshTime");
+ if (refreshTime != null)
+ this.refreshTime = refreshTime;
+
+ Boolean sampleRate = ParserUtils.parseBooleanAttribute(smvOptsNode, "sampleRate");
+ if (sampleRate != null)
+ this.sampleRate = sampleRate;
+
+ Boolean dataSet = ParserUtils.parseBooleanAttribute(smvOptsNode, "dataSet");
+ if (dataSet != null)
+ this.dataSet = dataSet;
+
+ Boolean security = ParserUtils.parseBooleanAttribute(smvOptsNode, "security");
+ if (security != null)
+ this.security = security;
+
+ Boolean sampleSynchronized = ParserUtils.parseBooleanAttribute(smvOptsNode, "sampleSynchronized");
+ if (sampleSynchronized != null)
+ this.sampleSynchronized = sampleSynchronized;
+
+ }
+
+}
diff --git a/tools/model_generator/src/com/libiec61850/tools/DynamicModelGenerator.java b/tools/model_generator/src/com/libiec61850/tools/DynamicModelGenerator.java
index ac47251c..1297c623 100644
--- a/tools/model_generator/src/com/libiec61850/tools/DynamicModelGenerator.java
+++ b/tools/model_generator/src/com/libiec61850/tools/DynamicModelGenerator.java
@@ -35,7 +35,7 @@ import com.libiec61850.scl.DataAttributeDefinition;
import com.libiec61850.scl.SclParser;
import com.libiec61850.scl.SclParserException;
import com.libiec61850.scl.communication.ConnectedAP;
-import com.libiec61850.scl.communication.GSEAddress;
+import com.libiec61850.scl.communication.PhyComAddress;
import com.libiec61850.scl.model.AccessPoint;
import com.libiec61850.scl.model.DataAttribute;
import com.libiec61850.scl.model.DataModelValue;
@@ -145,7 +145,7 @@ public class DynamicModelGenerator {
for (GSEControl gcb : logicalNode.getGSEControlBlocks()) {
LogicalDevice ld = logicalNode.getParentLogicalDevice();
- GSEAddress gseAddress = null;
+ PhyComAddress gseAddress = null;
if (connectedAP != null)
gseAddress = connectedAP.lookupGSEAddress(ld.getInst(), gcb.getName());
diff --git a/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java b/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java
index b1ed816e..a7e3ff42 100644
--- a/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java
+++ b/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java
@@ -37,7 +37,7 @@ import com.libiec61850.scl.SclParserException;
import com.libiec61850.scl.communication.Communication;
import com.libiec61850.scl.communication.ConnectedAP;
import com.libiec61850.scl.communication.GSE;
-import com.libiec61850.scl.communication.GSEAddress;
+import com.libiec61850.scl.communication.PhyComAddress;
import com.libiec61850.scl.communication.SubNetwork;
import com.libiec61850.scl.model.AccessPoint;
import com.libiec61850.scl.model.DataAttribute;
@@ -753,7 +753,7 @@ public class StaticModelGenerator {
for (GSEControl gseControlBlock : gseControlBlocks) {
- GSEAddress gseAddress = connectedAP.lookupGSEAddress(logicalDeviceName, gseControlBlock.getName());
+ PhyComAddress gseAddress = connectedAP.lookupGSEAddress(logicalDeviceName, gseControlBlock.getName());
String gseString = "";