diff --git a/src/main/java/com/beanit/iec61850bean/BdaTimestamp.java b/src/main/java/com/beanit/iec61850bean/BdaTimestamp.java
index 3e328e9..6ec5d0b 100644
--- a/src/main/java/com/beanit/iec61850bean/BdaTimestamp.java
+++ b/src/main/java/com/beanit/iec61850bean/BdaTimestamp.java
@@ -17,226 +17,266 @@ import com.beanit.asn1bean.ber.types.BerNull;
import com.beanit.iec61850bean.internal.mms.asn1.Data;
import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription;
import com.beanit.iec61850bean.internal.mms.asn1.UtcTime;
+
import java.time.Instant;
import java.util.Date;
public final class BdaTimestamp extends BasicDataAttribute {
- private volatile byte[] value;
-
- public BdaTimestamp(
- ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) {
- super(objectReference, fc, sAddr, dchg, dupd);
- basicType = BdaType.TIMESTAMP;
- setDefault();
- }
-
- /**
- * The SecondSinceEpoch shall be the interval in seconds continuously counted from the epoch
- * 1970-01-01 00:00:00 UTC
- */
-
- /**
- * Returns the value as the number of seconds since epoch 1970-01-01 00:00:00 UTC
- *
- * @return the number of seconds since epoch 1970-01-01 00:00:00 UTC
- */
- private long getSecondsSinceEpoch() {
- return ((0xffL & value[0]) << 24
- | (0xffL & value[1]) << 16
- | (0xffL & value[2]) << 8
- | (0xffL & value[3]));
- }
-
- /**
- * The attribute FractionOfSecond shall be the fraction of the current second when the value of
- * the TimeStamp has been determined. The fraction of second shall be calculated as
- * (SUM from I = 0 to 23 of bi*2**–(I+1) s). NOTE 1 The resolution is the smallest unit by
- * which the time stamp is updated. The 24 bits of the integer provides 1 out of 16777216 counts
- * as the smallest unit; calculated by 1/2**24 which equals approximately 60 ns.
- *
- *
NOTE 2 The resolution of a time stamp may be 1/2**1 (= 0,5 s) if only the first bit is used;
- * or may be 1/2**2 (= 0,25 s) if the first two bits are used; or may be approximately 60 ns if
- * all 24 bits are used. The resolution provided by an IED is outside the scope of this standard.
- *
- * @return the fraction of seconds
- */
- private int getFractionOfSecond() {
- return ((0xff & value[4]) << 16 | (0xff & value[5]) << 8 | (0xff & value[6]));
- }
-
- @Override
- public void setValueFrom(BasicDataAttribute bda) {
- byte[] srcValue = ((BdaTimestamp) bda).getValue();
- if (value.length != srcValue.length) {
- value = new byte[srcValue.length];
- }
- System.arraycopy(srcValue, 0, value, 0, srcValue.length);
- }
-
- public Instant getInstant() {
- if (value == null || value.length == 0) {
- return null;
- }
- long time =
- getSecondsSinceEpoch() * 1000L
- + (long) (((float) getFractionOfSecond()) / (1 << 24) * 1000 + 0.5);
- return Instant.ofEpochMilli(time);
- }
-
- public void setInstant(Instant instant) {
- setInstant(instant, true, false, false, 10);
- }
-
- public void setInstant(
- Instant instant,
- boolean leapSecondsKnown,
- boolean clockFailure,
- boolean clockNotSynchronized,
- int timeAccuracy) {
- if (value == null) {
- value = new byte[8];
- }
-
- int secondsSinceEpoch = (int) (instant.toEpochMilli() / 1000L);
- int fractionOfSecond = (int) ((instant.toEpochMilli() % 1000L) / 1000.0 * (1 << 24));
-
- int timeQuality = timeAccuracy & 0x1f;
- if (leapSecondsKnown) {
- timeQuality = timeQuality | 0x80;
- }
- if (clockFailure) {
- timeQuality = timeQuality | 0x40;
- }
- if (clockNotSynchronized) {
- timeQuality = timeQuality | 0x20;
- }
-
- value =
- new byte[] {
- (byte) ((secondsSinceEpoch >> 24) & 0xff),
- (byte) ((secondsSinceEpoch >> 16) & 0xff),
- (byte) ((secondsSinceEpoch >> 8) & 0xff),
- (byte) (secondsSinceEpoch & 0xff),
- (byte) ((fractionOfSecond >> 16) & 0xff),
- (byte) ((fractionOfSecond >> 8) & 0xff),
- (byte) (fractionOfSecond & 0xff),
- (byte) timeQuality
- };
- }
-
- public byte[] getValue() {
- return value;
- }
-
- public void setValue(byte[] value) {
- if (value == null) {
- this.value = new byte[8];
- }
- this.value = value;
- }
-
- /**
- * The value TRUE of the attribute LeapSecondsKnown shall indicate that the value for
- * SecondSinceEpoch takes into account all leap seconds occurred. If it is FALSE then the value
- * does not take into account the leap seconds that occurred before the initialization of the time
- * source of the device.
- *
- * @return TRUE of the attribute LeapSecondsKnown shall indicate that the value for
- * SecondSinceEpoch takes into account all leap seconds occurred
- */
- public boolean getLeapSecondsKnown() {
- return ((value[7] & 0x80) != 0);
- }
-
- /**
- * The attribute clockFailure shall indicate that the time source of the sending device is
- * unreliable. The value of the TimeStamp shall be ignored.
- *
- * @return true if the time source of the sending device is unreliable
- */
- public boolean getClockFailure() {
- return ((value[7] & 0x40) != 0);
- }
-
- /**
- * The attribute clockNotSynchronized shall indicate that the time source of the sending device is
- * not synchronized with the external UTC time.
- *
- * @return true if the time source of the sending device is not synchronized
- */
- public boolean getClockNotSynchronized() {
- return ((value[7] & 0x20) != 0);
- }
-
- /**
- * The attribute TimeAccuracy shall represent the time accuracy class of the time source of the
- * sending device relative to the external UTC time. The timeAccuracy classes shall represent the
- * number of significant bits in the FractionOfSecond
- *
- *
If the time is set via Java {@link Date} objects, the accuracy is 1 ms, that is a
- * timeAccuracy value of 10.
- *
- * @return the time accuracy
- */
- public int getTimeAccuracy() {
- return ((value[7] & 0x1f));
- }
-
- /** Sets Timestamp the empty byte array (indicating an invalid Timestamp) */
- @Override
- public void setDefault() {
- value = new byte[8];
- }
-
- /** Sets Timestamp to current time */
- public void setCurrentTime() {
- setInstant(Instant.now());
- }
-
- @Override
- public BdaTimestamp copy() {
- BdaTimestamp copy = new BdaTimestamp(objectReference, fc, sAddr, dchg, dupd);
- byte[] valueCopy = new byte[value.length];
- System.arraycopy(value, 0, valueCopy, 0, value.length);
- copy.setValue(valueCopy);
- if (mirror == null) {
- copy.mirror = this;
- } else {
- copy.mirror = mirror;
- }
- return copy;
- }
-
- @Override
- Data getMmsDataObj() {
- Data data = new Data();
- data.setUtcTime(new UtcTime(value));
- return data;
- }
-
- @Override
- void setValueFromMmsDataObj(Data data) throws ServiceError {
- if (data.getUtcTime() == null) {
- throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: utc_time/timestamp");
- }
- value = data.getUtcTime().value;
- }
-
- @Override
- TypeDescription getMmsTypeSpec() {
- TypeDescription typeDescription = new TypeDescription();
- typeDescription.setUtcTime(new BerNull());
- return typeDescription;
- }
-
- @Override
- public String toString() {
- return getReference().toString() + ": " + getInstant();
- }
-
- @Override
- public String getValueString() {
- return getInstant().toString();
- }
+ private volatile byte[] value;
+
+ public BdaTimestamp(
+ ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) {
+ super(objectReference, fc, sAddr, dchg, dupd);
+ basicType = BdaType.TIMESTAMP;
+ setDefault();
+ }
+
+ /**
+ * The SecondSinceEpoch shall be the interval in seconds continuously counted from the epoch
+ * 1970-01-01 00:00:00 UTC
+ */
+
+ /**
+ * Returns the value as the number of seconds since epoch 1970-01-01 00:00:00 UTC
+ *
+ * @return the number of seconds since epoch 1970-01-01 00:00:00 UTC
+ */
+ private long getSecondsSinceEpoch() {
+ return ((0xffL & value[0]) << 24
+ | (0xffL & value[1]) << 16
+ | (0xffL & value[2]) << 8
+ | (0xffL & value[3]));
+ }
+
+ /**
+ * The attribute FractionOfSecond shall be the fraction of the current second when the value of
+ * the TimeStamp has been determined. The fraction of second shall be calculated as
+ * (SUM from I = 0 to 23 of bi*2**–(I+1) s). NOTE 1 The resolution is the smallest unit by
+ * which the time stamp is updated. The 24 bits of the integer provides 1 out of 16777216 counts
+ * as the smallest unit; calculated by 1/2**24 which equals approximately 60 ns.
+ *
+ *
NOTE 2 The resolution of a time stamp may be 1/2**1 (= 0,5 s) if only the first bit is used;
+ * or may be 1/2**2 (= 0,25 s) if the first two bits are used; or may be approximately 60 ns if
+ * all 24 bits are used. The resolution provided by an IED is outside the scope of this standard.
+ *
+ * @return the fraction of seconds
+ */
+ private int getFractionOfSecond() {
+ return ((0xff & value[4]) << 16 | (0xff & value[5]) << 8 | (0xff & value[6]));
+ }
+
+ public Date getDate() {
+ if (value == null || value.length == 0) {
+ return null;
+ }
+ long time =
+ getSecondsSinceEpoch() * 1000L
+ + (long) (((float) getFractionOfSecond()) / (1 << 24) * 1000 + 0.5);
+ return new Date(time);
+ }
+
+ public void setDate(Date date) {
+ if (value == null) {
+ value = new byte[8];
+ }
+
+ int secondsSinceEpoch = (int) (date.getTime() / 1000L);
+ int fractionOfSecond = (int) ((date.getTime() % 1000L) / 1000.0 * (1 << 24));
+
+ // 0x8a = time accuracy of 10 and LeapSecondsKnown = true, ClockFailure
+ // = false, ClockNotSynchronized = false
+ value =
+ new byte[] {
+ (byte) ((secondsSinceEpoch >> 24) & 0xff),
+ (byte) ((secondsSinceEpoch >> 16) & 0xff),
+ (byte) ((secondsSinceEpoch >> 8) & 0xff),
+ (byte) (secondsSinceEpoch & 0xff),
+ (byte) ((fractionOfSecond >> 16) & 0xff),
+ (byte) ((fractionOfSecond >> 8) & 0xff),
+ (byte) (fractionOfSecond & 0xff),
+ (byte) 0x8a
+ };
+ }
+
+
+
+ @Override
+ public void setValueFrom(BasicDataAttribute bda) {
+ byte[] srcValue = ((BdaTimestamp) bda).getValue();
+ if (value.length != srcValue.length) {
+ value = new byte[srcValue.length];
+ }
+ System.arraycopy(srcValue, 0, value, 0, srcValue.length);
+ }
+
+ public Instant getInstant() {
+ if (value == null || value.length == 0) {
+ return null;
+ }
+ long time =
+ getSecondsSinceEpoch() * 1000L
+ + (long) (((float) getFractionOfSecond()) / (1 << 24) * 1000 + 0.5);
+ return Instant.ofEpochMilli(time);
+ }
+
+ public void setInstant(Instant instant) {
+ setInstant(instant, true, false, false, 10);
+ }
+
+ public void setInstant(
+ Instant instant,
+ boolean leapSecondsKnown,
+ boolean clockFailure,
+ boolean clockNotSynchronized,
+ int timeAccuracy) {
+ if (value == null) {
+ value = new byte[8];
+ }
+
+ int secondsSinceEpoch = (int) (instant.toEpochMilli() / 1000L);
+ int fractionOfSecond = (int) ((instant.toEpochMilli() % 1000L) / 1000.0 * (1 << 24));
+
+ int timeQuality = timeAccuracy & 0x1f;
+ if (leapSecondsKnown) {
+ timeQuality = timeQuality | 0x80;
+ }
+ if (clockFailure) {
+ timeQuality = timeQuality | 0x40;
+ }
+ if (clockNotSynchronized) {
+ timeQuality = timeQuality | 0x20;
+ }
+
+ value =
+ new byte[]{
+ (byte) ((secondsSinceEpoch >> 24) & 0xff),
+ (byte) ((secondsSinceEpoch >> 16) & 0xff),
+ (byte) ((secondsSinceEpoch >> 8) & 0xff),
+ (byte) (secondsSinceEpoch & 0xff),
+ (byte) ((fractionOfSecond >> 16) & 0xff),
+ (byte) ((fractionOfSecond >> 8) & 0xff),
+ (byte) (fractionOfSecond & 0xff),
+ (byte) timeQuality
+ };
+ }
+
+ public byte[] getValue() {
+ return value;
+ }
+
+ public void setValue(byte[] value) {
+ if (value == null) {
+ this.value = new byte[8];
+ }
+ this.value = value;
+ }
+
+ /**
+ * The value TRUE of the attribute LeapSecondsKnown shall indicate that the value for
+ * SecondSinceEpoch takes into account all leap seconds occurred. If it is FALSE then the value
+ * does not take into account the leap seconds that occurred before the initialization of the time
+ * source of the device.
+ *
+ * @return TRUE of the attribute LeapSecondsKnown shall indicate that the value for
+ * SecondSinceEpoch takes into account all leap seconds occurred
+ */
+ public boolean getLeapSecondsKnown() {
+ return ((value[7] & 0x80) != 0);
+ }
+
+ /**
+ * The attribute clockFailure shall indicate that the time source of the sending device is
+ * unreliable. The value of the TimeStamp shall be ignored.
+ *
+ * @return true if the time source of the sending device is unreliable
+ */
+ public boolean getClockFailure() {
+ return ((value[7] & 0x40) != 0);
+ }
+
+ /**
+ * The attribute clockNotSynchronized shall indicate that the time source of the sending device is
+ * not synchronized with the external UTC time.
+ *
+ * @return true if the time source of the sending device is not synchronized
+ */
+ public boolean getClockNotSynchronized() {
+ return ((value[7] & 0x20) != 0);
+ }
+
+ /**
+ * The attribute TimeAccuracy shall represent the time accuracy class of the time source of the
+ * sending device relative to the external UTC time. The timeAccuracy classes shall represent the
+ * number of significant bits in the FractionOfSecond
+ *
+ *
If the time is set via Java {@link Date} objects, the accuracy is 1 ms, that is a
+ * timeAccuracy value of 10.
+ *
+ * @return the time accuracy
+ */
+ public int getTimeAccuracy() {
+ return ((value[7] & 0x1f));
+ }
+
+ /**
+ * Sets Timestamp the empty byte array (indicating an invalid Timestamp)
+ */
+ @Override
+ public void setDefault() {
+ value = new byte[8];
+ }
+
+ /**
+ * Sets Timestamp to current time
+ */
+ public void setCurrentTime() {
+ setInstant(Instant.now());
+ }
+
+ @Override
+ public BdaTimestamp copy() {
+ BdaTimestamp copy = new BdaTimestamp(objectReference, fc, sAddr, dchg, dupd);
+ byte[] valueCopy = new byte[value.length];
+ System.arraycopy(value, 0, valueCopy, 0, value.length);
+ copy.setValue(valueCopy);
+ if (mirror == null) {
+ copy.mirror = this;
+ } else {
+ copy.mirror = mirror;
+ }
+ return copy;
+ }
+
+ @Override
+ Data getMmsDataObj() {
+ Data data = new Data();
+ data.setUtcTime(new UtcTime(value));
+ return data;
+ }
+
+ @Override
+ void setValueFromMmsDataObj(Data data) throws ServiceError {
+ if (data.getUtcTime() == null) {
+ throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: utc_time/timestamp");
+ }
+ value = data.getUtcTime().value;
+ }
+
+ @Override
+ TypeDescription getMmsTypeSpec() {
+ TypeDescription typeDescription = new TypeDescription();
+ typeDescription.setUtcTime(new BerNull());
+ return typeDescription;
+ }
+
+ @Override
+ public String toString() {
+ return getReference().toString() + ": " + getInstant();
+ }
+
+ @Override
+ public String getValueString() {
+ return getInstant().toString();
+ }
}
diff --git a/src/main/java/com/beanit/iec61850bean/FcDataObject.java b/src/main/java/com/beanit/iec61850bean/FcDataObject.java
index 8b0cf5a..4f6b2e3 100644
--- a/src/main/java/com/beanit/iec61850bean/FcDataObject.java
+++ b/src/main/java/com/beanit/iec61850bean/FcDataObject.java
@@ -14,6 +14,7 @@
package com.beanit.iec61850bean;
import com.beanit.iec61850bean.internal.mms.asn1.Data;
+
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
@@ -30,66 +31,89 @@ import java.util.List;
*/
public class FcDataObject extends FcModelNode {
- public FcDataObject(ObjectReference objectReference, Fc fc, List children) {
+ private final List fcModelNodes;
+ private String doType;
+ private String cdc;
- this.children = new LinkedHashMap<>((int) ((children.size() / 0.75) + 1));
- this.objectReference = objectReference;
- for (ModelNode child : children) {
- this.children.put(child.getReference().getName(), child);
- child.setParent(this);
- }
- this.fc = fc;
- }
-
- @Override
- public FcDataObject copy() {
- List childCopies = new ArrayList<>(children.size());
- for (ModelNode childNode : children.values()) {
- childCopies.add((FcModelNode) childNode.copy());
+
+ public FcDataObject(ObjectReference objectReference, Fc fc, List children) {
+ this.fcModelNodes = children;
+ super.setDataAttributes(children);
+ this.children = new LinkedHashMap<>((int) ((children.size() / 0.75) + 1));
+ this.objectReference = objectReference;
+
+ for (ModelNode child : children) {
+ this.children.put(child.getReference().getName(), child);
+ child.setParent(this);
+ }
+ this.fc = fc;
}
- return new FcDataObject(objectReference, fc, childCopies);
- }
-
- @Override
- Data getMmsDataObj() {
- Data.Structure dataStructure = new Data.Structure();
- List seq = dataStructure.getData();
-
- for (ModelNode modelNode : getChildren()) {
- Data child = modelNode.getMmsDataObj();
- if (child == null) {
- throw new IllegalArgumentException(
- "Unable to convert Child: " + modelNode.objectReference + " to MMS Data Object.");
- }
- seq.add(child);
+
+ @Override
+ public FcDataObject copy() {
+ List childCopies = new ArrayList<>(children.size());
+ for (ModelNode childNode : children.values()) {
+ childCopies.add((FcModelNode) childNode.copy());
+ }
+ return new FcDataObject(objectReference, fc, childCopies);
}
- if (seq.size() == 0) {
- throw new IllegalArgumentException(
- "Converting ModelNode: "
- + objectReference
- + " to MMS Data Object resulted in Sequence of size zero.");
+
+ @Override
+ Data getMmsDataObj() {
+ Data.Structure dataStructure = new Data.Structure();
+ List seq = dataStructure.getData();
+
+ for (ModelNode modelNode : getChildren()) {
+ Data child = modelNode.getMmsDataObj();
+ if (child == null) {
+ throw new IllegalArgumentException(
+ "Unable to convert Child: " + modelNode.objectReference + " to MMS Data Object.");
+ }
+ seq.add(child);
+ }
+ if (seq.size() == 0) {
+ throw new IllegalArgumentException(
+ "Converting ModelNode: "
+ + objectReference
+ + " to MMS Data Object resulted in Sequence of size zero.");
+ }
+
+ Data data = new Data();
+ data.setStructure(dataStructure);
+
+ return data;
}
- Data data = new Data();
- data.setStructure(dataStructure);
+ @Override
+ void setValueFromMmsDataObj(Data data) throws ServiceError {
+ if (data.getStructure() == null) {
+ throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: structure");
+ }
+ if (data.getStructure().getData().size() != children.size()) {
+ throw new ServiceError(
+ ServiceError.TYPE_CONFLICT,
+ "expected type: structure with " + children.size() + " elements");
+ }
+
+ Iterator iterator = data.getStructure().getData().iterator();
+ for (ModelNode child : children.values()) {
+ child.setValueFromMmsDataObj(iterator.next());
+ }
+ }
- return data;
- }
+ public String getDoType() {
+ return doType;
+ }
- @Override
- void setValueFromMmsDataObj(Data data) throws ServiceError {
- if (data.getStructure() == null) {
- throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: structure");
+ public void setDoType(String doType) {
+ this.doType = doType;
}
- if (data.getStructure().getData().size() != children.size()) {
- throw new ServiceError(
- ServiceError.TYPE_CONFLICT,
- "expected type: structure with " + children.size() + " elements");
+
+ public String getCdc() {
+ return cdc;
}
- Iterator iterator = data.getStructure().getData().iterator();
- for (ModelNode child : children.values()) {
- child.setValueFromMmsDataObj(iterator.next());
+ public void setCdc(String cdc) {
+ this.cdc = cdc;
}
- }
}
diff --git a/src/main/java/com/beanit/iec61850bean/FcModelNode.java b/src/main/java/com/beanit/iec61850bean/FcModelNode.java
index e414979..aa6ae9c 100644
--- a/src/main/java/com/beanit/iec61850bean/FcModelNode.java
+++ b/src/main/java/com/beanit/iec61850bean/FcModelNode.java
@@ -13,240 +13,373 @@
*/
package com.beanit.iec61850bean;
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-import com.beanit.iec61850bean.internal.mms.asn1.AlternateAccess;
-import com.beanit.iec61850bean.internal.mms.asn1.AlternateAccessSelection;
+import com.beanit.iec61850bean.internal.mms.asn1.*;
import com.beanit.iec61850bean.internal.mms.asn1.AlternateAccessSelection.SelectAccess;
import com.beanit.iec61850bean.internal.mms.asn1.AlternateAccessSelection.SelectAccess.Component;
-import com.beanit.iec61850bean.internal.mms.asn1.BasicIdentifier;
-import com.beanit.iec61850bean.internal.mms.asn1.Identifier;
-import com.beanit.iec61850bean.internal.mms.asn1.ObjectName;
-import com.beanit.iec61850bean.internal.mms.asn1.Unsigned32;
-import com.beanit.iec61850bean.internal.mms.asn1.VariableDefs;
-import com.beanit.iec61850bean.internal.mms.asn1.VariableSpecification;
+
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
public abstract class FcModelNode extends ModelNode {
- Fc fc;
- private VariableDefs.SEQUENCE variableDef = null;
- private ServerAssociation selected = null;
- private TimerTask task = null;
+ Fc fc;
+ private VariableDefs.SEQUENCE variableDef = null;
+ private ServerAssociation selected = null;
+ private TimerTask task = null;
+
+ private String daType;
+ private BdaType basicType = null;
+ private String sAddr;
+ private String daiVal;
+ private boolean dchg;
+ private boolean dupd;
+ private boolean qchg;
+
+ private String bType;
+ private List bdas;
+
+ private short valueShort;
+ private byte[] valueBytes;
+ private byte valueByte;
+ private boolean valueBoolean;
+ private int valueInt;
+ private long valueLong;
+
+ public Fc getFc() {
+ return fc;
+ }
- public Fc getFc() {
- return fc;
- }
+ boolean select(ServerAssociation association, Timer timer) {
+ if (selected != null) {
+ if (selected != association) {
+ return false;
+ }
+ } else {
+ selected = association;
+ association.selects.add(this);
+ }
- boolean select(ServerAssociation association, Timer timer) {
- if (selected != null) {
- if (selected != association) {
- return false;
- }
- } else {
- selected = association;
- association.selects.add(this);
- }
+ ModelNode sboTimeoutNode =
+ association.serverModel.findModelNode(objectReference, Fc.CF).getChild("sboTimeout");
- ModelNode sboTimeoutNode =
- association.serverModel.findModelNode(objectReference, Fc.CF).getChild("sboTimeout");
+ if (sboTimeoutNode == null) {
+ return true;
+ }
- if (sboTimeoutNode == null) {
- return true;
- }
+ long sboTimeout = ((BdaInt32U) sboTimeoutNode).getValue();
- long sboTimeout = ((BdaInt32U) sboTimeoutNode).getValue();
+ if (sboTimeout == 0) {
+ return true;
+ }
- if (sboTimeout == 0) {
- return true;
- }
+ class SelectResetTask extends TimerTask {
+ ServerAssociation association;
+
+ SelectResetTask(ServerAssociation association) {
+ this.association = association;
+ }
+
+ @Override
+ public void run() {
+ synchronized (association.serverModel) {
+ if (task == this) {
+ task = null;
+ deselectAndRemove(association);
+ }
+ }
+ }
+ }
- class SelectResetTask extends TimerTask {
- ServerAssociation association;
+ if (task != null) {
+ task.cancel();
+ }
- SelectResetTask(ServerAssociation association) {
- this.association = association;
- }
+ task = new SelectResetTask(association);
+ timer.schedule(task, sboTimeout);
+
+ return true;
+ }
- @Override
- public void run() {
- synchronized (association.serverModel) {
- if (task == this) {
+ void deselectAndRemove(ServerAssociation association) {
+ selected = null;
+ if (task != null) {
+ task.cancel();
task = null;
- deselectAndRemove(association);
- }
}
- }
+ association.selects.remove(this);
}
- if (task != null) {
- task.cancel();
+ void deselect() {
+ selected = null;
+ if (task != null) {
+ task.cancel();
+ task = null;
+ }
}
- task = new SelectResetTask(association);
- timer.schedule(task, sboTimeout);
-
- return true;
- }
-
- void deselectAndRemove(ServerAssociation association) {
- selected = null;
- if (task != null) {
- task.cancel();
- task = null;
+ boolean isSelected() {
+ return selected != null;
}
- association.selects.remove(this);
- }
- void deselect() {
- selected = null;
- if (task != null) {
- task.cancel();
- task = null;
+ boolean isSelectedBy(ServerAssociation association) {
+ return selected == association;
}
- }
- boolean isSelected() {
- return selected != null;
- }
+ VariableDefs.SEQUENCE getMmsVariableDef() {
+
+ if (variableDef != null) {
+ return variableDef;
+ }
- boolean isSelectedBy(ServerAssociation association) {
- return selected == association;
- }
+ AlternateAccess alternateAccess = null;
- VariableDefs.SEQUENCE getMmsVariableDef() {
+ StringBuilder preArrayIndexItemId = new StringBuilder(objectReference.get(1));
+ preArrayIndexItemId.append("$");
+ preArrayIndexItemId.append(fc);
- if (variableDef != null) {
- return variableDef;
- }
+ int arrayIndexPosition = objectReference.getArrayIndexPosition();
+ if (arrayIndexPosition != -1) {
- AlternateAccess alternateAccess = null;
+ for (int i = 2; i < arrayIndexPosition; i++) {
+ preArrayIndexItemId.append("$");
+ preArrayIndexItemId.append(objectReference.get(i));
+ }
- StringBuilder preArrayIndexItemId = new StringBuilder(objectReference.get(1));
- preArrayIndexItemId.append("$");
- preArrayIndexItemId.append(fc);
+ alternateAccess = new AlternateAccess();
+ List subSeqOfAlternateAccess = alternateAccess.getCHOICE();
+ Unsigned32 indexBerInteger =
+ new Unsigned32(Integer.parseInt(objectReference.get(arrayIndexPosition)));
- int arrayIndexPosition = objectReference.getArrayIndexPosition();
- if (arrayIndexPosition != -1) {
+ if (arrayIndexPosition < (objectReference.size() - 1)) {
+ // this reference points to a sub-node of an array element
- for (int i = 2; i < arrayIndexPosition; i++) {
- preArrayIndexItemId.append("$");
- preArrayIndexItemId.append(objectReference.get(i));
- }
+ StringBuilder postArrayIndexItemId =
+ new StringBuilder(objectReference.get(arrayIndexPosition + 1));
+
+ for (int i = (arrayIndexPosition + 2); i < objectReference.size(); i++) {
+ postArrayIndexItemId.append("$");
+ postArrayIndexItemId.append(objectReference.get(i));
+ }
+
+ BasicIdentifier subIndexReference =
+ new BasicIdentifier(postArrayIndexItemId.toString().getBytes(UTF_8));
+
+ AlternateAccessSelection.SelectAccess subIndexReferenceSelectAccess =
+ new AlternateAccessSelection.SelectAccess();
+ Component component = new Component();
+ component.setBasic(subIndexReference);
+ subIndexReferenceSelectAccess.setComponent(component);
+
+ AlternateAccessSelection subIndexReferenceAlternateAccessSelection =
+ new AlternateAccessSelection();
+ subIndexReferenceAlternateAccessSelection.setSelectAccess(subIndexReferenceSelectAccess);
+
+ AlternateAccess.CHOICE subIndexReferenceAlternateAccessSubChoice =
+ new AlternateAccess.CHOICE();
+ subIndexReferenceAlternateAccessSubChoice.setUnnamed(
+ subIndexReferenceAlternateAccessSelection);
+
+ AlternateAccess subIndexReferenceAlternateAccess = new AlternateAccess();
+
+ List subIndexReferenceAlternateAccessSubSeqOf =
+ subIndexReferenceAlternateAccess.getCHOICE();
+ subIndexReferenceAlternateAccessSubSeqOf.add(subIndexReferenceAlternateAccessSubChoice);
+
+ // set array index:
+
+ AlternateAccessSelection.SelectAlternateAccess.AccessSelection indexAccessSelectionChoice =
+ new AlternateAccessSelection.SelectAlternateAccess.AccessSelection();
+ indexAccessSelectionChoice.setIndex(indexBerInteger);
+
+ AlternateAccessSelection.SelectAlternateAccess indexAndLowerReferenceSelectAlternateAccess =
+ new AlternateAccessSelection.SelectAlternateAccess();
+ indexAndLowerReferenceSelectAlternateAccess.setAccessSelection(indexAccessSelectionChoice);
+ indexAndLowerReferenceSelectAlternateAccess.setAlternateAccess(
+ subIndexReferenceAlternateAccess);
+
+ AlternateAccessSelection indexAndLowerReferenceAlternateAccessSelection =
+ new AlternateAccessSelection();
+ indexAndLowerReferenceAlternateAccessSelection.setSelectAlternateAccess(
+ indexAndLowerReferenceSelectAlternateAccess);
+
+ AlternateAccess.CHOICE indexAndLowerReferenceAlternateAccessChoice =
+ new AlternateAccess.CHOICE();
+ indexAndLowerReferenceAlternateAccessChoice.setUnnamed(
+ indexAndLowerReferenceAlternateAccessSelection);
+
+ subSeqOfAlternateAccess.add(indexAndLowerReferenceAlternateAccessChoice);
+
+ } else {
+ SelectAccess selectAccess = new SelectAccess();
+ selectAccess.setIndex(indexBerInteger);
+
+ AlternateAccessSelection alternateAccessSelection = new AlternateAccessSelection();
+ alternateAccessSelection.setSelectAccess(selectAccess);
+
+ AlternateAccess.CHOICE alternateAccessChoice = new AlternateAccess.CHOICE();
+ alternateAccessChoice.setUnnamed(alternateAccessSelection);
+
+ subSeqOfAlternateAccess.add(alternateAccessChoice);
+ }
- alternateAccess = new AlternateAccess();
- List subSeqOfAlternateAccess = alternateAccess.getCHOICE();
- Unsigned32 indexBerInteger =
- new Unsigned32(Integer.parseInt(objectReference.get(arrayIndexPosition)));
+ } else {
- if (arrayIndexPosition < (objectReference.size() - 1)) {
- // this reference points to a sub-node of an array element
+ for (int i = 2; i < objectReference.size(); i++) {
+ preArrayIndexItemId.append("$");
+ preArrayIndexItemId.append(objectReference.get(i));
+ }
+ }
+
+ ObjectName.DomainSpecific domainSpecificObjectName = new ObjectName.DomainSpecific();
+ domainSpecificObjectName.setDomainID(new Identifier(objectReference.get(0).getBytes(UTF_8)));
+ domainSpecificObjectName.setItemID(
+ new Identifier(preArrayIndexItemId.toString().getBytes(UTF_8)));
+
+ ObjectName objectName = new ObjectName();
+ objectName.setDomainSpecific(domainSpecificObjectName);
- StringBuilder postArrayIndexItemId =
- new StringBuilder(objectReference.get(arrayIndexPosition + 1));
+ VariableSpecification varSpec = new VariableSpecification();
+ varSpec.setName(objectName);
+
+ variableDef = new VariableDefs.SEQUENCE();
+ variableDef.setAlternateAccess(alternateAccess);
+ variableDef.setVariableSpecification(varSpec);
+
+ return variableDef;
+ }
- for (int i = (arrayIndexPosition + 2); i < objectReference.size(); i++) {
- postArrayIndexItemId.append("$");
- postArrayIndexItemId.append(objectReference.get(i));
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(getReference().toString()).append(" [").append(fc).append("]");
+ for (ModelNode childNode : children.values()) {
+ sb.append("\n");
+ sb.append(childNode.toString());
}
+ return sb.toString();
+ }
- BasicIdentifier subIndexReference =
- new BasicIdentifier(postArrayIndexItemId.toString().getBytes(UTF_8));
+ public String getDaType() {
+ return daType;
+ }
- AlternateAccessSelection.SelectAccess subIndexReferenceSelectAccess =
- new AlternateAccessSelection.SelectAccess();
- Component component = new Component();
- component.setBasic(subIndexReference);
- subIndexReferenceSelectAccess.setComponent(component);
+ public void setDaType(String daType) {
+ this.daType = daType;
+ }
+
+ public BdaType getBasicType() {
+ return basicType;
+ }
+
+ public void setBasicType(BdaType basicType) {
+ this.basicType = basicType;
+ }
+
+ public String getsAddr() {
+ return sAddr;
+ }
+
+ public void setsAddr(String sAddr) {
+ this.sAddr = sAddr;
+ }
+
+ public String getDaiVal() {
+ return daiVal;
+ }
+
+ public void setDaiVal(String daiVal) {
+ this.daiVal = daiVal;
+ }
- AlternateAccessSelection subIndexReferenceAlternateAccessSelection =
- new AlternateAccessSelection();
- subIndexReferenceAlternateAccessSelection.setSelectAccess(subIndexReferenceSelectAccess);
+ public boolean isDchg() {
+ return dchg;
+ }
- AlternateAccess.CHOICE subIndexReferenceAlternateAccessSubChoice =
- new AlternateAccess.CHOICE();
- subIndexReferenceAlternateAccessSubChoice.setUnnamed(
- subIndexReferenceAlternateAccessSelection);
+ public void setDchg(boolean dchg) {
+ this.dchg = dchg;
+ }
- AlternateAccess subIndexReferenceAlternateAccess = new AlternateAccess();
+ public boolean isDupd() {
+ return dupd;
+ }
- List subIndexReferenceAlternateAccessSubSeqOf =
- subIndexReferenceAlternateAccess.getCHOICE();
- subIndexReferenceAlternateAccessSubSeqOf.add(subIndexReferenceAlternateAccessSubChoice);
+ public void setDupd(boolean dupd) {
+ this.dupd = dupd;
+ }
- // set array index:
+ public boolean isQchg() {
+ return qchg;
+ }
- AlternateAccessSelection.SelectAlternateAccess.AccessSelection indexAccessSelectionChoice =
- new AlternateAccessSelection.SelectAlternateAccess.AccessSelection();
- indexAccessSelectionChoice.setIndex(indexBerInteger);
+ public void setQchg(boolean qchg) {
+ this.qchg = qchg;
+ }
- AlternateAccessSelection.SelectAlternateAccess indexAndLowerReferenceSelectAlternateAccess =
- new AlternateAccessSelection.SelectAlternateAccess();
- indexAndLowerReferenceSelectAlternateAccess.setAccessSelection(indexAccessSelectionChoice);
- indexAndLowerReferenceSelectAlternateAccess.setAlternateAccess(
- subIndexReferenceAlternateAccess);
+ public String getbType() {
+ return bType;
+ }
- AlternateAccessSelection indexAndLowerReferenceAlternateAccessSelection =
- new AlternateAccessSelection();
- indexAndLowerReferenceAlternateAccessSelection.setSelectAlternateAccess(
- indexAndLowerReferenceSelectAlternateAccess);
+ public void setbType(String bType) {
+ this.bType = bType;
+ }
- AlternateAccess.CHOICE indexAndLowerReferenceAlternateAccessChoice =
- new AlternateAccess.CHOICE();
- indexAndLowerReferenceAlternateAccessChoice.setUnnamed(
- indexAndLowerReferenceAlternateAccessSelection);
+ public List getDataAttributes() {
+ return bdas;
+ }
- subSeqOfAlternateAccess.add(indexAndLowerReferenceAlternateAccessChoice);
+ public FcModelNode setDataAttributes(List bdas) {
+ this.bdas = bdas;
+ return this;
+ }
- } else {
- SelectAccess selectAccess = new SelectAccess();
- selectAccess.setIndex(indexBerInteger);
+ public short getValueShort() {
+ return valueShort;
+ }
- AlternateAccessSelection alternateAccessSelection = new AlternateAccessSelection();
- alternateAccessSelection.setSelectAccess(selectAccess);
+ public void setValueShort(short valueShort) {
+ this.valueShort = valueShort;
+ }
- AlternateAccess.CHOICE alternateAccessChoice = new AlternateAccess.CHOICE();
- alternateAccessChoice.setUnnamed(alternateAccessSelection);
+ public byte[] getValueBytes() {
+ return valueBytes;
+ }
- subSeqOfAlternateAccess.add(alternateAccessChoice);
- }
+ public void setValueBytes(byte[] valueBytes) {
+ this.valueBytes = valueBytes;
+ }
- } else {
+ public byte getValueByte() {
+ return valueByte;
+ }
- for (int i = 2; i < objectReference.size(); i++) {
- preArrayIndexItemId.append("$");
- preArrayIndexItemId.append(objectReference.get(i));
- }
+ public void setValueByte(byte valueByte) {
+ this.valueByte = valueByte;
}
- ObjectName.DomainSpecific domainSpecificObjectName = new ObjectName.DomainSpecific();
- domainSpecificObjectName.setDomainID(new Identifier(objectReference.get(0).getBytes(UTF_8)));
- domainSpecificObjectName.setItemID(
- new Identifier(preArrayIndexItemId.toString().getBytes(UTF_8)));
+ public boolean isValueBoolean() {
+ return valueBoolean;
+ }
- ObjectName objectName = new ObjectName();
- objectName.setDomainSpecific(domainSpecificObjectName);
+ public void setValueBoolean(boolean valueBoolean) {
+ this.valueBoolean = valueBoolean;
+ }
- VariableSpecification varSpec = new VariableSpecification();
- varSpec.setName(objectName);
+ public int getValueInt() {
+ return valueInt;
+ }
- variableDef = new VariableDefs.SEQUENCE();
- variableDef.setAlternateAccess(alternateAccess);
- variableDef.setVariableSpecification(varSpec);
+ public void setValueInt(int valueInt) {
+ this.valueInt = valueInt;
+ }
- return variableDef;
- }
+ public long getValueLong() {
+ return valueLong;
+ }
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append(getReference().toString()).append(" [").append(fc).append("]");
- for (ModelNode childNode : children.values()) {
- sb.append("\n");
- sb.append(childNode.toString());
+ public void setValueLong(long valueLong) {
+ this.valueLong = valueLong;
}
- return sb.toString();
- }
}
diff --git a/src/main/java/com/beanit/iec61850bean/LogicalDevice.java b/src/main/java/com/beanit/iec61850bean/LogicalDevice.java
index c67bfe6..d46d6e6 100644
--- a/src/main/java/com/beanit/iec61850bean/LogicalDevice.java
+++ b/src/main/java/com/beanit/iec61850bean/LogicalDevice.java
@@ -19,7 +19,11 @@ import java.util.List;
public final class LogicalDevice extends ModelNode {
+ private final List logicalNodes;
+ private String ldInst;
+
public LogicalDevice(ObjectReference objectReference, List logicalNodes) {
+ this.logicalNodes = logicalNodes;
children = new LinkedHashMap<>((int) ((logicalNodes.size() / 0.75) + 1));
this.objectReference = objectReference;
for (LogicalNode logicalNode : logicalNodes) {
@@ -36,4 +40,16 @@ public final class LogicalDevice extends ModelNode {
}
return new LogicalDevice(objectReference, childCopies);
}
+
+ public List getLogicalNodes() {
+ return logicalNodes;
+ }
+
+ public String getLdInst() {
+ return ldInst;
+ }
+
+ public void setLdInst(String ldInst) {
+ this.ldInst = ldInst;
+ }
}
diff --git a/src/main/java/com/beanit/iec61850bean/LogicalNode.java b/src/main/java/com/beanit/iec61850bean/LogicalNode.java
index c5f9e2a..38393f7 100644
--- a/src/main/java/com/beanit/iec61850bean/LogicalNode.java
+++ b/src/main/java/com/beanit/iec61850bean/LogicalNode.java
@@ -28,7 +28,14 @@ public final class LogicalNode extends ModelNode {
private final Map urcbs = new HashMap<>();
private final Map brcbs = new HashMap<>();
+ private final List dataObjects;
+ private String prefix;
+ private String lnClass;
+ private String lnInst;
+ private String lnType;
+
public LogicalNode(ObjectReference objectReference, List fcDataObjects) {
+ this.dataObjects = fcDataObjects;
children = new LinkedHashMap<>();
for (Fc fc : Fc.values()) {
this.fcDataObjects.put(fc, new LinkedHashMap());
@@ -59,8 +66,7 @@ public final class LogicalNode extends ModelNode {
dataObjectsCopy.add((FcDataObject) obj.copy());
}
- LogicalNode copy = new LogicalNode(objectReference, dataObjectsCopy);
- return copy;
+ return new LogicalNode(objectReference, dataObjectsCopy);
}
public List getChildren(Fc fc) {
@@ -134,4 +140,36 @@ public final class LogicalNode extends ModelNode {
}
return sb.toString();
}
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public void setPrefix(String prefix) {
+ this.prefix = prefix;
+ }
+
+ public String getLnClass() {
+ return lnClass;
+ }
+
+ public void setLnClass(String lnClass) {
+ this.lnClass = lnClass;
+ }
+
+ public String getLnInst() {
+ return lnInst;
+ }
+
+ public void setLnInst(String lnInst) {
+ this.lnInst = lnInst;
+ }
+
+ public String getLnType() {
+ return lnType;
+ }
+
+ public void setLnType(String lnType) {
+ this.lnType = lnType;
+ }
}
diff --git a/src/main/java/com/beanit/iec61850bean/SclParser.java b/src/main/java/com/beanit/iec61850bean/SclParser.java
index a3468f1..e5b94da 100644
--- a/src/main/java/com/beanit/iec61850bean/SclParser.java
+++ b/src/main/java/com/beanit/iec61850bean/SclParser.java
@@ -41,6 +41,17 @@ public class SclParser {
private String iedConnectedAP;
ConnectionParam connectionParm;
private final Map iedConnectionMap = new HashMap<>();
+ private String iedManufacturer;
+ Map descMap;
+
+ private List ldsInsts;
+ private List ldsRefs;
+ private Set lnSet;
+ private Map> lns;
+ private final HashSet lnS = new HashSet<>();
+ private final Map cdcDOMap = new HashMap<>();
+ private Map daiDescMap;
+ private List logicalDevices;
private SclParser() {
}
@@ -125,6 +136,9 @@ public class SclParser {
Node nameAttribute = iedNode.getAttributes().getNamedItem("name");
+ Node manufacturerAttr = iedNode.getAttributes().getNamedItem("manufacturer");
+ iedManufacturer = manufacturerAttr.getNodeValue();
+
iedName = nameAttribute.getNodeValue();
if ((iedName == null) || (iedName.length() == 0)) {
throw new SclParseException("IED must have a name!");
@@ -242,6 +256,12 @@ public class SclParser {
if (element.getNodeName().equals("Server")) {
+ ldsInsts = new ArrayList<>();
+ ldsRefs = new ArrayList<>();
+ descMap = new HashMap<>();
+ daiDescMap = new HashMap<>();
+ logicalDevices = new ArrayList<>();
+
ServerModel server = createServerModel(element);
Node namedItem = iedServer.getAttributes().getNamedItem("name");
@@ -267,7 +287,9 @@ public class SclParser {
Node element = elements.item(i);
if (element.getNodeName().equals("LDevice")) {
+ lns = new HashMap<>();
logicalDevices.add(createNewLDevice(element));
+ this.logicalDevices.add(createNewLDevice(element));
}
}
@@ -285,6 +307,17 @@ public class SclParser {
dataSetDefs.clear();
serverModel.setConnectionParam(iedConnectionMap.get(iedName));
+ serverModel.setIedName(iedName);
+ serverModel.setIedManufacturer(iedManufacturer);
+ serverModel.setLns(lns);
+ serverModel.setLnS(lnS);
+ serverModel.setDos(cdcDOMap);
+
+ serverModel.setLdsInsts(ldsInsts);
+ serverModel.setLdsRefs(ldsRefs);
+ serverModel.setDescriptions(descMap);
+ serverModel.setdAIDescriptions(daiDescMap);
+ serverModel.setLogicalDevices(logicalDevices);
return serverModel;
}
@@ -311,15 +344,20 @@ public class SclParser {
throw new SclParseException("Required attribute \"inst\" in logical device not found!");
}
+ ldsInsts.add(inst);
+
NodeList elements = ldXmlNode.getChildNodes();
List logicalNodes = new ArrayList<>();
String ref;
if ((ldName != null) && (ldName.length() != 0)) {
ref = ldName;
+ ldsRefs.add(ref);
} else {
ref = iedName + inst;
+ ldsRefs.add(ref);
}
+ lnSet = new HashSet<>();
for (int i = 0; i < elements.getLength(); i++) {
Node element = elements.item(i);
@@ -328,8 +366,10 @@ public class SclParser {
logicalNodes.add(createNewLogicalNode(element, ref));
}
}
+ lns.put(ref, lnSet);
LogicalDevice lDevice = new LogicalDevice(new ObjectReference(ref), logicalNodes);
+ lDevice.setLdInst(inst);
return lDevice;
}
@@ -350,17 +390,24 @@ public class SclParser {
Node node = attributes.item(i);
String nodeName = node.getNodeName();
- if (nodeName.equals("inst")) {
- inst = node.getNodeValue();
- } else if (nodeName.equals("lnType")) {
- lnType = node.getNodeValue();
- } else if (nodeName.equals("lnClass")) {
- lnClass = node.getNodeValue();
- } else if (nodeName.equals("prefix")) {
- prefix = node.getNodeValue();
+ switch (nodeName) {
+ case "inst":
+ inst = node.getNodeValue();
+ break;
+ case "lnType":
+ lnType = node.getNodeValue();
+ break;
+ case "lnClass":
+ lnClass = node.getNodeValue();
+ break;
+ case "prefix":
+ prefix = node.getNodeValue();
+ break;
}
}
+ lnSet.add(prefix + lnClass + inst);
+
if (inst == null) {
throw new SclParseException("Required attribute \"inst\" not found!");
}
@@ -372,6 +419,7 @@ public class SclParser {
}
String ref = parentRef + '/' + prefix + lnClass + inst;
+ lnS.add(ref);
LnType lnTypeDef = typeDefinitions.getLNodeType(lnType);
@@ -390,6 +438,12 @@ public class SclParser {
NamedNodeMap doiAttributes = childNode.getAttributes();
Node nameAttribute = doiAttributes.getNamedItem("name");
+ Node cdcAttribute = doiAttributes.getNamedItem("desc");
+
+ if (cdcAttribute != null) {
+ descMap.put(ref + "." + nameAttribute.getNodeValue(), cdcAttribute.getNodeValue());
+ }
+
if (nameAttribute != null && nameAttribute.getNodeValue().equals(dobject.getName())) {
doiNodeFound = childNode;
}
@@ -397,7 +451,7 @@ public class SclParser {
}
dataObjects.addAll(
- createFcDataObjects(dobject.getName(), ref, dobject.getType(), doiNodeFound));
+ createFcDataObjects(dobject.getName(), ref, dobject.getType(), doiNodeFound, dobject.getType()));
}
// look for ReportControl
@@ -417,6 +471,12 @@ public class SclParser {
dataSetDefs.add(new LnSubDef(childNode, lNode));
}
}
+
+ lNode.setPrefix(prefix);
+ lNode.setLnClass(lnClass);
+ lNode.setLnInst(inst);
+ lNode.setLnType(lnType);
+
return lNode;
}
@@ -528,8 +588,7 @@ public class SclParser {
}
}
- DataSet dataSet = new DataSet(lNode.getReference().toString() + '.' + name, dsMembers, false);
- return dataSet;
+ return new DataSet(lNode.getReference().toString() + '.' + name, dsMembers, false);
}
private List createReportControlBlocks(Node xmlNode, String parentRef)
@@ -795,7 +854,7 @@ public class SclParser {
}
private List createFcDataObjects(
- String name, String parentRef, String doTypeID, Node doiNode) throws SclParseException {
+ String name, String parentRef, String doTypeID, Node doiNode, String type) throws SclParseException {
DoType doType = typeDefinitions.getDOType(doTypeID);
@@ -805,6 +864,10 @@ public class SclParser {
String ref = parentRef + '.' + name;
+ String cdc = doType.getCdc();
+
+ cdcDOMap.put(ref, cdc);
+
List childNodes = new ArrayList<>();
for (Da dattr : doType.das) {
@@ -812,10 +875,22 @@ public class SclParser {
// look for DAI node with the name of the DA
Node iNodeFound = findINode(doiNode, dattr.getName());
+ if (iNodeFound != null) {
+ NamedNodeMap daiAttributes = iNodeFound.getAttributes();
+ if (daiAttributes != null) {
+ Node nameAttribute = daiAttributes.getNamedItem("name");
+ Node cdcAttribute = daiAttributes.getNamedItem("desc");
+
+ if (cdcAttribute != null) {
+ daiDescMap.put(ref + "." + nameAttribute.getNodeValue(), cdcAttribute.getNodeValue());
+ }
+ }
+ }
+
if (dattr.getCount() >= 1) {
childNodes.add(createArrayOfDataAttributes(ref + '.' + dattr.getName(), dattr, iNodeFound));
} else {
- childNodes.add(
+ FcModelNode fcModelNode =
createDataAttribute(
ref + '.' + dattr.getName(),
dattr.getFc(),
@@ -823,7 +898,12 @@ public class SclParser {
iNodeFound,
false,
false,
- false));
+ false
+ );
+
+ fcModelNode.setbType(dattr.getbType());
+ fcModelNode.setDaType(dattr.getType());
+ childNodes.add(fcModelNode);
}
}
@@ -837,7 +917,7 @@ public class SclParser {
Node iNodeFound = findINode(doiNode, sdo.getName());
- childNodes.addAll(createFcDataObjects(sdo.getName(), ref, sdo.getType(), iNodeFound));
+ childNodes.addAll(createFcDataObjects(sdo.getName(), ref, sdo.getType(), iNodeFound, type));
}
Map> subFCDataMap = new LinkedHashMap<>();
@@ -855,7 +935,10 @@ public class SclParser {
for (Fc fc : Fc.values()) {
if (subFCDataMap.get(fc).size() > 0) {
- fcDataObjects.add(new FcDataObject(objectReference, fc, subFCDataMap.get(fc)));
+ FcDataObject fcDataObject = new FcDataObject(objectReference, fc, subFCDataMap.get(fc));
+ fcDataObject.setDoType(type);
+ fcDataObject.setCdc(cdc);
+ fcDataObjects.add(fcDataObject);
}
}
@@ -937,8 +1020,11 @@ public class SclParser {
Node iNodeFound = findINode(iXmlNode, bda.getName());
- subDataAttributes.add(
- createDataAttribute(ref + '.' + bda.getName(), fc, bda, iNodeFound, dchg, dupd, qchg));
+ FcModelNode fcModelNode = createDataAttribute(ref + '.' + bda.getName(), fc, bda, iNodeFound, dchg, dupd, qchg);
+ fcModelNode.setDaType(bda.getType());
+ fcModelNode.setbType(bda.getbType());
+
+ subDataAttributes.add(fcModelNode);
}
return new ConstructedDataAttribute(new ObjectReference(ref), fc, subDataAttributes);
}
@@ -1141,7 +1227,7 @@ public class SclParser {
BdaTimestamp bda = new BdaTimestamp(new ObjectReference(ref), fc, sAddr, dchg, dupd);
if (val != null) {
// TODO
- throw new SclParseException("parsing configured value for TIMESTAMP is not supported yet.");
+ bda.setDate(new Date(System.currentTimeMillis()));
}
return bda;
} else if (bType.equals("Enum")) {
diff --git a/src/main/java/com/beanit/iec61850bean/ServerModel.java b/src/main/java/com/beanit/iec61850bean/ServerModel.java
index 0330770..a13f073 100644
--- a/src/main/java/com/beanit/iec61850bean/ServerModel.java
+++ b/src/main/java/com/beanit/iec61850bean/ServerModel.java
@@ -28,6 +28,17 @@ public final class ServerModel extends ModelNode {
private final Map brcbs = new HashMap<>();
private ConnectionParam connectionParam;
+ private String iedName;
+ private String iedManufacturer;
+ private List ldsInsts;
+ private List ldsRefs;
+ private List lnsRefs;
+ private Map> lns;
+ private HashSet lnS;
+ private Map descriptions;
+ private Map dAIDescriptions;
+ private Map dos;
+ private List logicalDevices;
public ServerModel(List logicalDevices, Collection dataSets) {
children = new LinkedHashMap<>();
@@ -402,4 +413,92 @@ public final class ServerModel extends ModelNode {
public void setConnectionParam(ConnectionParam connectionParam) {
this.connectionParam = connectionParam;
}
+
+ public String getIedName() {
+ return iedName;
+ }
+
+ public void setIedName(String iedName) {
+ this.iedName = iedName;
+ }
+
+ public String getIedManufacturer() {
+ return iedManufacturer;
+ }
+
+ public void setIedManufacturer(String iedManufacturer) {
+ this.iedManufacturer = iedManufacturer;
+ }
+
+ public List getLdsInsts() {
+ return ldsInsts;
+ }
+
+ public void setLdsInsts(List ldsInsts) {
+ this.ldsInsts = ldsInsts;
+ }
+
+ public List getLdsRefs() {
+ return ldsRefs;
+ }
+
+ public void setLdsRefs(List ldsRefs) {
+ this.ldsRefs = ldsRefs;
+ }
+
+ public List getLnsRefs() {
+ return lnsRefs;
+ }
+
+ public void setLnsRefs(List lnsRefs) {
+ this.lnsRefs = lnsRefs;
+ }
+
+ public Map> getLns() {
+ return lns;
+ }
+
+ public void setLns(Map> lns) {
+ this.lns = lns;
+ }
+
+ public HashSet getLnS() {
+ return lnS;
+ }
+
+ public void setLnS(HashSet lnS) {
+ this.lnS = lnS;
+ }
+
+ public Map getDescriptions() {
+ return descriptions;
+ }
+
+ public void setDescriptions(Map descriptions) {
+ this.descriptions = descriptions;
+ }
+
+ public Map getdAIDescriptions() {
+ return dAIDescriptions;
+ }
+
+ public void setdAIDescriptions(Map dAIDescriptions) {
+ this.dAIDescriptions = dAIDescriptions;
+ }
+
+ public Map getDos() {
+ return dos;
+ }
+
+ public void setDos(Map dos) {
+ this.dos = dos;
+ }
+
+ public List getLogicalDevices() {
+ return logicalDevices;
+ }
+
+ public void setLogicalDevices(List logicalDevices) {
+ this.logicalDevices = logicalDevices;
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/beanit/iec61850bean/internal/scl/DoType.java b/src/main/java/com/beanit/iec61850bean/internal/scl/DoType.java
index 67bfce6..81ee192 100644
--- a/src/main/java/com/beanit/iec61850bean/internal/scl/DoType.java
+++ b/src/main/java/com/beanit/iec61850bean/internal/scl/DoType.java
@@ -14,36 +14,45 @@
package com.beanit.iec61850bean.internal.scl;
import com.beanit.iec61850bean.SclParseException;
-import java.util.ArrayList;
-import java.util.List;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
+import java.util.ArrayList;
+import java.util.List;
+
public final class DoType extends AbstractType {
- // attributes not needed: cdc, iedType
+ // attributes not needed: cdc, iedType
- public List das = new ArrayList<>();
- public List sdos = new ArrayList<>();
+ public List das = new ArrayList<>();
+ public List sdos = new ArrayList<>();
- public DoType(Node xmlNode) throws SclParseException {
+ private String cdc;
- super(xmlNode);
+ public DoType(Node xmlNode) throws SclParseException {
- if (xmlNode.getAttributes().getNamedItem("cdc") == null) {
- throw new SclParseException("Required attribute \"cdc\" not found in DOType!");
- }
+ super(xmlNode);
+
+ if (xmlNode.getAttributes().getNamedItem("cdc") == null) {
+ throw new SclParseException("Required attribute \"cdc\" not found in DOType!");
+ } else {
+ cdc = xmlNode.getAttributes().getNamedItem("cdc").getNodeValue();
+ }
- NodeList elements = xmlNode.getChildNodes();
+ NodeList elements = xmlNode.getChildNodes();
+
+ for (int i = 0; i < elements.getLength(); i++) {
+ Node node = elements.item(i);
+ if (node.getNodeName().equals("SDO")) {
+ sdos.add(new Sdo(node));
+ }
+ if (node.getNodeName().equals("DA")) {
+ das.add(new Da(node));
+ }
+ }
+ }
- for (int i = 0; i < elements.getLength(); i++) {
- Node node = elements.item(i);
- if (node.getNodeName().equals("SDO")) {
- sdos.add(new Sdo(node));
- }
- if (node.getNodeName().equals("DA")) {
- das.add(new Da(node));
- }
+ public String getCdc() {
+ return cdc;
}
- }
}
diff --git a/src/main/java/com/beanit/iec61850bean/internal/scl/LnType.java b/src/main/java/com/beanit/iec61850bean/internal/scl/LnType.java
index 7947ec3..34e898e 100644
--- a/src/main/java/com/beanit/iec61850bean/internal/scl/LnType.java
+++ b/src/main/java/com/beanit/iec61850bean/internal/scl/LnType.java
@@ -14,32 +14,44 @@
package com.beanit.iec61850bean.internal.scl;
import com.beanit.iec61850bean.SclParseException;
-import java.util.ArrayList;
-import java.util.List;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
+import java.util.ArrayList;
+import java.util.List;
+
public final class LnType extends AbstractType {
- // attributes not needed: lnClass, iedType
+ // attributes not needed: lnClass, iedType
+
+ public List dos = new ArrayList<>();
+ private String lnClass;
- public List dos = new ArrayList<>();
+ public LnType(Node xmlNode) throws SclParseException {
- public LnType(Node xmlNode) throws SclParseException {
+ super(xmlNode);
- super(xmlNode);
+ if (xmlNode.getAttributes().getNamedItem("lnClass") == null) {
+ throw new SclParseException("Required attribute \"lnClass\" not found in LNType!");
+ } else {
+ lnClass = xmlNode.getAttributes().getNamedItem("lnClass").getNodeValue();
+ }
- if (xmlNode.getAttributes().getNamedItem("lnClass") == null) {
- throw new SclParseException("Required attribute \"lnClass\" not found in LNType!");
+ NodeList elements = xmlNode.getChildNodes();
+
+ for (int i = 0; i < elements.getLength(); i++) {
+ Node node = elements.item(i);
+ if (node.getNodeName().equals("DO")) {
+ dos.add(new Do(node));
+ }
+ }
}
- NodeList elements = xmlNode.getChildNodes();
+ public String getLnClass() {
+ return lnClass;
+ }
- for (int i = 0; i < elements.getLength(); i++) {
- Node node = elements.item(i);
- if (node.getNodeName().equals("DO")) {
- dos.add(new Do(node));
- }
+ public void setLnClass(String lnClass) {
+ this.lnClass = lnClass;
}
- }
}