- server side support for SV control blocks - WIP
parent
25d8254683
commit
8482cfce9b
@ -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_ */
|
@ -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) */
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue