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; } - } }