- server side support for SV control blocks - WIP
This commit is contained in:
parent
25d8254683
commit
8482cfce9b
25 changed files with 772 additions and 58 deletions
|
@ -67,12 +67,14 @@
|
||||||
/* Ethernet interface ID for GOOSE and SV */
|
/* Ethernet interface ID for GOOSE and SV */
|
||||||
#define CONFIG_ETHERNET_INTERFACE_ID "eth0"
|
#define CONFIG_ETHERNET_INTERFACE_ID "eth0"
|
||||||
//#define CONFIG_ETHERNET_INTERFACE_ID "vboxnet0"
|
//#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.
|
//#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 */
|
/* Set to 1 to include GOOSE support in the build. Otherwise set to 0 */
|
||||||
#define CONFIG_INCLUDE_GOOSE_SUPPORT 1
|
#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
|
#ifdef _WIN32
|
||||||
|
|
||||||
/* GOOSE will be disabled for Windows if ethernet support (winpcap) is not available */
|
/* GOOSE will be disabled for Windows if ethernet support (winpcap) is not available */
|
||||||
|
|
|
@ -71,6 +71,9 @@
|
||||||
/* Set to 1 to include GOOSE support in the build. Otherwise set to 0 */
|
/* Set to 1 to include GOOSE support in the build. Otherwise set to 0 */
|
||||||
#cmakedefine01 CONFIG_INCLUDE_GOOSE_SUPPORT
|
#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
|
#ifdef _WIN32
|
||||||
|
|
||||||
/* GOOSE will be disabled for Windows if ethernet support (winpcap) is not available */
|
/* GOOSE will be disabled for Windows if ethernet support (winpcap) is not available */
|
||||||
|
|
28
dotnet/reporting/Settings.cs
Normal file
28
dotnet/reporting/Settings.cs
Normal file
|
@ -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.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
#include "platform_endian.h"
|
#include "platform_endian.h"
|
||||||
|
|
||||||
#define LIBIEC61850_VERSION "0.8.7"
|
#define LIBIEC61850_VERSION "0.9.0"
|
||||||
|
|
||||||
#ifndef CONFIG_DEFAULT_MMS_VENDOR_NAME
|
#ifndef CONFIG_DEFAULT_MMS_VENDOR_NAME
|
||||||
#define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com"
|
#define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com"
|
||||||
|
@ -29,6 +29,10 @@
|
||||||
#define CONFIG_DEFAULT_MMS_REVISION LIBIEC61850_VERSION
|
#define CONFIG_DEFAULT_MMS_REVISION LIBIEC61850_VERSION
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT
|
||||||
|
#define CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#if (DEBUG != 1)
|
#if (DEBUG != 1)
|
||||||
#define NDEBUG 1
|
#define NDEBUG 1
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -183,7 +183,7 @@ SettingGroupControlBlock_create(LogicalNode* parent, uint8_t actSG, uint8_t numO
|
||||||
* \param parent the parent LN
|
* \param parent the parent LN
|
||||||
* \param appId the application ID of the GoCB
|
* \param appId the application ID of the GoCB
|
||||||
* \param dataSet the data set reference to be used by 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 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 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)
|
* \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
|
* \return the new GoCB instance
|
||||||
*/
|
*/
|
||||||
GSEControlBlock*
|
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);
|
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)
|
||||||
*
|
*
|
||||||
* A PhyComAddress object contains all required addressing informations for a GOOSE publisher.
|
* 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 information for a GOOSE publisher.
|
||||||
*
|
*
|
||||||
* \param parent the parent GSEControlBlock object
|
|
||||||
* \param vlanPriority the priority field of the VLAN tag
|
* \param vlanPriority the priority field of the VLAN tag
|
||||||
* \param vlanId the ID field of the VLAN tag
|
* \param vlanId the ID field of the VLAN tag
|
||||||
* \param appId the application identifier
|
* \param appId the application identifier
|
||||||
|
@ -208,7 +233,7 @@ GSEControlBlock_create(const char* name, LogicalNode* parent, char* appId, char*
|
||||||
* \return the new PhyComAddress object
|
* \return the new PhyComAddress object
|
||||||
*/
|
*/
|
||||||
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[]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief create a new data set
|
* \brief create a new data set
|
||||||
|
|
|
@ -80,6 +80,8 @@ typedef struct sSettingGroupControlBlock SettingGroupControlBlock;
|
||||||
|
|
||||||
typedef struct sGSEControlBlock GSEControlBlock;
|
typedef struct sGSEControlBlock GSEControlBlock;
|
||||||
|
|
||||||
|
typedef struct sSVControlBlock SVControlBlock;
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
IEC61850_BOOLEAN = 0,/* int */
|
IEC61850_BOOLEAN = 0,/* int */
|
||||||
|
@ -162,6 +164,7 @@ struct sIedModel {
|
||||||
DataSet* dataSets;
|
DataSet* dataSets;
|
||||||
ReportControlBlock* rcbs;
|
ReportControlBlock* rcbs;
|
||||||
GSEControlBlock* gseCBs;
|
GSEControlBlock* gseCBs;
|
||||||
|
SVControlBlock* svCBs;
|
||||||
SettingGroupControlBlock* sgcbs;
|
SettingGroupControlBlock* sgcbs;
|
||||||
void (*initializer) (void);
|
void (*initializer) (void);
|
||||||
};
|
};
|
||||||
|
@ -279,7 +282,7 @@ struct sGSEControlBlock {
|
||||||
char* name;
|
char* name;
|
||||||
char* appId;
|
char* appId;
|
||||||
char* dataSetName; /* pre loaded with relative name in logical node */
|
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 */
|
bool fixedOffs; /* fixed offsets */
|
||||||
PhyComAddress* address; /* GSE communication parameters */
|
PhyComAddress* address; /* GSE communication parameters */
|
||||||
int minTime; /* optional minTime parameter --> -1 if not present */
|
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 */
|
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
|
* \brief get the number of direct children of a model node
|
||||||
*
|
*
|
||||||
|
|
|
@ -40,6 +40,11 @@ struct sMmsMapping {
|
||||||
const char* gooseInterfaceId;
|
const char* gooseInterfaceId;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT == 1)
|
||||||
|
LinkedList svControls;
|
||||||
|
const char* svInterfaceId;
|
||||||
|
#endif
|
||||||
|
|
||||||
LinkedList controlObjects;
|
LinkedList controlObjects;
|
||||||
LinkedList observedObjects;
|
LinkedList observedObjects;
|
||||||
LinkedList attributeAccessHandlers;
|
LinkedList attributeAccessHandlers;
|
||||||
|
|
31
src/iec61850/inc_private/mms_sv.h
Normal file
31
src/iec61850/inc_private/mms_sv.h
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* 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_ */
|
|
@ -550,7 +550,7 @@ GOOSE_createGOOSEControlBlocks(MmsMapping* self, MmsDomain* domain,
|
||||||
|
|
||||||
MmsValue* confRef = MmsValue_getElement(gseValues, 3);
|
MmsValue* confRef = MmsValue_getElement(gseValues, 3);
|
||||||
|
|
||||||
MmsValue_setUint32(confRef, gooseControlBlock->confRef);
|
MmsValue_setUint32(confRef, gooseControlBlock->confRev);
|
||||||
|
|
||||||
mmsGCB->dataSet = NULL;
|
mmsGCB->dataSet = NULL;
|
||||||
|
|
||||||
|
@ -587,5 +587,5 @@ GOOSE_createGOOSEControlBlocks(MmsMapping* self, MmsDomain* domain,
|
||||||
return namedVariable;
|
return namedVariable;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */
|
||||||
|
|
||||||
|
|
|
@ -766,9 +766,8 @@ countGSEControlBlocksForLogicalNode(MmsMapping* self, LogicalNode* logicalNode)
|
||||||
GSEControlBlock* gcb = self->model->gseCBs;
|
GSEControlBlock* gcb = self->model->gseCBs;
|
||||||
|
|
||||||
while (gcb != NULL) {
|
while (gcb != NULL) {
|
||||||
if (gcb->parent == logicalNode) {
|
if (gcb->parent == logicalNode)
|
||||||
gseCount++;
|
gseCount++;
|
||||||
}
|
|
||||||
|
|
||||||
gcb = gcb->sibling;
|
gcb = gcb->sibling;
|
||||||
}
|
}
|
||||||
|
@ -778,6 +777,27 @@ countGSEControlBlocksForLogicalNode(MmsMapping* self, LogicalNode* logicalNode)
|
||||||
|
|
||||||
#endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */
|
#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*
|
static SettingGroupControlBlock*
|
||||||
checkForSgcb(MmsMapping* self, LogicalNode* logicalNode)
|
checkForSgcb(MmsMapping* self, LogicalNode* logicalNode)
|
||||||
{
|
{
|
||||||
|
@ -862,6 +882,28 @@ createNamedVariableFromLogicalNode(MmsMapping* self, MmsDomain* domain,
|
||||||
|
|
||||||
#endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */
|
#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,
|
namedVariable->typeSpec.structure.elements = (MmsVariableSpecification**) GLOBAL_CALLOC(componentCount,
|
||||||
sizeof(MmsVariableSpecification*));
|
sizeof(MmsVariableSpecification*));
|
||||||
|
|
||||||
|
@ -961,6 +1003,24 @@ createNamedVariableFromLogicalNode(MmsMapping* self, MmsDomain* domain,
|
||||||
currentComponent++;
|
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)) {
|
if (LogicalNode_hasFCData(logicalNode, IEC61850_FC_EX)) {
|
||||||
namedVariable->typeSpec.structure.elements[currentComponent] =
|
namedVariable->typeSpec.structure.elements[currentComponent] =
|
||||||
createFCNamedVariable(logicalNode, IEC61850_FC_EX);
|
createFCNamedVariable(logicalNode, IEC61850_FC_EX);
|
||||||
|
@ -1138,6 +1198,11 @@ MmsMapping_create(IedModel* model)
|
||||||
self->gooseInterfaceId = NULL;
|
self->gooseInterfaceId = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT == 1)
|
||||||
|
self->svControls = LinkedList_create();
|
||||||
|
self->svInterfaceId = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if (CONFIG_IEC61850_CONTROL_SERVICE == 1)
|
#if (CONFIG_IEC61850_CONTROL_SERVICE == 1)
|
||||||
self->controlObjects = LinkedList_create();
|
self->controlObjects = LinkedList_create();
|
||||||
#endif
|
#endif
|
||||||
|
@ -1177,6 +1242,10 @@ MmsMapping_destroy(MmsMapping* self)
|
||||||
LinkedList_destroyDeep(self->gseControls, (LinkedListValueDeleteFunction) MmsGooseControlBlock_destroy);
|
LinkedList_destroyDeep(self->gseControls, (LinkedListValueDeleteFunction) MmsGooseControlBlock_destroy);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT == 1)
|
||||||
|
LinkedList_destroyDeep(self->svControls, (LinkedListValueDeleteFunction) MmsSvControlBlock_destroy);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if (CONFIG_IEC61850_CONTROL_SERVICE == 1)
|
#if (CONFIG_IEC61850_CONTROL_SERVICE == 1)
|
||||||
LinkedList_destroyDeep(self->controlObjects, (LinkedListValueDeleteFunction) ControlObject_destroy);
|
LinkedList_destroyDeep(self->controlObjects, (LinkedListValueDeleteFunction) ControlObject_destroy);
|
||||||
#endif
|
#endif
|
||||||
|
|
251
src/iec61850/server/mms_mapping/mms_sv.c
Normal file
251
src/iec61850/server/mms_mapping/mms_sv.c
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* 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) */
|
|
@ -395,8 +395,12 @@ ConfigFileParser_createModelFromConfigFile(FileHandle fileHandle)
|
||||||
if (StringUtils_createBufferFromHexString(nameString, (uint8_t*) nameString2) != 6)
|
if (StringUtils_createBufferFromHexString(nameString, (uint8_t*) nameString2) != 6)
|
||||||
goto exit_error;
|
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
|
else
|
||||||
|
|
|
@ -327,7 +327,7 @@ GSEControlBlock_create(const char* name, LogicalNode* parent, char* appId, char*
|
||||||
else
|
else
|
||||||
self->dataSetName = NULL;
|
self->dataSetName = NULL;
|
||||||
|
|
||||||
self->confRef = confRef;
|
self->confRev = confRef;
|
||||||
self->fixedOffs = fixedOffs;
|
self->fixedOffs = fixedOffs;
|
||||||
self->minTime = minTime;
|
self->minTime = minTime;
|
||||||
self->maxTime = maxTime;
|
self->maxTime = maxTime;
|
||||||
|
@ -342,14 +342,47 @@ GSEControlBlock_create(const char* name, LogicalNode* parent, char* appId, char*
|
||||||
return self;
|
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)
|
GSEControlBlock_addPhyComAddress(GSEControlBlock* self, PhyComAddress* phyComAddress)
|
||||||
{
|
{
|
||||||
self->address = phyComAddress;
|
self->address = phyComAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
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));
|
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);
|
memcpy(self->dstAddress, dstAddress, 6);
|
||||||
|
|
||||||
if (parent != NULL)
|
|
||||||
GSEControlBlock_addPhyComAddress(parent, self);
|
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -494,4 +494,7 @@ EXPORTS
|
||||||
LogicalDevice_getChildByMmsVariableName
|
LogicalDevice_getChildByMmsVariableName
|
||||||
LogicalNode_getDataSet
|
LogicalNode_getDataSet
|
||||||
ClientReport_getDataSetName
|
ClientReport_getDataSetName
|
||||||
MmsValue_getStringSize
|
MmsValue_getStringSize
|
||||||
|
SVControlBlock_create
|
||||||
|
SVControlBlock_addPhyComAddress
|
||||||
|
GSEControlBlock_addPhyComAddress
|
||||||
|
|
|
@ -519,3 +519,6 @@ EXPORTS
|
||||||
LogicalNode_getDataSet
|
LogicalNode_getDataSet
|
||||||
ClientReport_getDataSetName
|
ClientReport_getDataSetName
|
||||||
MmsValue_getStringSize
|
MmsValue_getStringSize
|
||||||
|
SVControlBlock_create
|
||||||
|
SVControlBlock_addPhyComAddress
|
||||||
|
GSEControlBlock_addPhyComAddress
|
||||||
|
|
|
@ -35,6 +35,7 @@ public class ConnectedAP {
|
||||||
private String apName;
|
private String apName;
|
||||||
|
|
||||||
private List<GSE> gses;
|
private List<GSE> gses;
|
||||||
|
private List<SMV> smvs;
|
||||||
|
|
||||||
public ConnectedAP(Node node) throws SclParserException {
|
public ConnectedAP(Node node) throws SclParserException {
|
||||||
iedName = ParserUtils.parseAttribute(node, "iedName");
|
iedName = ParserUtils.parseAttribute(node, "iedName");
|
||||||
|
@ -50,6 +51,14 @@ public class ConnectedAP {
|
||||||
for (Node gseNode : gseNodes) {
|
for (Node gseNode : gseNodes) {
|
||||||
gses.add(new GSE(gseNode));
|
gses.add(new GSE(gseNode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
smvs = new LinkedList<SMV>();
|
||||||
|
|
||||||
|
List<Node> smvNodes = ParserUtils.getChildNodesWithTag(node, "SMV");
|
||||||
|
|
||||||
|
for (Node smvNode : smvNodes) {
|
||||||
|
smvs.add(new SMV(smvNode));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getIedName() {
|
public String getIedName() {
|
||||||
|
@ -64,7 +73,11 @@ public class ConnectedAP {
|
||||||
return gses;
|
return gses;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GSEAddress lookupGSEAddress(String logicalDeviceName, String name) {
|
public List<SMV> getSmvs() {
|
||||||
|
return smvs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PhyComAddress lookupGSEAddress(String logicalDeviceName, String name) {
|
||||||
|
|
||||||
for (GSE gse : this.getGses()) {
|
for (GSE gse : this.getGses()) {
|
||||||
if (gse.getLdInst().equals(logicalDeviceName)) {
|
if (gse.getLdInst().equals(logicalDeviceName)) {
|
||||||
|
@ -75,5 +88,17 @@ public class ConnectedAP {
|
||||||
|
|
||||||
return null;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ public class GSE {
|
||||||
private String ldInst;
|
private String ldInst;
|
||||||
private String cbName;
|
private String cbName;
|
||||||
|
|
||||||
private GSEAddress address;
|
private PhyComAddress address;
|
||||||
|
|
||||||
public GSE(Node gseNode) throws SclParserException {
|
public GSE(Node gseNode) throws SclParserException {
|
||||||
ldInst = ParserUtils.parseAttribute(gseNode, "ldInst");
|
ldInst = ParserUtils.parseAttribute(gseNode, "ldInst");
|
||||||
|
@ -45,7 +45,7 @@ public class GSE {
|
||||||
if (addressNode == null)
|
if (addressNode == null)
|
||||||
throw new SclParserException(gseNode, "GSE is missing address definition!");
|
throw new SclParserException(gseNode, "GSE is missing address definition!");
|
||||||
|
|
||||||
address = new GSEAddress(addressNode);
|
address = new PhyComAddress(addressNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLdInst() {
|
public String getLdInst() {
|
||||||
|
@ -56,7 +56,7 @@ public class GSE {
|
||||||
return cbName;
|
return cbName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GSEAddress getAddress() {
|
public PhyComAddress getAddress() {
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,14 +29,14 @@ import org.w3c.dom.Node;
|
||||||
import com.libiec61850.scl.ParserUtils;
|
import com.libiec61850.scl.ParserUtils;
|
||||||
import com.libiec61850.scl.SclParserException;
|
import com.libiec61850.scl.SclParserException;
|
||||||
|
|
||||||
public class GSEAddress {
|
public class PhyComAddress {
|
||||||
|
|
||||||
private Integer vlanId = null;
|
private Integer vlanId = null;
|
||||||
private Integer vlanPriority = null;
|
private Integer vlanPriority = null;
|
||||||
private Integer appId = null;
|
private Integer appId = null;
|
||||||
private int[] macAddress = null;
|
private int[] macAddress = null;
|
||||||
|
|
||||||
public GSEAddress(Node addressNode) throws DOMException, SclParserException {
|
public PhyComAddress(Node addressNode) throws DOMException, SclParserException {
|
||||||
|
|
||||||
List<Node> pNodes = ParserUtils.getChildNodesWithTag(addressNode, "P");
|
List<Node> pNodes = ParserUtils.getChildNodesWithTag(addressNode, "P");
|
||||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,40 +36,45 @@ public class GSEControl {
|
||||||
private boolean fixedOffs = false;
|
private boolean fixedOffs = false;
|
||||||
private int minTime = -1;
|
private int minTime = -1;
|
||||||
private int maxTime = -1;
|
private int maxTime = -1;
|
||||||
|
|
||||||
public GSEControl(Node gseControlNode) throws SclParserException {
|
public GSEControl(Node gseControlNode) throws SclParserException {
|
||||||
|
|
||||||
this.name = ParserUtils.parseAttribute(gseControlNode, "name");
|
this.name = ParserUtils.parseAttribute(gseControlNode, "name");
|
||||||
this.desc = ParserUtils.parseAttribute(gseControlNode, "desc");
|
this.desc = ParserUtils.parseAttribute(gseControlNode, "desc");
|
||||||
this.dataSet = ParserUtils.parseAttribute(gseControlNode, "datSet");
|
this.dataSet = ParserUtils.parseAttribute(gseControlNode, "datSet");
|
||||||
|
|
||||||
String confRevString = ParserUtils.parseAttribute(gseControlNode, "confRev");
|
String confRevString = ParserUtils.parseAttribute(gseControlNode,
|
||||||
|
"confRev");
|
||||||
|
|
||||||
if (confRevString != null)
|
if (confRevString != null)
|
||||||
this.confRev = new Integer(confRevString);
|
this.confRev = new Integer(confRevString);
|
||||||
|
|
||||||
this.appID = ParserUtils.parseAttribute(gseControlNode, "appID");
|
this.appID = ParserUtils.parseAttribute(gseControlNode, "appID");
|
||||||
|
|
||||||
Boolean fixedOffs = ParserUtils.parseBooleanAttribute(gseControlNode, "fixedOffs");
|
Boolean fixedOffs = ParserUtils.parseBooleanAttribute(gseControlNode,
|
||||||
|
"fixedOffs");
|
||||||
if (fixedOffs != null)
|
|
||||||
this.fixedOffs = fixedOffs;
|
if (fixedOffs != null)
|
||||||
|
this.fixedOffs = fixedOffs;
|
||||||
String minTimeStr = ParserUtils.parseAttribute(gseControlNode, "minTime");
|
|
||||||
String maxTimeStr = ParserUtils.parseAttribute(gseControlNode, "maxTime");
|
String minTimeStr = ParserUtils.parseAttribute(gseControlNode,
|
||||||
|
"minTime");
|
||||||
if (minTimeStr != null)
|
String maxTimeStr = ParserUtils.parseAttribute(gseControlNode,
|
||||||
minTime = new Integer(minTimeStr);
|
"maxTime");
|
||||||
|
|
||||||
if (maxTimeStr != null)
|
if (minTimeStr != null)
|
||||||
maxTime = new Integer(maxTimeStr);
|
minTime = new Integer(minTimeStr);
|
||||||
|
|
||||||
String typeString = ParserUtils.parseAttribute(gseControlNode, "type");
|
if (maxTimeStr != null)
|
||||||
|
maxTime = new Integer(maxTimeStr);
|
||||||
if (typeString != null)
|
|
||||||
if (!typeString.equals("GOOSE"))
|
String typeString = ParserUtils.parseAttribute(gseControlNode, "type");
|
||||||
throw new SclParserException(gseControlNode, "GSEControl of type " + typeString + " not supported!");
|
|
||||||
|
if (typeString != null)
|
||||||
|
if (!typeString.equals("GOOSE"))
|
||||||
|
throw new SclParserException(gseControlNode,
|
||||||
|
"GSEControl of type " + typeString + " not supported!");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
|
|
@ -47,6 +47,7 @@ public class LogicalNode implements DataModelNode {
|
||||||
private List<DataSet> dataSets;
|
private List<DataSet> dataSets;
|
||||||
private List<ReportControlBlock> reportControlBlocks;
|
private List<ReportControlBlock> reportControlBlocks;
|
||||||
private List<GSEControl> gseControlBlocks;
|
private List<GSEControl> gseControlBlocks;
|
||||||
|
private List<SampledValueControl> smvControlBlocks;
|
||||||
private List<LogControl> logControlBlocks;
|
private List<LogControl> logControlBlocks;
|
||||||
private List<Log> logs;
|
private List<Log> logs;
|
||||||
private List<SettingControl> settingGroupControlBlocks;
|
private List<SettingControl> settingGroupControlBlocks;
|
||||||
|
@ -113,6 +114,10 @@ public class LogicalNode implements DataModelNode {
|
||||||
for (Node gseControlNode : gseControlNodes)
|
for (Node gseControlNode : gseControlNodes)
|
||||||
gseControlBlocks.add(new GSEControl(gseControlNode));
|
gseControlBlocks.add(new GSEControl(gseControlNode));
|
||||||
|
|
||||||
|
/* Parse Sampled Values (SV) control block definitions */
|
||||||
|
smvControlBlocks = new LinkedList<SampledValueControl>();
|
||||||
|
|
||||||
|
|
||||||
/* Parse log control block definitions */
|
/* Parse log control block definitions */
|
||||||
logControlBlocks = new LinkedList<LogControl>();
|
logControlBlocks = new LinkedList<LogControl>();
|
||||||
|
|
||||||
|
@ -261,6 +266,10 @@ public class LogicalNode implements DataModelNode {
|
||||||
return gseControlBlocks;
|
return gseControlBlocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<SampledValueControl> getSampledValueControlBlocks() {
|
||||||
|
return smvControlBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
public List<SettingControl> getSettingGroupControlBlocks() {
|
public List<SettingControl> getSettingGroupControlBlocks() {
|
||||||
return settingGroupControlBlocks;
|
return settingGroupControlBlocks;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -35,7 +35,7 @@ import com.libiec61850.scl.DataAttributeDefinition;
|
||||||
import com.libiec61850.scl.SclParser;
|
import com.libiec61850.scl.SclParser;
|
||||||
import com.libiec61850.scl.SclParserException;
|
import com.libiec61850.scl.SclParserException;
|
||||||
import com.libiec61850.scl.communication.ConnectedAP;
|
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.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;
|
||||||
|
@ -145,7 +145,7 @@ public class DynamicModelGenerator {
|
||||||
for (GSEControl gcb : logicalNode.getGSEControlBlocks()) {
|
for (GSEControl gcb : logicalNode.getGSEControlBlocks()) {
|
||||||
LogicalDevice ld = logicalNode.getParentLogicalDevice();
|
LogicalDevice ld = logicalNode.getParentLogicalDevice();
|
||||||
|
|
||||||
GSEAddress gseAddress = null;
|
PhyComAddress gseAddress = null;
|
||||||
|
|
||||||
if (connectedAP != null)
|
if (connectedAP != null)
|
||||||
gseAddress = connectedAP.lookupGSEAddress(ld.getInst(), gcb.getName());
|
gseAddress = connectedAP.lookupGSEAddress(ld.getInst(), gcb.getName());
|
||||||
|
|
|
@ -37,7 +37,7 @@ import com.libiec61850.scl.SclParserException;
|
||||||
import com.libiec61850.scl.communication.Communication;
|
import com.libiec61850.scl.communication.Communication;
|
||||||
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.GSEAddress;
|
import com.libiec61850.scl.communication.PhyComAddress;
|
||||||
import com.libiec61850.scl.communication.SubNetwork;
|
import com.libiec61850.scl.communication.SubNetwork;
|
||||||
import com.libiec61850.scl.model.AccessPoint;
|
import com.libiec61850.scl.model.AccessPoint;
|
||||||
import com.libiec61850.scl.model.DataAttribute;
|
import com.libiec61850.scl.model.DataAttribute;
|
||||||
|
@ -753,7 +753,7 @@ public class StaticModelGenerator {
|
||||||
|
|
||||||
for (GSEControl gseControlBlock : gseControlBlocks) {
|
for (GSEControl gseControlBlock : gseControlBlocks) {
|
||||||
|
|
||||||
GSEAddress gseAddress = connectedAP.lookupGSEAddress(logicalDeviceName, gseControlBlock.getName());
|
PhyComAddress gseAddress = connectedAP.lookupGSEAddress(logicalDeviceName, gseControlBlock.getName());
|
||||||
|
|
||||||
String gseString = "";
|
String gseString = "";
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue