build: 增加iec61850bean源码

dev
huangfeng 9 months ago
parent 4eb486e7ed
commit 830ef69c1d

@ -187,6 +187,12 @@
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
<dependency>
<groupId>com.beanit</groupId>
<artifactId>asn1bean</artifactId>
<version>1.14.0</version>
</dependency>
</dependencies>
<build>

@ -0,0 +1,38 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import com.beanit.josistack.AcseAssociation;
import com.beanit.josistack.AcseAssociationListener;
import java.io.IOException;
import java.nio.ByteBuffer;
final class AcseListener implements AcseAssociationListener {
ServerSap serverSap;
AcseListener(ServerSap serverSap) {
this.serverSap = serverSap;
}
@Override
public void connectionIndication(AcseAssociation acseAssociation, ByteBuffer psdu) {
serverSap.connectionIndication(acseAssociation, psdu);
}
@Override
public void serverStoppedListeningIndication(IOException e) {
serverSap.serverStoppedListeningIndication(e);
}
}

@ -0,0 +1,163 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import com.beanit.iec61850bean.internal.mms.asn1.Data;
import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription;
import com.beanit.iec61850bean.internal.mms.asn1.TypeSpecification;
import com.beanit.iec61850bean.internal.mms.asn1.Unsigned32;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
/**
* An Array can contain up to n instances of one and the same DataObject, ConstructedDataAttribute,
* or BasicDataAttribute. The children of the array have the name that equals the index in the array
* (e.g. "0","1" etc.)
*
* @author Stefan Feuerhahn
*/
public final class Array extends FcModelNode {
private final List<ModelNode> items;
/**
* Creates an array object.
*
* @param objectReference the reference of the array
* @param fc the functional constraint of the array
* @param children the children of the array
*/
public Array(ObjectReference objectReference, Fc fc, List<FcModelNode> children) {
this.objectReference = objectReference;
this.fc = fc;
items = new ArrayList<>(children.size());
for (ModelNode child : children) {
items.add(child);
child.setParent(this);
}
}
@Override
public Collection<ModelNode> getChildren() {
return new ArrayList<>(items);
}
@Override
public Iterator<ModelNode> iterator() {
return items.iterator();
}
@Override
public ModelNode getChild(String childName, Fc fc) {
return items.get(Integer.parseInt(childName));
}
public ModelNode getChild(int index) {
return items.get(index);
}
@Override
public ModelNode copy() {
List<FcModelNode> itemsCopy = new ArrayList<>(items.size());
for (ModelNode item : items) {
itemsCopy.add((FcModelNode) item.copy());
}
return new Array(objectReference, fc, itemsCopy);
}
@Override
public List<BasicDataAttribute> getBasicDataAttributes() {
List<BasicDataAttribute> subBasicDataAttributes = new ArrayList<>();
for (ModelNode item : items) {
subBasicDataAttributes.addAll(item.getBasicDataAttributes());
}
return subBasicDataAttributes;
}
public int size() {
return items.size();
}
@Override
Data getMmsDataObj() {
Data.Array dataArray = new Data.Array();
List<Data> arrayDataList = dataArray.getData();
for (ModelNode modelNode : items) {
Data mmsArrayItem = modelNode.getMmsDataObj();
if (mmsArrayItem == null) {
throw new IllegalArgumentException(
"Unable to convert Child: " + modelNode.objectReference + " to MMS Data Object.");
}
arrayDataList.add(mmsArrayItem);
}
if (arrayDataList.size() == 0) {
throw new IllegalArgumentException(
"Converting ModelNode: "
+ objectReference
+ " to MMS Data Object resulted in Sequence of size zero.");
}
Data data = new Data();
data.setArray(dataArray);
return data;
}
@Override
void setValueFromMmsDataObj(Data data) throws ServiceError {
if (data.getArray() == null) {
throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: array");
}
if (data.getArray().getData().size() != items.size()) {
throw new ServiceError(
ServiceError.TYPE_CONFLICT, "expected type: array with " + children.size() + " elements");
}
Iterator<Data> iterator = data.getArray().getData().iterator();
for (ModelNode child : items) {
child.setValueFromMmsDataObj(iterator.next());
}
}
@Override
TypeDescription getMmsTypeSpec() {
TypeSpecification elementType = new TypeSpecification();
elementType.setTypeDescription(items.get(0).getMmsTypeSpec());
TypeDescription.Array array = new TypeDescription.Array();
array.setNumberOfElements(new Unsigned32(items.size()));
array.setElementType(elementType);
TypeDescription typeDescription = new TypeDescription();
typeDescription.setArray(array);
return typeDescription;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getReference().toString()).append(" [").append(fc).append("]");
for (ModelNode childNode : items) {
sb.append("\n");
sb.append(childNode.toString());
}
return sb.toString();
}
}

@ -0,0 +1,114 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
public abstract class BasicDataAttribute extends FcModelNode {
final List<Urcb> chgRcbs;
final List<Urcb> dupdRcbs;
BasicDataAttribute mirror;
/** attribute value type */
BdaType basicType = null;
/** short address, can be used by SCSM and for local data mapping */
String sAddr = null;
boolean dchg;
boolean qchg;
boolean dupd;
protected BasicDataAttribute(
ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) {
this.objectReference = objectReference;
this.fc = fc;
this.sAddr = sAddr;
this.dchg = dchg;
this.dupd = dupd;
if (dchg) {
chgRcbs = new ArrayList<>();
} else {
chgRcbs = null;
}
if (dupd) {
dupdRcbs = new ArrayList<>();
} else {
dupdRcbs = null;
}
}
public boolean getDchg() {
return dchg;
}
public boolean getDupd() {
return dupd;
}
public boolean getQchg() {
return dupd;
}
public BdaType getBasicType() {
return basicType;
}
public String getSAddr() {
return sAddr;
}
@Override
public ModelNode getChild(String childName, Fc fc) {
return null;
}
@Override
public ModelNode getChild(String childName) {
return null;
}
@Override
public Collection<ModelNode> getChildren() {
return null;
}
@Override
public Iterator<ModelNode> iterator() {
return Collections.emptyIterator();
}
public abstract void setDefault();
@Override
public List<BasicDataAttribute> getBasicDataAttributes() {
List<BasicDataAttribute> subBasicDataAttributes = new ArrayList<>();
subBasicDataAttributes.add(this);
return subBasicDataAttributes;
}
public abstract void setValueFrom(BasicDataAttribute bda);
void setMirror(BasicDataAttribute bda) {
mirror = bda;
}
public String getValueString() {
return null;
}
}

@ -0,0 +1,108 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import com.beanit.asn1bean.ber.types.BerBitString;
import com.beanit.iec61850bean.internal.HexString;
import com.beanit.iec61850bean.internal.mms.asn1.Data;
import com.beanit.iec61850bean.internal.mms.asn1.Integer32;
import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription;
public abstract class BdaBitString extends BasicDataAttribute {
final int maxNumBits;
volatile byte[] value;
protected BdaBitString(
ObjectReference objectReference,
Fc fc,
String sAddr,
int maxNumBits,
boolean dchg,
boolean dupd) {
super(objectReference, fc, sAddr, dchg, dupd);
this.maxNumBits = maxNumBits;
}
public byte[] getValue() {
return value;
}
public void setValue(byte[] value) {
if (value.length != ((maxNumBits - 1) / 8 + 1)) {
throw new IllegalArgumentException("value does not have correct length.");
}
this.value = value;
}
@Override
public void setValueFrom(BasicDataAttribute bda) {
byte[] srcValue = ((BdaBitString) bda).getValue();
if (value.length != srcValue.length) {
value = new byte[srcValue.length];
}
System.arraycopy(srcValue, 0, value, 0, srcValue.length);
}
public int getMaxNumBits() {
return maxNumBits;
}
/** Initializes BIT_STRING with all zeros */
@Override
public void setDefault() {
value = new byte[(maxNumBits - 1) / 8 + 1];
}
@Override
Data getMmsDataObj() {
Data data = new Data();
data.setBitString(new BerBitString(value, maxNumBits));
return data;
}
@Override
void setValueFromMmsDataObj(Data data) throws ServiceError {
if (data.getBitString() == null) {
throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: bit_string");
}
if (data.getBitString().numBits > maxNumBits) {
throw new ServiceError(
ServiceError.TYPE_CONFLICT,
objectReference
+ ": bit_string is bigger than type's size: "
+ data.getBitString().numBits
+ ">"
+ maxNumBits);
}
value = data.getBitString().value;
}
@Override
TypeDescription getMmsTypeSpec() {
TypeDescription typeDescription = new TypeDescription();
typeDescription.setBitString(new Integer32(maxNumBits * -1));
return typeDescription;
}
@Override
public String toString() {
return getReference().toString() + ": " + HexString.fromBytes(value);
}
@Override
public String getValueString() {
return HexString.fromBytes(value);
}
}

@ -0,0 +1,93 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import com.beanit.asn1bean.ber.types.BerNull;
import com.beanit.iec61850bean.internal.BerBoolean;
import com.beanit.iec61850bean.internal.mms.asn1.Data;
import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription;
public final class BdaBoolean extends BasicDataAttribute {
private volatile boolean value;
public BdaBoolean(
ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) {
super(objectReference, fc, sAddr, dchg, dupd);
basicType = BdaType.BOOLEAN;
setDefault();
}
@Override
public void setValueFrom(BasicDataAttribute bda) {
value = ((BdaBoolean) bda).getValue();
}
public boolean getValue() {
return value;
}
public void setValue(boolean value) {
this.value = value;
}
@Override
public void setDefault() {
value = false;
}
@Override
public BdaBoolean copy() {
BdaBoolean copy = new BdaBoolean(objectReference, fc, sAddr, dchg, dupd);
copy.setValue(value);
if (mirror == null) {
copy.mirror = this;
} else {
copy.mirror = mirror;
}
return copy;
}
@Override
Data getMmsDataObj() {
Data data = new Data();
data.setBool(new BerBoolean(value));
return data;
}
@Override
void setValueFromMmsDataObj(Data data) throws ServiceError {
if (data.getBool() == null) {
throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: boolean");
}
value = data.getBool().value;
}
@Override
TypeDescription getMmsTypeSpec() {
TypeDescription typeDescription = new TypeDescription();
typeDescription.setBool(new BerNull());
return typeDescription;
}
@Override
public String toString() {
return getReference().toString() + ": " + value;
}
@Override
public String getValueString() {
return "" + value;
}
}

@ -0,0 +1,68 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
/** Check packed list according to 61850-7-2 */
public final class BdaCheck extends BdaBitString {
public BdaCheck(ObjectReference objectReference) {
super(objectReference, Fc.CO, null, 2, false, false);
basicType = BdaType.CHECK;
setDefault();
}
public boolean getSynchrocheck() {
return ((value[0] & 0x80) == 0x80);
}
public void setSynchrocheck(boolean synchrocheck) {
if (synchrocheck) {
value[0] = (byte) (value[0] | 0x80);
} else {
value[0] = (byte) (value[0] & 0x7f);
}
}
public boolean getInterlockCheck() {
return ((value[0] & 0x40) == 0x40);
}
public void setInterlockCheck(boolean interlockCheck) {
if (interlockCheck) {
value[0] = (byte) (value[0] | 0x40);
} else {
value[0] = (byte) (value[0] & 0xbf);
}
}
@Override
public BdaCheck copy() {
BdaCheck copy = new BdaCheck(objectReference);
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
public String toString() {
return getReference().toString() + ": " + String.format("0x%x", value[0]);
}
}

@ -0,0 +1,94 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
public final class BdaDoubleBitPos extends BdaBitString {
public BdaDoubleBitPos(
ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) {
super(objectReference, fc, sAddr, 2, dchg, dupd);
basicType = BdaType.DOUBLE_BIT_POS;
setDefault();
}
/** Sets the value to DoubleBitPos.OFF */
@Override
public void setDefault() {
value = new byte[] {0x40};
}
@Override
public BdaDoubleBitPos copy() {
BdaDoubleBitPos copy = new BdaDoubleBitPos(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;
}
public DoubleBitPos getDoubleBitPos() {
if ((value[0] & 0xC0) == 0xC0) {
return DoubleBitPos.BAD_STATE;
}
if ((value[0] & 0x80) == 0x80) {
return DoubleBitPos.ON;
}
if ((value[0] & 0x40) == 0x40) {
return DoubleBitPos.OFF;
}
return DoubleBitPos.INTERMEDIATE_STATE;
}
public void setDoubleBitPos(DoubleBitPos doubleBitPos) {
if (doubleBitPos == DoubleBitPos.BAD_STATE) {
value[0] = (byte) 0xC0;
} else if (doubleBitPos == DoubleBitPos.ON) {
value[0] = (byte) 0x80;
} else if (doubleBitPos == DoubleBitPos.OFF) {
value[0] = (byte) 0x40;
} else {
value[0] = (byte) 0;
}
}
@Override
public String getValueString() {
return getDoubleBitPos().toString();
}
public enum DoubleBitPos {
INTERMEDIATE_STATE(0),
OFF(1),
ON(2),
BAD_STATE(3);
private final int value;
DoubleBitPos(int value) {
this.value = value;
}
public int getIntValue() {
return value;
}
}
}

@ -0,0 +1,142 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import com.beanit.iec61850bean.internal.BerBoolean;
import com.beanit.iec61850bean.internal.mms.asn1.Data;
import com.beanit.iec61850bean.internal.mms.asn1.TimeOfDay;
import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription;
/**
* BdaEntryTime stores time in terms of days and ms since 1984.
*
* @author Stefan Feuerhahn
*/
public final class BdaEntryTime extends BasicDataAttribute {
private volatile byte[] value;
public BdaEntryTime(
ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) {
super(objectReference, fc, sAddr, dchg, dupd);
basicType = BdaType.ENTRY_TIME;
setDefault();
}
/**
* Set the value of this object to the given timestamp, where timestamp is the number of ms since
* epoch 1970-01-01 00:00:00 UTC. Note that timestamps before 1984 are not valid as they cannot be
* stored.
*
* @param timestamp the number of ms since epoch 1970-01-01
*/
public void setTimestamp(long timestamp) {
long msSince1984 = timestamp - 441763200000l;
int days = (int) (msSince1984 / 86400000);
int ms = (int) (msSince1984 % 86400000);
value =
new byte[] {
(byte) (ms >> 24),
(byte) (ms >> 16),
(byte) (ms >> 8),
(byte) ms,
(byte) (days >> 8),
(byte) days
};
}
public long getTimestampValue() {
if (value.length != 6) {
return -1;
}
return (((value[0] & 0xffl) << 24)
+ ((value[1] & 0xffl) << 16)
+ ((value[2] & 0xffl) << 8)
+ (value[3] & 0xffl)
+ (((value[4] & 0xffl) << 8) + (value[5] & 0xffl)) * 86400000l)
+ 441763200000l;
}
@Override
public void setValueFrom(BasicDataAttribute bda) {
byte[] srcValue = ((BdaEntryTime) bda).getValue();
if (value.length != srcValue.length) {
value = new byte[srcValue.length];
}
System.arraycopy(srcValue, 0, value, 0, srcValue.length);
}
public byte[] getValue() {
return value;
}
public void setValue(byte[] value) {
this.value = value;
}
/** Sets EntryTime to byte[6] with all zeros */
@Override
public void setDefault() {
value = new byte[6];
}
@Override
public BdaEntryTime copy() {
BdaEntryTime copy = new BdaEntryTime(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() {
if (value == null) {
return null;
}
Data data = new Data();
data.setBinaryTime(new TimeOfDay(value));
return data;
}
@Override
void setValueFromMmsDataObj(Data data) throws ServiceError {
if (data.getBinaryTime() == null) {
throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: binary_time/EntryTime");
}
value = data.getBinaryTime().value;
}
@Override
TypeDescription getMmsTypeSpec() {
TypeDescription typeDescription = new TypeDescription();
typeDescription.setBinaryTime(new BerBoolean(true));
return typeDescription;
}
@Override
public String toString() {
return getReference().toString() + ": " + getTimestampValue();
}
@Override
public String getValueString() {
return "" + getTimestampValue();
}
}

@ -0,0 +1,121 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import com.beanit.iec61850bean.internal.mms.asn1.Data;
import com.beanit.iec61850bean.internal.mms.asn1.FloatingPoint;
import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription;
import com.beanit.iec61850bean.internal.mms.asn1.Unsigned8;
import java.nio.ByteBuffer;
public final class BdaFloat32 extends BasicDataAttribute {
private volatile byte[] value;
public BdaFloat32(
ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) {
super(objectReference, fc, sAddr, dchg, dupd);
basicType = BdaType.FLOAT32;
setDefault();
}
@Override
public void setValueFrom(BasicDataAttribute bda) {
byte[] srcValue = ((BdaFloat32) bda).getValue();
if (value.length != srcValue.length) {
value = new byte[srcValue.length];
}
System.arraycopy(srcValue, 0, value, 0, srcValue.length);
}
public byte[] getValue() {
return value;
}
public void setValue(byte[] value) {
this.value = value;
}
public Float getFloat() {
return Float.intBitsToFloat(
((0xff & value[1]) << 24)
| ((0xff & value[2]) << 16)
| ((0xff & value[3]) << 8)
| ((0xff & value[4]) << 0));
}
public void setFloat(Float value) {
this.value = ByteBuffer.allocate(1 + 4).put((byte) 8).putFloat(value).array();
}
@Override
public void setDefault() {
value = new byte[] {8, 0, 0, 0, 0};
}
@Override
public BdaFloat32 copy() {
BdaFloat32 copy = new BdaFloat32(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() {
if (value == null) {
return null;
}
Data data = new Data();
data.setFloatingPoint(new FloatingPoint(value));
return data;
}
@Override
void setValueFromMmsDataObj(Data data) throws ServiceError {
if (data.getFloatingPoint() == null || data.getFloatingPoint().value.length != 5) {
throw new ServiceError(
ServiceError.TYPE_CONFLICT, "expected type: floating_point as an octet string of size 5");
}
value = data.getFloatingPoint().value;
}
@Override
TypeDescription getMmsTypeSpec() {
TypeDescription.FloatingPoint floatingPointTypeDescription =
new TypeDescription.FloatingPoint();
floatingPointTypeDescription.setFormatWidth(new Unsigned8(32));
floatingPointTypeDescription.setExponentWidth(new Unsigned8(8));
TypeDescription typeDescription = new TypeDescription();
typeDescription.setFloatingPoint(floatingPointTypeDescription);
return typeDescription;
}
@Override
public String toString() {
return getReference().toString() + ": " + getFloat();
}
@Override
public String getValueString() {
return getFloat().toString();
}
}

@ -0,0 +1,132 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import com.beanit.iec61850bean.internal.mms.asn1.Data;
import com.beanit.iec61850bean.internal.mms.asn1.FloatingPoint;
import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription;
import com.beanit.iec61850bean.internal.mms.asn1.Unsigned8;
import java.nio.ByteBuffer;
import java.util.Arrays;
public final class BdaFloat64 extends BasicDataAttribute {
private volatile byte[] value = new byte[] {11, 0, 0, 0, 0, 0, 0, 0, 0};
public BdaFloat64(
ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) {
super(objectReference, fc, sAddr, dchg, dupd);
basicType = BdaType.FLOAT64;
setDefault();
}
@Override
public void setValueFrom(BasicDataAttribute bda) {
byte[] srcValue = ((BdaFloat64) bda).getValue();
if (value.length != srcValue.length) {
value = new byte[srcValue.length];
}
System.arraycopy(srcValue, 0, value, 0, srcValue.length);
}
public byte[] getValue() {
return value;
}
public void setValue(byte[] value) {
if (value != null && value.length != 9) {
throw new IllegalArgumentException("value does not have length 9");
}
this.value = value;
}
public Double getDouble() {
if (value == null) {
return null;
}
return Double.longBitsToDouble(
((0xffL & value[1]) << 56)
| ((0xffL & value[2]) << 48)
| ((0xffL & value[3]) << 40)
| ((0xffL & value[4]) << 32)
| ((0xffL & value[5]) << 24)
| ((0xffL & value[6]) << 16)
| ((0xffL & value[7]) << 8)
| ((0xffL & value[8]) << 0));
}
public void setDouble(Double value) {
this.value = ByteBuffer.allocate(1 + 8).put((byte) 11).putDouble(value).array();
}
@Override
public void setDefault() {
value = new byte[] {11, 0, 0, 0, 0, 0, 0, 0, 0};
}
@Override
public BdaFloat64 copy() {
BdaFloat64 copy = new BdaFloat64(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() {
if (value == null) {
return null;
}
Data data = new Data();
data.setFloatingPoint(new FloatingPoint(value));
return data;
}
@Override
void setValueFromMmsDataObj(Data data) throws ServiceError {
if (data.getFloatingPoint() == null || data.getFloatingPoint().value.length != 9) {
throw new ServiceError(
ServiceError.TYPE_CONFLICT, "expected type: floating_point as an octet string of size 9");
}
value = data.getFloatingPoint().value;
}
@Override
TypeDescription getMmsTypeSpec() {
TypeDescription.FloatingPoint floatingPointTypeDescription =
new TypeDescription.FloatingPoint();
floatingPointTypeDescription.setFormatWidth(new Unsigned8(64));
floatingPointTypeDescription.setExponentWidth(new Unsigned8(11));
TypeDescription typeDescription = new TypeDescription();
typeDescription.setFloatingPoint(floatingPointTypeDescription);
return typeDescription;
}
@Override
public String toString() {
return getReference().toString() + ": " + getDouble();
}
@Override
public String getValueString() {
return "" + Arrays.toString(value);
}
}

@ -0,0 +1,93 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import com.beanit.asn1bean.ber.types.BerInteger;
import com.beanit.iec61850bean.internal.mms.asn1.Data;
import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription;
import com.beanit.iec61850bean.internal.mms.asn1.Unsigned8;
public final class BdaInt128 extends BasicDataAttribute {
private volatile long value;
public BdaInt128(
ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) {
super(objectReference, fc, sAddr, dchg, dupd);
basicType = BdaType.INT128;
setDefault();
}
@Override
public void setValueFrom(BasicDataAttribute bda) {
value = ((BdaInt128) bda).getValue();
}
public long getValue() {
return value;
}
public void setValue(long value) {
this.value = value;
}
@Override
public void setDefault() {
value = 0;
}
@Override
public BdaInt128 copy() {
BdaInt128 copy = new BdaInt128(objectReference, fc, sAddr, dchg, dupd);
copy.setValue(value);
if (mirror == null) {
copy.mirror = this;
} else {
copy.mirror = mirror;
}
return copy;
}
@Override
Data getMmsDataObj() {
Data data = new Data();
data.setInteger(new BerInteger(value));
return data;
}
@Override
void setValueFromMmsDataObj(Data data) throws ServiceError {
if (data.getInteger() == null) {
throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: integer");
}
value = data.getInteger().value.longValue();
}
@Override
TypeDescription getMmsTypeSpec() {
TypeDescription typeDescription = new TypeDescription();
typeDescription.setInteger(new Unsigned8(128));
return typeDescription;
}
@Override
public String toString() {
return getReference().toString() + ": " + value;
}
@Override
public String getValueString() {
return "" + value;
}
}

@ -0,0 +1,88 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import com.beanit.asn1bean.ber.types.BerInteger;
import com.beanit.iec61850bean.internal.mms.asn1.Data;
import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription;
import com.beanit.iec61850bean.internal.mms.asn1.Unsigned8;
public final class BdaInt16 extends BasicDataAttribute {
private volatile short value;
public BdaInt16(
ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) {
super(objectReference, fc, sAddr, dchg, dupd);
basicType = BdaType.INT16;
setDefault();
}
@Override
public void setValueFrom(BasicDataAttribute bda) {
value = ((BdaInt16) bda).getValue();
}
public short getValue() {
return value;
}
public void setValue(short value) {
this.value = value;
}
@Override
public void setDefault() {
value = 0;
}
@Override
public BdaInt16 copy() {
BdaInt16 copy = new BdaInt16(objectReference, fc, sAddr, dchg, dupd);
copy.setValue(value);
if (mirror == null) {
copy.mirror = this;
} else {
copy.mirror = mirror;
}
return copy;
}
@Override
Data getMmsDataObj() {
Data data = new Data();
data.setInteger(new BerInteger(value));
return data;
}
@Override
void setValueFromMmsDataObj(Data data) throws ServiceError {
if (data.getInteger() == null) {
throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: integer");
}
value = data.getInteger().value.shortValue();
}
@Override
TypeDescription getMmsTypeSpec() {
TypeDescription typeDescription = new TypeDescription();
typeDescription.setInteger(new Unsigned8(16));
return typeDescription;
}
@Override
public String toString() {
return getReference().toString() + ": " + value;
}
}

@ -0,0 +1,88 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import com.beanit.asn1bean.ber.types.BerInteger;
import com.beanit.iec61850bean.internal.mms.asn1.Data;
import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription;
import com.beanit.iec61850bean.internal.mms.asn1.Unsigned8;
public final class BdaInt16U extends BasicDataAttribute {
private volatile int value;
public BdaInt16U(
ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) {
super(objectReference, fc, sAddr, dchg, dupd);
basicType = BdaType.INT16U;
setDefault();
}
@Override
public void setValueFrom(BasicDataAttribute bda) {
value = ((BdaInt16U) bda).getValue();
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
@Override
public void setDefault() {
value = 0;
}
@Override
public BdaInt16U copy() {
BdaInt16U copy = new BdaInt16U(objectReference, fc, sAddr, dchg, dupd);
copy.setValue(value);
if (mirror == null) {
copy.mirror = this;
} else {
copy.mirror = mirror;
}
return copy;
}
@Override
Data getMmsDataObj() {
Data data = new Data();
data.setUnsigned(new BerInteger(value));
return data;
}
@Override
void setValueFromMmsDataObj(Data data) throws ServiceError {
if (data.getUnsigned() == null) {
throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: unsigned");
}
value = data.getUnsigned().value.intValue();
}
@Override
TypeDescription getMmsTypeSpec() {
TypeDescription typeDescription = new TypeDescription();
typeDescription.setUnsigned(new Unsigned8(16));
return typeDescription;
}
@Override
public String toString() {
return getReference().toString() + ": " + value;
}
}

@ -0,0 +1,93 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import com.beanit.asn1bean.ber.types.BerInteger;
import com.beanit.iec61850bean.internal.mms.asn1.Data;
import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription;
import com.beanit.iec61850bean.internal.mms.asn1.Unsigned8;
public final class BdaInt32 extends BasicDataAttribute {
private volatile int value;
public BdaInt32(
ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) {
super(objectReference, fc, sAddr, dchg, dupd);
basicType = BdaType.INT32;
setDefault();
}
@Override
public void setValueFrom(BasicDataAttribute bda) {
value = ((BdaInt32) bda).getValue();
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
@Override
public void setDefault() {
value = 0;
}
@Override
public BdaInt32 copy() {
BdaInt32 copy = new BdaInt32(objectReference, fc, sAddr, dchg, dupd);
copy.setValue(value);
if (mirror == null) {
copy.mirror = this;
} else {
copy.mirror = mirror;
}
return copy;
}
@Override
Data getMmsDataObj() {
Data data = new Data();
data.setInteger(new BerInteger(value));
return data;
}
@Override
void setValueFromMmsDataObj(Data data) throws ServiceError {
if (data.getInteger() == null) {
throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: integer");
}
value = data.getInteger().value.intValue();
}
@Override
TypeDescription getMmsTypeSpec() {
TypeDescription typeDescription = new TypeDescription();
typeDescription.setInteger(new Unsigned8(32));
return typeDescription;
}
@Override
public String toString() {
return getReference().toString() + ": " + value;
}
@Override
public String getValueString() {
return "" + value;
}
}

@ -0,0 +1,93 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import com.beanit.asn1bean.ber.types.BerInteger;
import com.beanit.iec61850bean.internal.mms.asn1.Data;
import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription;
import com.beanit.iec61850bean.internal.mms.asn1.Unsigned8;
public final class BdaInt32U extends BasicDataAttribute {
private volatile long value;
public BdaInt32U(
ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) {
super(objectReference, fc, sAddr, dchg, dupd);
basicType = BdaType.INT32U;
setDefault();
}
@Override
public void setValueFrom(BasicDataAttribute bda) {
value = ((BdaInt32U) bda).getValue();
}
public long getValue() {
return value;
}
public void setValue(long value) {
this.value = value;
}
@Override
public void setDefault() {
value = 0;
}
@Override
public BdaInt32U copy() {
BdaInt32U copy = new BdaInt32U(objectReference, fc, sAddr, dchg, dupd);
copy.setValue(value);
if (mirror == null) {
copy.mirror = this;
} else {
copy.mirror = mirror;
}
return copy;
}
@Override
Data getMmsDataObj() {
Data data = new Data();
data.setUnsigned(new BerInteger(value));
return data;
}
@Override
void setValueFromMmsDataObj(Data data) throws ServiceError {
if (data.getUnsigned() == null) {
throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: unsigned");
}
value = data.getUnsigned().value.longValue();
}
@Override
TypeDescription getMmsTypeSpec() {
TypeDescription typeDescription = new TypeDescription();
typeDescription.setUnsigned(new Unsigned8(32));
return typeDescription;
}
@Override
public String toString() {
return getReference().toString() + ": " + value;
}
@Override
public String getValueString() {
return "" + value;
}
}

@ -0,0 +1,88 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import com.beanit.asn1bean.ber.types.BerInteger;
import com.beanit.iec61850bean.internal.mms.asn1.Data;
import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription;
import com.beanit.iec61850bean.internal.mms.asn1.Unsigned8;
public final class BdaInt64 extends BasicDataAttribute {
private volatile long value;
public BdaInt64(
ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) {
super(objectReference, fc, sAddr, dchg, dupd);
basicType = BdaType.INT64;
setDefault();
}
@Override
public void setValueFrom(BasicDataAttribute bda) {
value = ((BdaInt64) bda).getValue();
}
public long getValue() {
return value;
}
public void setValue(long value) {
this.value = value;
}
@Override
public void setDefault() {
value = 0;
}
@Override
public BdaInt64 copy() {
BdaInt64 copy = new BdaInt64(objectReference, fc, sAddr, dchg, dupd);
copy.setValue(value);
if (mirror == null) {
copy.mirror = this;
} else {
copy.mirror = mirror;
}
return copy;
}
@Override
Data getMmsDataObj() {
Data data = new Data();
data.setInteger(new BerInteger(value));
return data;
}
@Override
void setValueFromMmsDataObj(Data data) throws ServiceError {
if (data.getInteger() == null) {
throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: integer");
}
value = data.getInteger().value.longValue();
}
@Override
TypeDescription getMmsTypeSpec() {
TypeDescription typeDescription = new TypeDescription();
typeDescription.setInteger(new Unsigned8(64));
return typeDescription;
}
@Override
public String toString() {
return getReference().toString() + ": " + value;
}
}

@ -0,0 +1,92 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import com.beanit.asn1bean.ber.types.BerInteger;
import com.beanit.iec61850bean.internal.mms.asn1.Data;
import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription;
import com.beanit.iec61850bean.internal.mms.asn1.Unsigned8;
public final class BdaInt8 extends BasicDataAttribute {
private volatile byte value;
public BdaInt8(ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) {
super(objectReference, fc, sAddr, dchg, dupd);
basicType = BdaType.INT8;
setDefault();
}
@Override
public void setValueFrom(BasicDataAttribute bda) {
value = ((BdaInt8) bda).getValue();
}
public byte getValue() {
return value;
}
public void setValue(byte value) {
this.value = value;
}
@Override
public void setDefault() {
value = 0;
}
@Override
public BdaInt8 copy() {
BdaInt8 copy = new BdaInt8(objectReference, fc, sAddr, dchg, dupd);
copy.setValue(value);
if (mirror == null) {
copy.mirror = this;
} else {
copy.mirror = mirror;
}
return copy;
}
@Override
Data getMmsDataObj() {
Data data = new Data();
data.setInteger(new BerInteger(value));
return data;
}
@Override
void setValueFromMmsDataObj(Data data) throws ServiceError {
if (data.getInteger() == null) {
throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: integer");
}
value = data.getInteger().value.byteValue();
}
@Override
TypeDescription getMmsTypeSpec() {
TypeDescription typeDescription = new TypeDescription();
typeDescription.setInteger(new Unsigned8(8));
return typeDescription;
}
@Override
public String toString() {
return getReference().toString() + ": " + value;
}
@Override
public String getValueString() {
return "" + value;
}
}

@ -0,0 +1,88 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import com.beanit.asn1bean.ber.types.BerInteger;
import com.beanit.iec61850bean.internal.mms.asn1.Data;
import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription;
import com.beanit.iec61850bean.internal.mms.asn1.Unsigned8;
public final class BdaInt8U extends BasicDataAttribute {
private volatile short value;
public BdaInt8U(
ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) {
super(objectReference, fc, sAddr, dchg, dupd);
basicType = BdaType.INT8U;
setDefault();
}
@Override
public void setValueFrom(BasicDataAttribute bda) {
value = ((BdaInt8U) bda).getValue();
}
public short getValue() {
return value;
}
public void setValue(short value) {
this.value = value;
}
@Override
public void setDefault() {
value = 0;
}
@Override
public BdaInt8U copy() {
BdaInt8U copy = new BdaInt8U(objectReference, fc, sAddr, dchg, dupd);
copy.setValue(value);
if (mirror == null) {
copy.mirror = this;
} else {
copy.mirror = mirror;
}
return copy;
}
@Override
Data getMmsDataObj() {
Data data = new Data();
data.setUnsigned(new BerInteger(value));
return data;
}
@Override
void setValueFromMmsDataObj(Data data) throws ServiceError {
if (data.getUnsigned() == null) {
throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: unsigned");
}
value = data.getUnsigned().value.shortValue();
}
@Override
TypeDescription getMmsTypeSpec() {
TypeDescription typeDescription = new TypeDescription();
typeDescription.setUnsigned(new Unsigned8(8));
return typeDescription;
}
@Override
public String toString() {
return getReference().toString() + ": " + value;
}
}

@ -0,0 +1,110 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import com.beanit.asn1bean.ber.types.BerOctetString;
import com.beanit.iec61850bean.internal.mms.asn1.Data;
import com.beanit.iec61850bean.internal.mms.asn1.Integer32;
import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription;
import java.util.Arrays;
public final class BdaOctetString extends BasicDataAttribute {
private final int maxLength;
private volatile byte[] value;
public BdaOctetString(
ObjectReference objectReference,
Fc fc,
String sAddr,
int maxLength,
boolean dchg,
boolean dupd) {
super(objectReference, fc, sAddr, dchg, dupd);
basicType = BdaType.OCTET_STRING;
this.maxLength = maxLength;
setDefault();
}
public byte[] getValue() {
return value;
}
public void setValue(byte[] value) {
if (value != null && value.length > maxLength) {
throw new IllegalArgumentException(
"OCTET_STRING value size exceeds maxLength of " + maxLength);
}
this.value = value;
}
@Override
public void setValueFrom(BasicDataAttribute bda) {
byte[] srcValue = ((BdaOctetString) bda).getValue();
if (value.length != srcValue.length) {
value = new byte[srcValue.length];
}
System.arraycopy(srcValue, 0, value, 0, srcValue.length);
}
public int getMaxLength() {
return maxLength;
}
@Override
public void setDefault() {
value = new byte[0];
}
@Override
public BdaOctetString copy() {
BdaOctetString copy = new BdaOctetString(objectReference, fc, sAddr, maxLength, 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.setOctetString(new BerOctetString(value));
return data;
}
@Override
void setValueFromMmsDataObj(Data data) throws ServiceError {
if (data.getOctetString() == null) {
throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: octet_string");
}
value = data.getOctetString().value;
}
@Override
TypeDescription getMmsTypeSpec() {
TypeDescription typeDescription = new TypeDescription();
typeDescription.setOctetString(new Integer32(maxLength * -1));
return typeDescription;
}
@Override
public String toString() {
return getReference().toString() + ": " + Arrays.toString(value);
}
}

@ -0,0 +1,156 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
public final class BdaOptFlds extends BdaBitString {
public BdaOptFlds(ObjectReference objectReference, Fc fc) {
super(objectReference, fc, null, 10, false, false);
basicType = BdaType.OPTFLDS;
setDefault();
}
@Override
public void setDefault() {
/* default of buffer overflow is true by default in IEC 61850-6 sec. 9.3.8 */
value = new byte[] {0x02, 0x00};
}
@Override
public BdaOptFlds copy() {
BdaOptFlds copy = new BdaOptFlds(objectReference, fc);
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;
}
public boolean isSequenceNumber() {
return (value[0] & 0x40) == 0x40;
}
public void setSequenceNumber(boolean sequenceNumber) {
if (sequenceNumber) {
value[0] = (byte) (value[0] | 0x40);
} else {
value[0] = (byte) (value[0] & 0xbf);
}
}
public boolean isReportTimestamp() {
return (value[0] & 0x20) == 0x20;
}
public void setReportTimestamp(boolean reportTimestamp) {
if (reportTimestamp) {
value[0] = (byte) (value[0] | 0x20);
} else {
value[0] = (byte) (value[0] & 0xdf);
}
}
public boolean isReasonForInclusion() {
return (value[0] & 0x10) == 0x10;
}
public void setReasonForInclusion(boolean reasonForInclusion) {
if (reasonForInclusion) {
value[0] = (byte) (value[0] | 0x10);
} else {
value[0] = (byte) (value[0] & 0xef);
}
}
/**
* Will the data set reference (not just the name) be included in the report.
*
* @return true if the data set reference (not just the name) will be included in the report
*/
public boolean isDataSetName() {
return (value[0] & 0x08) == 0x08;
}
public void setDataSetName(boolean dataSetName) {
if (dataSetName) {
value[0] = (byte) (value[0] | 0x08);
} else {
value[0] = (byte) (value[0] & 0xf7);
}
}
public boolean isDataReference() {
return (value[0] & 0x04) == 0x04;
}
public void setDataReference(boolean dataReference) {
if (dataReference) {
value[0] = (byte) (value[0] | 0x04);
} else {
value[0] = (byte) (value[0] & 0xfb);
}
}
public boolean isBufferOverflow() {
return (value[0] & 0x02) == 0x02;
}
public void setBufferOverflow(boolean bufferOverflow) {
if (bufferOverflow) {
value[0] = (byte) (value[0] | 0x02);
} else {
value[0] = (byte) (value[0] & 0xfd);
}
}
public boolean isEntryId() {
return (value[0] & 0x01) == 0x01;
}
public void setEntryId(boolean entryId) {
if (entryId) {
value[0] = (byte) (value[0] | 0x01);
} else {
value[0] = (byte) (value[0] & 0xfe);
}
}
public boolean isConfigRevision() {
return (value[1] & 0x80) == 0x80;
}
public void setConfigRevision(boolean configRevision) {
if (configRevision) {
value[1] = (byte) (value[1] | 0x80);
} else {
value[1] = (byte) (value[1] & 0x7f);
}
}
public boolean isSegmentation() {
return (value[1] & 0x40) == 0x40;
}
public void setSegmentation(boolean segmentation) {
if (segmentation) {
value[1] = (byte) (value[1] | 0x40);
} else {
value[1] = (byte) (value[1] & 0xbf);
}
}
}

@ -0,0 +1,226 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
public final class BdaQuality extends BdaBitString {
public BdaQuality(ObjectReference objectReference, Fc fc, String sAddr, boolean qchg) {
super(objectReference, fc, sAddr, 13, qchg, false);
this.qchg = qchg;
basicType = BdaType.QUALITY;
setDefault();
}
@Override
public void setDefault() {
value = new byte[] {0x00, 0x00};
}
@Override
public BdaQuality copy() {
BdaQuality copy = new BdaQuality(objectReference, fc, sAddr, qchg);
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;
}
public Validity getValidity() {
if ((value[0] & 0xC0) == 0xC0) {
return Validity.QUESTIONABLE;
}
if ((value[0] & 0x80) == 0x80) {
return Validity.RESERVED;
}
if ((value[0] & 0x40) == 0x40) {
return Validity.INVALID;
}
return Validity.GOOD;
}
public void setValidity(Validity validity) {
if (validity == Validity.QUESTIONABLE) {
value[0] = (byte) (value[0] | 0xC0);
} else if (validity == Validity.RESERVED) {
value[0] = (byte) (value[0] | 0x80);
value[0] = (byte) (value[0] & 0xbf);
} else if (validity == Validity.INVALID) {
value[0] = (byte) (value[0] & 0x7f);
value[0] = (byte) (value[0] | 0x40);
} else {
value[0] = (byte) (value[0] & 0x03);
}
}
public boolean isOverflow() {
return (value[0] & 0x20) == 0x20;
}
public void setOverflow(boolean overflow) {
if (overflow) {
value[0] = (byte) (value[0] | 0x20);
} else {
value[0] = (byte) (value[0] & 0xdf);
}
}
public boolean isOutOfRange() {
return (value[0] & 0x10) == 0x10;
}
public void setOutOfRange(boolean outOfRange) {
if (outOfRange) {
value[0] = (byte) (value[0] | 0x10);
} else {
value[0] = (byte) (value[0] & 0xef);
}
}
public boolean isBadReference() {
return (value[0] & 0x08) == 0x08;
}
public void setBadReference(boolean badReference) {
if (badReference) {
value[0] = (byte) (value[0] | 0x08);
} else {
value[0] = (byte) (value[0] & 0xf7);
}
}
public boolean isOscillatory() {
return (value[0] & 0x04) == 0x04;
}
public void setOscillatory(boolean oscillatory) {
if (oscillatory) {
value[0] = (byte) (value[0] | 0x04);
} else {
value[0] = (byte) (value[0] & 0xfb);
}
}
public boolean isFailure() {
return (value[0] & 0x02) == 0x02;
}
public void setFailure(boolean failure) {
if (failure) {
value[0] = (byte) (value[0] | 0x02);
} else {
value[0] = (byte) (value[0] & 0xfd);
}
}
public boolean isOldData() {
return (value[0] & 0x01) == 0x01;
}
public void setOldData(boolean oldData) {
if (oldData) {
value[0] = (byte) (value[0] | 0x01);
} else {
value[0] = (byte) (value[0] & 0xfe);
}
}
public boolean isInconsistent() {
return (value[1] & 0x80) == 0x80;
}
public void setInconsistent(boolean inconsistent) {
if (inconsistent) {
value[1] = (byte) (value[0] | 0x80);
} else {
value[1] = (byte) (value[0] & 0x7f);
}
}
public boolean isInaccurate() {
return (value[1] & 0x40) == 0x40;
}
public void setInaccurate(boolean inaccurate) {
if (inaccurate) {
value[1] = (byte) (value[0] | 0x40);
} else {
value[1] = (byte) (value[0] & 0xbf);
}
}
public boolean isSubstituted() {
return (value[1] & 0x20) == 0x20;
}
public void setSubstituted(boolean substituted) {
if (substituted) {
value[1] = (byte) (value[0] | 0x20);
} else {
value[1] = (byte) (value[0] & 0xdf);
}
}
public boolean isTest() {
return (value[1] & 0x10) == 0x10;
}
public void setTest(boolean test) {
if (test) {
value[1] = (byte) (value[0] | 0x10);
} else {
value[1] = (byte) (value[0] & 0xef);
}
}
public boolean isOperatorBlocked() {
return (value[1] & 0x08) == 0x08;
}
public void setOperatorBlocked(boolean operatorBlocked) {
if (operatorBlocked) {
value[1] = (byte) (value[0] | 0x08);
} else {
value[1] = (byte) (value[0] & 0xf7);
}
}
@Override
public String getValueString() {
return getValidity().toString();
}
public enum Validity {
GOOD(0),
INVALID(1),
RESERVED(2),
QUESTIONABLE(3);
private final int value;
Validity(int value) {
this.value = value;
}
public int getIntValue() {
return value;
}
}
}

@ -0,0 +1,170 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
public final class BdaReasonForInclusion extends BdaBitString {
public BdaReasonForInclusion(ObjectReference objectReference) {
super(objectReference, null, null, 7, false, false);
basicType = BdaType.REASON_FOR_INCLUSION;
setDefault();
}
@Override
public BdaReasonForInclusion copy() {
BdaReasonForInclusion copy = new BdaReasonForInclusion(objectReference);
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;
}
public boolean isDataChange() {
return (value[0] & 0x40) == 0x40;
}
public void setDataChange(boolean dataChange) {
if (dataChange) {
value[0] = (byte) (value[0] | 0x40);
} else {
value[0] = (byte) (value[0] & 0xbf);
}
}
public boolean isQualityChange() {
return (value[0] & 0x20) == 0x20;
}
public void setQualityChange(boolean qualityChange) {
if (qualityChange) {
value[0] = (byte) (value[0] | 0x20);
} else {
value[0] = (byte) (value[0] & 0xdf);
}
}
public boolean isDataUpdate() {
return (value[0] & 0x10) == 0x10;
}
public void setDataUpdate(boolean dataUpdate) {
if (dataUpdate) {
value[0] = (byte) (value[0] | 0x10);
} else {
value[0] = (byte) (value[0] & 0xef);
}
}
public boolean isIntegrity() {
return (value[0] & 0x08) == 0x08;
}
public void setIntegrity(boolean integrity) {
if (integrity) {
value[0] = (byte) (value[0] | 0x08);
} else {
value[0] = (byte) (value[0] & 0xf7);
}
}
public boolean isGeneralInterrogation() {
return (value[0] & 0x04) == 0x04;
}
public void setGeneralInterrogation(boolean generalInterrogation) {
if (generalInterrogation) {
value[0] = (byte) (value[0] | 0x04);
} else {
value[0] = (byte) (value[0] & 0xfb);
}
}
public boolean isApplicationTrigger() {
return (value[0] & 0x02) == 0x02;
}
public void setApplicationTrigger(boolean applicationTrigger) {
if (applicationTrigger) {
value[0] = (byte) (value[0] | 0x02);
} else {
value[0] = (byte) (value[0] & 0xfd);
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
boolean first = true;
if (isDataChange()) {
if (!first) {
sb.append(",");
} else {
first = false;
}
sb.append("data-change");
}
if (isDataUpdate()) {
if (!first) {
sb.append(",");
} else {
first = false;
}
sb.append("data-update");
}
if (isQualityChange()) {
if (!first) {
sb.append(",");
} else {
first = false;
}
sb.append("quality-change");
}
if (isIntegrity()) {
if (!first) {
sb.append(",");
} else {
first = false;
}
sb.append("integrity");
}
if (isGeneralInterrogation()) {
if (!first) {
sb.append(",");
} else {
first = false;
}
sb.append("general-interrogation");
}
if (isApplicationTrigger()) {
if (!first) {
sb.append(",");
} else {
first = false;
}
sb.append("application-trigger");
}
return sb.toString();
}
}

@ -0,0 +1,89 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
public final class BdaTapCommand extends BdaBitString {
public BdaTapCommand(
ObjectReference objectReference, Fc fc, String sAddr, boolean dchg, boolean dupd) {
super(objectReference, fc, sAddr, 2, dchg, dupd);
basicType = BdaType.TAP_COMMAND;
setDefault();
}
/** Sets the value to TapCommand.STOP */
@Override
public void setDefault() {
value = new byte[] {0x00};
}
@Override
public BdaTapCommand copy() {
BdaTapCommand copy = new BdaTapCommand(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;
}
public TapCommand getTapCommand() {
if ((value[0] & 0xC0) == 0xC0) {
return TapCommand.RESERVED;
}
if ((value[0] & 0x80) == 0x80) {
return TapCommand.HIGHER;
}
if ((value[0] & 0x40) == 0x40) {
return TapCommand.LOWER;
}
return TapCommand.STOP;
}
public void setTapCommand(TapCommand tapCommand) {
if (tapCommand == TapCommand.RESERVED) {
value[0] = (byte) 0xC0;
} else if (tapCommand == TapCommand.HIGHER) {
value[0] = (byte) 0x80;
} else if (tapCommand == TapCommand.LOWER) {
value[0] = (byte) 0x40;
} else {
value[0] = (byte) 0x00;
}
}
public enum TapCommand {
STOP(0),
LOWER(1),
HIGHER(2),
RESERVED(3);
private final int value;
TapCommand(int value) {
this.value = value;
}
public int getIntValue() {
return value;
}
}
}

@ -0,0 +1,242 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
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 <code>
* (SUM from I = 0 to 23 of bi*2**(I+1) s).</code> 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.
*
* <p>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
*
* <p>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();
}
}

@ -0,0 +1,119 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
public final class BdaTriggerConditions extends BdaBitString {
public BdaTriggerConditions(ObjectReference objectReference, Fc fc) {
super(objectReference, fc, null, 6, false, false);
basicType = BdaType.TRIGGER_CONDITIONS;
setDefault();
}
@Override
public void setDefault() {
/* default of GI is true by default in IEC 61850-6 sec. 9.3.8 */
value = new byte[] {0x04};
}
@Override
public BdaTriggerConditions copy() {
BdaTriggerConditions copy = new BdaTriggerConditions(objectReference, fc);
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;
}
public boolean isDataChange() {
return (value[0] & 0x40) == 0x40;
}
public void setDataChange(boolean dataChange) {
if (dataChange) {
value[0] = (byte) (value[0] | 0x40);
} else {
value[0] = (byte) (value[0] & 0xbf);
}
}
public boolean isQualityChange() {
return (value[0] & 0x20) == 0x20;
}
public void setQualityChange(boolean qualityChange) {
if (qualityChange) {
value[0] = (byte) (value[0] | 0x20);
} else {
value[0] = (byte) (value[0] & 0xdf);
}
}
public boolean isDataUpdate() {
return (value[0] & 0x10) == 0x10;
}
public void setDataUpdate(boolean dataUpdate) {
if (dataUpdate) {
value[0] = (byte) (value[0] | 0x10);
} else {
value[0] = (byte) (value[0] & 0xef);
}
}
public boolean isIntegrity() {
return (value[0] & 0x08) == 0x08;
}
public void setIntegrity(boolean integrity) {
if (integrity) {
value[0] = (byte) (value[0] | 0x08);
} else {
value[0] = (byte) (value[0] & 0xf7);
}
}
public boolean isGeneralInterrogation() {
return (value[0] & 0x04) == 0x04;
}
public void setGeneralInterrogation(boolean generalInterrogation) {
if (generalInterrogation) {
value[0] = (byte) (value[0] | 0x04);
} else {
value[0] = (byte) (value[0] & 0xfb);
}
}
@Override
public String toString() {
return super.toString()
+ ", data change: "
+ isDataChange()
+ ", data update: "
+ isDataUpdate()
+ ", quality change:"
+ isQualityChange()
+ ", integrity period: "
+ isIntegrity()
+ ", GI: "
+ isGeneralInterrogation();
}
}

@ -0,0 +1,44 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
/**
* This Enumeration includes all possible Types for IEC 61850 leave nodes ( {@link
* BasicDataAttribute}). This includes BasicTypes and CommonACSITypes as defined in part 7-2.
*/
public enum BdaType {
BOOLEAN,
INT8,
INT16,
INT32,
INT64,
INT128,
INT8U,
INT16U,
INT32U,
FLOAT32,
FLOAT64,
OCTET_STRING,
VISIBLE_STRING,
UNICODE_STRING,
TIMESTAMP,
ENTRY_TIME,
CHECK,
QUALITY,
DOUBLE_BIT_POS,
TAP_COMMAND,
TRIGGER_CONDITIONS,
OPTFLDS,
REASON_FOR_INCLUSION
}

@ -0,0 +1,115 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.beanit.iec61850bean.internal.mms.asn1.Data;
import com.beanit.iec61850bean.internal.mms.asn1.Integer32;
import com.beanit.iec61850bean.internal.mms.asn1.MMSString;
import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription;
public final class BdaUnicodeString extends BasicDataAttribute {
private final int maxLength;
private byte[] value;
public BdaUnicodeString(
ObjectReference objectReference,
Fc fc,
String sAddr,
int maxLength,
boolean dchg,
boolean dupd) {
super(objectReference, fc, sAddr, dchg, dupd);
basicType = BdaType.UNICODE_STRING;
this.maxLength = maxLength;
setDefault();
}
public byte[] getValue() {
return value;
}
public void setValue(byte[] value) {
if (value == null || value.length > maxLength) {
throw new IllegalArgumentException(
"Value was null or UNICODE_STRING value size exceeds maxLength of " + maxLength);
}
this.value = value;
}
@Override
public void setValueFrom(BasicDataAttribute bda) {
byte[] srcValue = ((BdaUnicodeString) bda).getValue();
if (value.length != srcValue.length) {
value = new byte[srcValue.length];
}
System.arraycopy(srcValue, 0, value, 0, srcValue.length);
}
public int getMaxLength() {
return maxLength;
}
@Override
public void setDefault() {
value = new byte[0];
}
@Override
public BdaUnicodeString copy() {
BdaUnicodeString copy = new BdaUnicodeString(objectReference, fc, sAddr, maxLength, 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.setMMSString(new MMSString(value));
return data;
}
@Override
void setValueFromMmsDataObj(Data data) throws ServiceError {
if (data.getMMSString() == null) {
throw new ServiceError(
ServiceError.TYPE_CONFLICT, "expected type: mms_string/unicode_string");
}
value = data.getMMSString().value;
}
@Override
TypeDescription getMmsTypeSpec() {
TypeDescription typeDescription = new TypeDescription();
typeDescription.setMMSString(new Integer32(maxLength * -1));
return typeDescription;
}
@Override
public String toString() {
if (value == null) {
return getReference().toString() + ": null";
}
return getReference().toString() + ": " + new String(value, UTF_8);
}
}

@ -0,0 +1,130 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.beanit.asn1bean.ber.types.string.BerVisibleString;
import com.beanit.iec61850bean.internal.mms.asn1.Data;
import com.beanit.iec61850bean.internal.mms.asn1.Integer32;
import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription;
public final class BdaVisibleString extends BasicDataAttribute {
private final int maxLength;
private byte[] value;
public BdaVisibleString(
ObjectReference objectReference,
Fc fc,
String sAddr,
int maxLength,
boolean dchg,
boolean dupd) {
super(objectReference, fc, sAddr, dchg, dupd);
basicType = BdaType.VISIBLE_STRING;
this.maxLength = maxLength;
setDefault();
}
public byte[] getValue() {
return value;
}
public void setValue(byte[] value) {
if (value == null || value.length > maxLength) {
throw new IllegalArgumentException(
"value was null or VISIBLE_STRING value size exceeds maxLength of " + maxLength);
}
this.value = value;
}
public void setValue(String value) {
setValue(value.getBytes(UTF_8));
}
@Override
public void setValueFrom(BasicDataAttribute bda) {
byte[] srcValue = ((BdaVisibleString) bda).getValue();
if (value.length != srcValue.length) {
value = new byte[srcValue.length];
}
System.arraycopy(srcValue, 0, value, 0, srcValue.length);
}
public int getMaxLength() {
return maxLength;
}
public String getStringValue() {
return new String(value, UTF_8);
}
@Override
public void setDefault() {
value = new byte[0];
}
@Override
public BdaVisibleString copy() {
BdaVisibleString copy = new BdaVisibleString(objectReference, fc, sAddr, maxLength, 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.setVisibleString(new BerVisibleString(value));
return data;
}
@Override
void setValueFromMmsDataObj(Data data) throws ServiceError {
if (data.getVisibleString() == null) {
throw new ServiceError(ServiceError.TYPE_CONFLICT, "expected type: visible_string");
}
value = data.getVisibleString().value;
}
@Override
TypeDescription getMmsTypeSpec() {
TypeDescription typeDescription = new TypeDescription();
typeDescription.setVisibleString(new Integer32(maxLength * -1));
return typeDescription;
}
@Override
public String toString() {
if (value == null) {
return getReference().toString() + ": null";
}
if (value.length == 0 || value[0] == (byte) 0) {
return getReference().toString() + ": ''";
}
return getReference().toString() + ": " + new String(value, UTF_8);
}
@Override
public String getValueString() {
return new String(value, UTF_8);
}
}

@ -0,0 +1,57 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import java.util.ArrayList;
import java.util.List;
public class Brcb extends Rcb {
public Brcb(ObjectReference objectReference, List<FcModelNode> children) {
super(objectReference, Fc.BR, children);
}
public BdaBoolean getPurgeBuf() {
return (BdaBoolean) children.get("PurgeBuf");
}
public BdaOctetString getEntryId() {
return (BdaOctetString) children.get("EntryID");
}
public BdaEntryTime getTimeOfEntry() {
return (BdaEntryTime) children.get("TimeOfEntry");
}
/**
* Gets the ResvTms attribute. This attribute is optional. Will return NULL if the attribute is
* not available.
*
* @return the ResvTms attribute, null if not available.
*/
public BdaInt16 getResvTms() {
return (BdaInt16) children.get("ResvTms");
}
@Override
public FcDataObject copy() {
List<FcModelNode> childCopies = new ArrayList<>(children.size());
for (ModelNode childNode : children.values()) {
childCopies.add((FcModelNode) childNode.copy());
}
Brcb brcb = new Brcb(objectReference, childCopies);
brcb.dataSet = dataSet;
return brcb;
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,44 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import java.io.IOException;
/**
* The listener interface for receiving incoming reports and association closed events. A listener
* is registered through the {@link ClientSap#associate(java.net.InetAddress, int, String,
* ClientEventListener) associate} method.
*
* @author Stefan Feuerhahn
*/
public interface ClientEventListener {
/**
* Invoked when a new report arrives. Note that the implementation of this method needs to be
* thread safe as it can be called in parallel if a new report arrives while an old one is still
* being processed.
*
* @param report the report that arrived.
*/
void newReport(Report report);
/**
* Invoked when an IOException occurred for the association. An IOException implies that the
* ClientAssociation that feeds this listener was automatically closed and can no longer be used
* to receive reports.
*
* @param e the exception that occured.
*/
void associationClosed(IOException e);
}

@ -0,0 +1,346 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import com.beanit.josistack.ClientAcseSap;
import java.io.IOException;
import java.net.InetAddress;
import javax.net.SocketFactory;
/**
* The <code>ClientSap</code> class represents the IEC 61850 service access point for client
* applications. A client application that wants to connect to a server should first create an
* instance of <code>ClientSap</code>. Next all the necessary configuration parameters can be set.
* Finally the <code>associate</code> function is called to connect to the server. An instance of
* <code>ClientSap</code> can be used to create an unlimited number of associations. Changing the
* parameters of a ClientSap has no affect on associations that have already been created.
*/
public final class ClientSap {
static final int MINIMUM_MMS_PDU_SIZE = 64;
private static final int MAXIMUM_MMS_PDU_SIZE = 65000;
private static final byte[] DEFAULT_TSEL_LOCAL = new byte[] {0, 0};
private static final byte[] DEFAULT_TSEL_REMOTE = new byte[] {0, 1};
private static final int DEFAULT_TPDU_SIZE_PARAMETER = 10; // size = 1024
private final ClientAcseSap acseSap;
private int proposedMaxServOutstandingCalling = 5;
private int proposedMaxServOutstandingCalled = 5;
private int proposedDataStructureNestingLevel = 10;
private int proposedMaxMmsPduSize = 65000;
private byte[] servicesSupportedCalling =
new byte[] {(byte) 0xee, 0x1c, 0, 0, 0x04, 0x08, 0, 0, 0x79, (byte) 0xef, 0x18};
private int messageFragmentTimeout = 10000;
private int responseTimeout = 20000;
/** Use this constructor to create a default client SAP. */
public ClientSap() {
acseSap = new ClientAcseSap();
acseSap.tSap.tSelLocal = DEFAULT_TSEL_LOCAL;
acseSap.tSap.tSelRemote = DEFAULT_TSEL_REMOTE;
acseSap.tSap.setMaxTPDUSizeParam(DEFAULT_TPDU_SIZE_PARAMETER);
}
/**
* Use this constructor to create a client SAP that uses the given <code>SocketFactory</code> to
* connect to servers. You could pass an SSLSocketFactory to enable SSL.
*
* @param socketFactory the socket factory to construct the socket
*/
public ClientSap(SocketFactory socketFactory) {
acseSap = new ClientAcseSap(socketFactory);
acseSap.tSap.tSelLocal = DEFAULT_TSEL_LOCAL;
acseSap.tSap.tSelRemote = DEFAULT_TSEL_REMOTE;
acseSap.tSap.setMaxTPDUSizeParam(DEFAULT_TPDU_SIZE_PARAMETER);
}
/**
* Gets the maximum MMS PDU size.
*
* @return the maximum MMS PDU size.
*/
public int getMaxMmsPduSize() {
return proposedMaxMmsPduSize;
}
/**
* Sets the maximum MMS PDU size in bytes that the client association will support. The client
* proposes this value to the server during association. If the server requires the use of a
* smaller maximum MMS PDU size, then the smaller size will be accepted by the client. The default
* size is 65000.
*
* @param size cannot be less than 64. The upper limit is 65000 so that segmentation at the lower
* transport layer is avoided. The Transport Layer's maximum PDU size is 65531.
*/
public void setMaxMmsPduSize(int size) {
if (size >= MINIMUM_MMS_PDU_SIZE && size <= MAXIMUM_MMS_PDU_SIZE) {
proposedMaxMmsPduSize = size;
} else {
throw new IllegalArgumentException("maximum size is out of bound");
}
}
public void setProposedMaxServOutstandingCalling(int proposedMaxServOutstandingCalling) {
this.proposedMaxServOutstandingCalling = proposedMaxServOutstandingCalling;
}
public void setProposedMaxServOutstandingCalled(int proposedMaxServOutstandingCalled) {
this.proposedMaxServOutstandingCalled = proposedMaxServOutstandingCalled;
}
public void setProposedDataStructureNestingLevel(int proposedDataStructureNestingLevel) {
this.proposedDataStructureNestingLevel = proposedDataStructureNestingLevel;
}
/**
* Gets the ServicesSupportedCalling parameter.
*
* @return the ServicesSupportedCalling parameter.
*/
public byte[] getServicesSupportedCalling() {
return servicesSupportedCalling;
}
/**
* Sets the SevicesSupportedCalling parameter. The given parameter is sent to the server but has
* no affect on the functionality of this client.
*
* @param services the ServicesSupportedCalling parameter
*/
public void setServicesSupportedCalling(byte[] services) {
if (services.length != 11) {
throw new IllegalArgumentException("The services parameter needs to be of lenth 11");
}
servicesSupportedCalling = services;
}
/**
* Sets the remote/called Session-Selector (S-SEL). The default remote S-SEL is byte[] { 0, 1 }.
*
* @param sSelRemote the remote/called S-SEL.
*/
public void setSSelRemote(byte[] sSelRemote) {
acseSap.sSelRemote = sSelRemote;
}
/**
* Sets the local/calling Session-Selector (S-SEL). The default local S-SEL is byte[] { 0, 1 }.
*
* @param sSelLocal the local/calling S-SEL.
*/
public void setSSelLocal(byte[] sSelLocal) {
acseSap.sSelLocal = sSelLocal;
}
/**
* Sets the remote/called Presentation-Selector (P-SEL). The default remote P-SEL is byte[] { 0,
* 0, 0, 1 }.
*
* @param pSelRemote the remote/called P-SEL.
*/
public void setPSelRemote(byte[] pSelRemote) {
acseSap.pSelRemote = pSelRemote;
}
/**
* Sets the local/calling Presentation-Selector (P-SEL). The default local P-SEL is byte[] { 0, 0,
* 0, 1 }.
*
* @param pSelLocal the local/calling P-SEL.
*/
public void setPSelLocal(byte[] pSelLocal) {
acseSap.pSelLocal = pSelLocal;
}
/**
* Sets the remote/called Transport-Selector (T-SEL). It is optionally transmitted in the OSI
* Transport Layer connection request (CR). The default remote T-SEL is byte[] { 0, 1 }.
*
* @param tSelRemote the remote/called T-SEL. If null the T-SEL will be omitted. No maximum size
* is defined by the standard.
*/
public void setTSelRemote(byte[] tSelRemote) {
acseSap.tSap.tSelRemote = tSelRemote;
}
/**
* Sets the local/calling Transport-Selector (T-SEL). It is optionally transmitted in the OSI
* Transport Layer connection request (CR). The default local T-SEL byte[] { 0, 0 }.
*
* @param tSelLocal the local/calling T-SEL. If null the T-SEL will be omitted. No maximum size is
* defined by the standard.
*/
public void setTSelLocal(byte[] tSelLocal) {
acseSap.tSap.tSelLocal = tSelLocal;
}
/**
* Set the maxTPDUSize. The default maxTPduSize is 65531 (see RFC 1006).
*
* @param maxTPduSizeParam The maximum length is equal to 2^(maxTPduSizeParam) octets. Note that
* the actual TSDU size that can be transfered is equal to TPduSize-3. Default is 65531 octets
* (see RFC 1006), 7 &lt;= maxTPduSizeParam &lt;= 16, needs to be set before listening or
* connecting
*/
public void setMaxTPduSizeParameter(int maxTPduSizeParam) {
acseSap.tSap.setMaxTPDUSizeParam(maxTPduSizeParam);
}
/**
* Sets the remote/called Application Process Title. The default value is int[] { 1, 1, 999, 1, 1
* }
*
* @param title the remote/called AP title.
*/
public void setApTitleCalled(int[] title) {
acseSap.setApTitleCalled(title);
}
/**
* Sets the local/calling Application Process Title. The default value is int[] { 1, 1, 999, 1 }
*
* @param title the local/calling AP title.
*/
public void setApTitleCalling(int[] title) {
acseSap.setApTitleCalling(title);
}
/**
* Sets the remote/called Application Entity Qualifier. The default value is 12.
*
* @param qualifier the remote/called AE Qualifier
*/
public void setAeQualifierCalled(int qualifier) {
acseSap.setAeQualifierCalled(qualifier);
}
/**
* Sets the local/calling Application Entity Qualifier. The default value is 12.
*
* @param qualifier the local/calling AE Qualifier
*/
public void setAeQualifierCalling(int qualifier) {
acseSap.setAeQualifierCalling(qualifier);
}
/**
* Sets the default response timeout of the <code>ClientAssociation</code> that is created using
* this ClientSap.
*
* @param timeout the response timeout in milliseconds. The default is 20000.
*/
public void setResponseTimeout(int timeout) {
responseTimeout = timeout;
}
/**
* Sets the message fragment timeout. This is the timeout that the socket timeout is set to after
* the first byte of a message has been received. A request function (e.g. setDataValues()) will
* throw an IOException if the socket throws this timeout because the association/connection
* cannot recover from this kind of error.
*
* @param timeout the timeout in milliseconds. The default is 10000.
*/
public void setMessageFragmentTimeout(int timeout) {
messageFragmentTimeout = timeout;
}
/**
* Connects to the IEC 61850 MMS server at the given address and port and returns the resulting
* association object.
*
* @param address the address to connect to.
* @param port the port to connect to. Usually the MMS port is 102.
* @param authenticationParameter an optional authentication parameters that is transmitted. It
* will be omitted if equal to null.
* @param reportListener the listener to be notified of incoming reports
* @return the association object
* @throws IOException if any kind of error occurs trying build up the association
*/
public ClientAssociation associate(
InetAddress address,
int port,
String authenticationParameter,
ClientEventListener reportListener)
throws IOException {
return associate(address, port, authenticationParameter, null, -1, reportListener);
}
/**
* Connects to the IEC 61850 MMS server at the given address and port and returns the resulting
* association object.
*
* @param address the address to connect to
* @param port the port to connect to. Usually the MMS port is 102.
* @param authenticationParameter an optional authentication parameters that is transmitted. It
* will be omitted if equal to null.
* @param localAddr the local address to use
* @param localPort the local port to use
* @param reportListener the listener to be notified of incoming reports
* @return the association object.
* @throws IOException if any kind of error occurs trying build up the association
*/
public ClientAssociation associate(
InetAddress address,
int port,
String authenticationParameter,
InetAddress localAddr,
int localPort,
ClientEventListener reportListener)
throws IOException {
if (port < 0 || port > 65535) {
throw new IllegalArgumentException("invalid port");
}
if (address == null) {
throw new IllegalArgumentException("address may not be null");
}
if (acseSap.sSelRemote == null) {
throw new IllegalArgumentException("sSelRemote may not be null");
}
if (acseSap.sSelRemote.length != 2) {
throw new IllegalArgumentException("sSelRemote lenght must be two");
}
if (acseSap.sSelLocal == null) {
throw new IllegalArgumentException("sSelLocal may not be null");
}
if (acseSap.sSelLocal.length != 2) {
throw new IllegalArgumentException("sSelLocal lenght must be two");
}
ClientAssociation clientAssociation =
new ClientAssociation(
address,
port,
localAddr,
localPort,
authenticationParameter,
acseSap,
proposedMaxMmsPduSize,
proposedMaxServOutstandingCalling,
proposedMaxServOutstandingCalled,
proposedDataStructureNestingLevel,
servicesSupportedCalling,
responseTimeout,
messageFragmentTimeout,
reportListener);
return clientAssociation;
}
}

@ -0,0 +1,87 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import com.beanit.iec61850bean.internal.mms.asn1.Data;
import com.beanit.iec61850bean.internal.mms.asn1.Data.Structure;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
public final class ConstructedDataAttribute extends FcModelNode {
public ConstructedDataAttribute(
ObjectReference objectReference, Fc fc, List<FcModelNode> children) {
this.objectReference = objectReference;
this.fc = fc;
this.children = new LinkedHashMap<>((int) ((children.size() / 0.75) + 1));
for (ModelNode child : children) {
this.children.put(child.getName(), child);
child.setParent(this);
}
}
@Override
public ConstructedDataAttribute copy() {
List<FcModelNode> subDataAttributesCopy = new ArrayList<>();
for (ModelNode subDA : children.values()) {
subDataAttributesCopy.add((FcModelNode) subDA.copy());
}
return new ConstructedDataAttribute(getReference(), fc, subDataAttributesCopy);
}
@Override
Data getMmsDataObj() {
Structure structure = new Structure();
List<Data> seq = structure.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(structure);
return data;
}
@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<Data> iterator = data.getStructure().getData().iterator();
for (ModelNode child : children.values()) {
child.setValueFromMmsDataObj(iterator.next());
}
}
}

@ -0,0 +1,274 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import com.beanit.iec61850bean.internal.mms.asn1.ConfirmedServiceResponse;
import com.beanit.iec61850bean.internal.mms.asn1.GetVariableAccessAttributesResponse;
import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription;
import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription.Structure.Components;
import com.beanit.iec61850bean.internal.mms.asn1.TypeSpecification;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
final class DataDefinitionResParser {
static LogicalNode parseGetDataDefinitionResponse(
ConfirmedServiceResponse confirmedServiceResponse, ObjectReference lnRef)
throws ServiceError {
if (confirmedServiceResponse.getGetVariableAccessAttributes() == null) {
throw new ServiceError(
ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT,
"decodeGetDataDefinitionResponse: Error decoding GetDataDefinitionResponsePdu");
}
GetVariableAccessAttributesResponse varAccAttrs =
confirmedServiceResponse.getGetVariableAccessAttributes();
TypeDescription typeSpec = varAccAttrs.getTypeDescription();
if (typeSpec.getStructure() == null) {
throw new ServiceError(
ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT,
"decodeGetDataDefinitionResponse: Error decoding GetDataDefinitionResponsePdu");
}
Components structure = typeSpec.getStructure().getComponents();
List<FcDataObject> fcDataObjects = new ArrayList<>();
Fc fc;
for (TypeDescription.Structure.Components.SEQUENCE fcComponent : structure.getSEQUENCE()) {
if (fcComponent.getComponentName() == null) {
throw new ServiceError(
ServiceError.PARAMETER_VALUE_INAPPROPRIATE,
"Error decoding GetDataDefinitionResponsePdu");
}
if (fcComponent.getComponentType().getTypeDescription().getStructure() == null) {
throw new ServiceError(
ServiceError.PARAMETER_VALUE_INAPPROPRIATE,
"Error decoding GetDataDefinitionResponsePdu");
}
String fcString = fcComponent.getComponentName().toString();
if (fcString.equals("LG")
|| fcString.equals("GO")
|| fcString.equals("GS")
|| fcString.equals("MS")
|| fcString.equals("US")) {
continue;
}
fc = Fc.fromString(fcComponent.getComponentName().toString());
Components subStructure =
fcComponent.getComponentType().getTypeDescription().getStructure().getComponents();
fcDataObjects.addAll(getFcDataObjectsFromSubStructure(lnRef, fc, subStructure));
}
LogicalNode ln = new LogicalNode(lnRef, fcDataObjects);
return ln;
}
private static List<FcDataObject> getFcDataObjectsFromSubStructure(
ObjectReference lnRef, Fc fc, Components components) throws ServiceError {
List<TypeDescription.Structure.Components.SEQUENCE> structComponents = components.getSEQUENCE();
List<FcDataObject> dataObjects = new ArrayList<>(structComponents.size());
for (TypeDescription.Structure.Components.SEQUENCE doComp : structComponents) {
if (doComp.getComponentName() == null) {
throw new ServiceError(
ServiceError.PARAMETER_VALUE_INAPPROPRIATE,
"Error decoding GetDataDefinitionResponsePdu");
}
if (doComp.getComponentType().getTypeDescription() == null) {
throw new ServiceError(
ServiceError.PARAMETER_VALUE_INAPPROPRIATE,
"Error decoding GetDataDefinitionResponsePdu");
}
ObjectReference doRef =
new ObjectReference(lnRef + "." + doComp.getComponentName().toString());
List<FcModelNode> children =
getDoSubModelNodesFromSubStructure(
doRef,
fc,
doComp.getComponentType().getTypeDescription().getStructure().getComponents());
if (fc == Fc.RP) {
dataObjects.add(new Urcb(doRef, children));
} else if (fc == Fc.BR) {
dataObjects.add(new Brcb(doRef, children));
} else {
dataObjects.add(new FcDataObject(doRef, fc, children));
}
}
return dataObjects;
}
private static List<FcModelNode> getDoSubModelNodesFromSubStructure(
ObjectReference parentRef, Fc fc, Components structure) throws ServiceError {
Collection<TypeDescription.Structure.Components.SEQUENCE> structComponents =
structure.getSEQUENCE();
List<FcModelNode> dataObjects = new ArrayList<>(structComponents.size());
for (TypeDescription.Structure.Components.SEQUENCE component : structComponents) {
if (component.getComponentName() == null) {
throw new ServiceError(
ServiceError.PARAMETER_VALUE_INAPPROPRIATE,
"Error decoding GetDataDefinitionResponsePdu");
}
String childName = component.getComponentName().toString();
dataObjects.add(
getModelNodesFromTypeSpecification(
new ObjectReference(parentRef + "." + childName), fc, component.getComponentType()));
}
return dataObjects;
}
private static FcModelNode getModelNodesFromTypeSpecification(
ObjectReference ref, Fc fc, TypeSpecification mmsTypeSpec) throws ServiceError {
if (mmsTypeSpec.getTypeDescription().getArray() != null) {
int numArrayElements =
mmsTypeSpec.getTypeDescription().getArray().getNumberOfElements().intValue();
List<FcModelNode> arrayChildren = new ArrayList<>(numArrayElements);
for (int i = 0; i < numArrayElements; i++) {
arrayChildren.add(
getModelNodesFromTypeSpecification(
new ObjectReference(ref + "(" + i + ")"),
fc,
mmsTypeSpec.getTypeDescription().getArray().getElementType()));
}
return new Array(ref, fc, arrayChildren);
}
if (mmsTypeSpec.getTypeDescription().getStructure() != null) {
List<FcModelNode> children =
getDoSubModelNodesFromSubStructure(
ref, fc, mmsTypeSpec.getTypeDescription().getStructure().getComponents());
return (new ConstructedDataAttribute(ref, fc, children));
}
// it is a single element
BasicDataAttribute bt = convertMmsBasicTypeSpec(ref, fc, mmsTypeSpec.getTypeDescription());
if (bt == null) {
throw new ServiceError(
ServiceError.PARAMETER_VALUE_INAPPROPRIATE,
"decodeGetDataDefinitionResponse: Unknown data type received " + ref);
}
return (bt);
}
private static BasicDataAttribute convertMmsBasicTypeSpec(
ObjectReference ref, Fc fc, TypeDescription mmsTypeSpec) throws ServiceError {
if (mmsTypeSpec.getBool() != null) {
return new BdaBoolean(ref, fc, null, false, false);
}
if (mmsTypeSpec.getBitString() != null) {
int bitStringMaxLength = Math.abs(mmsTypeSpec.getBitString().intValue());
if (bitStringMaxLength == 13) {
return new BdaQuality(ref, fc, null, false);
} else if (bitStringMaxLength == 10) {
return new BdaOptFlds(ref, fc);
} else if (bitStringMaxLength == 6) {
return new BdaTriggerConditions(ref, fc);
} else if (bitStringMaxLength == 2) {
if (fc == Fc.CO) {
// if name == ctlVal
if (ref.getName().charAt(1) == 't') {
return new BdaTapCommand(ref, fc, null, false, false);
}
// name == Check
else {
return new BdaCheck(ref);
}
} else {
return new BdaDoubleBitPos(ref, fc, null, false, false);
}
}
return null;
} else if (mmsTypeSpec.getInteger() != null) {
switch (mmsTypeSpec.getInteger().intValue()) {
case 8:
return new BdaInt8(ref, fc, null, false, false);
case 16:
return new BdaInt16(ref, fc, null, false, false);
case 32:
return new BdaInt32(ref, fc, null, false, false);
case 64:
return new BdaInt64(ref, fc, null, false, false);
case 128:
return new BdaInt128(ref, fc, null, false, false);
}
} else if (mmsTypeSpec.getUnsigned() != null) {
switch (mmsTypeSpec.getUnsigned().intValue()) {
case 8:
return new BdaInt8U(ref, fc, null, false, false);
case 16:
return new BdaInt16U(ref, fc, null, false, false);
case 32:
return new BdaInt32U(ref, fc, null, false, false);
}
} else if (mmsTypeSpec.getFloatingPoint() != null) {
int floatSize = mmsTypeSpec.getFloatingPoint().getFormatWidth().intValue();
if (floatSize == 32) {
return new BdaFloat32(ref, fc, null, false, false);
} else if (floatSize == 64) {
return new BdaFloat64(ref, fc, null, false, false);
}
throw new ServiceError(
ServiceError.PARAMETER_VALUE_INAPPROPRIATE,
"FLOAT of size: " + floatSize + " is not supported.");
} else if (mmsTypeSpec.getOctetString() != null) {
int stringSize = mmsTypeSpec.getOctetString().intValue();
if (stringSize > 255 || stringSize < -255) {
throw new ServiceError(
ServiceError.PARAMETER_VALUE_INAPPROPRIATE,
"OCTET_STRING of size: " + stringSize + " is not supported.");
}
return new BdaOctetString(ref, fc, null, Math.abs(stringSize), false, false);
} else if (mmsTypeSpec.getVisibleString() != null) {
int stringSize = mmsTypeSpec.getVisibleString().intValue();
if (stringSize > 255 || stringSize < -255) {
throw new ServiceError(
ServiceError.PARAMETER_VALUE_INAPPROPRIATE,
"VISIBLE_STRING of size: " + stringSize + " is not supported.");
}
return new BdaVisibleString(ref, fc, null, Math.abs(stringSize), false, false);
} else if (mmsTypeSpec.getMMSString() != null) {
int stringSize = mmsTypeSpec.getMMSString().intValue();
if (stringSize > 255 || stringSize < -255) {
throw new ServiceError(
ServiceError.PARAMETER_VALUE_INAPPROPRIATE,
"UNICODE_STRING of size: " + stringSize + " is not supported.");
}
return new BdaUnicodeString(ref, fc, null, Math.abs(stringSize), false, false);
} else if (mmsTypeSpec.getUtcTime() != null) {
return new BdaTimestamp(ref, fc, null, false, false);
} else if (mmsTypeSpec.getBinaryTime() != null) {
return new BdaEntryTime(ref, fc, null, false, false);
}
return null;
}
}

@ -0,0 +1,152 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.beanit.iec61850bean.internal.mms.asn1.Identifier;
import com.beanit.iec61850bean.internal.mms.asn1.ObjectName;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public final class DataSet implements Iterable<FcModelNode> {
private final String dataSetReference;
private final List<FcModelNode> members;
private final Map<Fc, Map<String, FcModelNode>> membersMap = new EnumMap<>(Fc.class);
private final boolean deletable;
private ObjectName mmsObjectName = null;
public DataSet(String dataSetReference, List<FcModelNode> members) {
this(dataSetReference, members, true);
}
public DataSet(String dataSetReference, List<FcModelNode> members, boolean deletable) {
if (!dataSetReference.startsWith("@") && dataSetReference.indexOf('/') == -1) {
throw new IllegalArgumentException(
"DataSet reference "
+ dataSetReference
+ " is invalid. Must either start with @ or contain a slash.");
}
this.members = new ArrayList<>();
this.dataSetReference = dataSetReference;
this.deletable = deletable;
for (Fc myfc : Fc.values()) {
membersMap.put(myfc, new LinkedHashMap<String, FcModelNode>());
}
for (FcModelNode member : members) {
this.members.add(member);
membersMap.get(member.getFc()).put(member.getReference().toString(), member);
}
}
public String getReferenceStr() {
return dataSetReference;
}
public DataSet copy() {
List<FcModelNode> membersCopy = new ArrayList<>(members.size());
for (FcModelNode node : members) {
membersCopy.add((FcModelNode) node.copy());
}
return new DataSet(dataSetReference, membersCopy, deletable);
}
public FcModelNode getMember(ObjectReference memberReference, Fc fc) {
if (fc != null) {
return membersMap.get(fc).get(memberReference.toString());
}
for (FcModelNode member : members) {
if (member.getReference().toString().equals(memberReference.toString())) {
return member;
}
}
return null;
}
public FcModelNode getMember(int index) {
return members.get(index);
}
public List<FcModelNode> getMembers() {
return members;
}
/**
* Those DataSets defined in the SCL file are not deletable. All other DataSets are deletable.
* Note that no Reports/Logs may be using the DataSet otherwise it cannot be deleted (but this
* function will still return true).
*
* @return true if deletable
*/
public boolean isDeletable() {
return deletable;
}
@Override
public Iterator<FcModelNode> iterator() {
return members.iterator();
}
public List<BasicDataAttribute> getBasicDataAttributes() {
List<BasicDataAttribute> subBasicDataAttributes = new ArrayList<>();
for (ModelNode member : members) {
subBasicDataAttributes.addAll(member.getBasicDataAttributes());
}
return subBasicDataAttributes;
}
ObjectName getMmsObjectName() {
if (mmsObjectName != null) {
return mmsObjectName;
}
if (dataSetReference.charAt(0) == '@') {
mmsObjectName = new ObjectName();
mmsObjectName.setAaSpecific(new Identifier(dataSetReference.getBytes(UTF_8)));
return mmsObjectName;
}
int slash = dataSetReference.indexOf('/');
String domainID = dataSetReference.substring(0, slash);
String itemID = dataSetReference.substring(slash + 1).replace('.', '$');
ObjectName.DomainSpecific domainSpecificObjectName = new ObjectName.DomainSpecific();
domainSpecificObjectName.setDomainID(new Identifier(domainID.getBytes(UTF_8)));
domainSpecificObjectName.setItemID(new Identifier(itemID.getBytes(UTF_8)));
mmsObjectName = new ObjectName();
mmsObjectName.setDomainSpecific(domainSpecificObjectName);
return mmsObjectName;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getReferenceStr());
for (FcModelNode member : members) {
sb.append("\n");
sb.append(member.toString());
}
return sb.toString();
}
}

@ -0,0 +1,61 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
public enum Fc {
// The following FCs are not part of this enum because they are not really
// FCs and only defined in part 8-1:
// RP (report), LG (log), BR (buffered report), GO, GS, MS, US
// FCs according to IEC 61850-7-2:
/** Status information */
ST,
/** Measurands - analogue values */
MX,
/** Setpoint */
SP,
/** Substitution */
SV,
/** Configuration */
CF,
/** Description */
DC,
/** Setting group */
SG,
/** Setting group editable */
SE,
/** Service response / Service tracking */
SR,
/** Operate received */
OR,
/** Blocking */
BL,
/** Extended definition */
EX,
/** Control, deprecated but kept here for backward compatibility */
CO,
/** Unbuffered Reporting */
RP,
/** Buffered Reporting */
BR;
public static Fc fromString(String fc) {
try {
return Fc.valueOf(fc);
} catch (Exception e) {
return null;
}
}
}

@ -0,0 +1,95 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import com.beanit.iec61850bean.internal.mms.asn1.Data;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
/**
* This class represents a functionally constraint DataObject. That means it has unique reference
* and FunctionalConstraint. A DataObject as defined in part 7-3 is made up of 1..n FcDataObjects
* where n is the number of different FunctionalConstraints that the children of the DataObject
* have. An FcDataObject can have children of types FcDataObject, Array, ConstructedDataAttribute or
* BasicDataAttribute.
*
* @author Stefan Feuerhahn
*/
public class FcDataObject extends FcModelNode {
public FcDataObject(ObjectReference objectReference, Fc fc, List<FcModelNode> 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;
}
@Override
public FcDataObject copy() {
List<FcModelNode> childCopies = new ArrayList<>(children.size());
for (ModelNode childNode : children.values()) {
childCopies.add((FcModelNode) childNode.copy());
}
return new FcDataObject(objectReference, fc, childCopies);
}
@Override
Data getMmsDataObj() {
Data.Structure dataStructure = new Data.Structure();
List<Data> 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;
}
@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<Data> iterator = data.getStructure().getData().iterator();
for (ModelNode child : children.values()) {
child.setValueFromMmsDataObj(iterator.next());
}
}
}

@ -0,0 +1,252 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
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.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;
public abstract class FcModelNode extends ModelNode {
Fc fc;
private VariableDefs.SEQUENCE variableDef = null;
private ServerAssociation selected = null;
private TimerTask task = null;
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);
}
ModelNode sboTimeoutNode =
association.serverModel.findModelNode(objectReference, Fc.CF).getChild("sboTimeout");
if (sboTimeoutNode == null) {
return true;
}
long sboTimeout = ((BdaInt32U) sboTimeoutNode).getValue();
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);
}
}
}
}
if (task != null) {
task.cancel();
}
task = new SelectResetTask(association);
timer.schedule(task, sboTimeout);
return true;
}
void deselectAndRemove(ServerAssociation association) {
selected = null;
if (task != null) {
task.cancel();
task = null;
}
association.selects.remove(this);
}
void deselect() {
selected = null;
if (task != null) {
task.cancel();
task = null;
}
}
boolean isSelected() {
return selected != null;
}
boolean isSelectedBy(ServerAssociation association) {
return selected == association;
}
VariableDefs.SEQUENCE getMmsVariableDef() {
if (variableDef != null) {
return variableDef;
}
AlternateAccess alternateAccess = null;
StringBuilder preArrayIndexItemId = new StringBuilder(objectReference.get(1));
preArrayIndexItemId.append("$");
preArrayIndexItemId.append(fc);
int arrayIndexPosition = objectReference.getArrayIndexPosition();
if (arrayIndexPosition != -1) {
for (int i = 2; i < arrayIndexPosition; i++) {
preArrayIndexItemId.append("$");
preArrayIndexItemId.append(objectReference.get(i));
}
alternateAccess = new AlternateAccess();
List<AlternateAccess.CHOICE> subSeqOfAlternateAccess = alternateAccess.getCHOICE();
Unsigned32 indexBerInteger =
new Unsigned32(Integer.parseInt(objectReference.get(arrayIndexPosition)));
if (arrayIndexPosition < (objectReference.size() - 1)) {
// this reference points to a sub-node of an array element
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<AlternateAccess.CHOICE> 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);
}
} else {
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);
VariableSpecification varSpec = new VariableSpecification();
varSpec.setName(objectName);
variableDef = new VariableDefs.SEQUENCE();
variableDef.setAlternateAccess(alternateAccess);
variableDef.setVariableSpecification(varSpec);
return variableDef;
}
@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();
}
}

@ -0,0 +1,51 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import java.util.Calendar;
/** Contains file information received by the GetFileDirectory service */
public class FileInformation {
private final String filename;
private final long fileSize;
private final Calendar lastModified;
public FileInformation(String filename, long fileSize, Calendar lastModified) {
super();
this.filename = filename;
this.fileSize = fileSize;
this.lastModified = lastModified;
}
public String getFilename() {
return filename;
}
public long getFileSize() {
return fileSize;
}
/**
* Get the time stamp of last modification. As it is an optional attribute the return value can be
* null
*
* @return the time stamp of last modification, or null if the time stamp is not present
*/
public Calendar getLastModified() {
return lastModified;
}
}

@ -0,0 +1,26 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
/** Callback handler for GetFile service */
public interface GetFileListener {
/**
* Is called when a new block of file data is received
*
* @param fileData block of file data received
* @param moreFollows true if more data blocks will follow, false otherwise
* @return true to continue the GetFile service, false to cancel
*/
boolean dataReceived(byte[] fileData, boolean moreFollows);
}

@ -0,0 +1,39 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
public final class LogicalDevice extends ModelNode {
public LogicalDevice(ObjectReference objectReference, List<LogicalNode> logicalNodes) {
children = new LinkedHashMap<>((int) ((logicalNodes.size() / 0.75) + 1));
this.objectReference = objectReference;
for (LogicalNode logicalNode : logicalNodes) {
children.put(logicalNode.getReference().getName(), logicalNode);
logicalNode.setParent(this);
}
}
@Override
public LogicalDevice copy() {
List<LogicalNode> childCopies = new ArrayList<>(children.size());
for (ModelNode childNode : children.values()) {
childCopies.add((LogicalNode) childNode.copy());
}
return new LogicalDevice(objectReference, childCopies);
}
}

@ -0,0 +1,137 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public final class LogicalNode extends ModelNode {
private final Map<Fc, Map<String, FcDataObject>> fcDataObjects = new EnumMap<>(Fc.class);
private final Map<String, Urcb> urcbs = new HashMap<>();
private final Map<String, Brcb> brcbs = new HashMap<>();
public LogicalNode(ObjectReference objectReference, List<FcDataObject> fcDataObjects) {
children = new LinkedHashMap<>();
for (Fc fc : Fc.values()) {
this.fcDataObjects.put(fc, new LinkedHashMap<String, FcDataObject>());
}
this.objectReference = objectReference;
for (FcDataObject fcDataObject : fcDataObjects) {
children.put(
fcDataObject.getReference().getName() + fcDataObject.fc.toString(), fcDataObject);
this.fcDataObjects
.get(fcDataObject.getFc())
.put(fcDataObject.getReference().getName(), fcDataObject);
fcDataObject.setParent(this);
if (fcDataObject.getFc() == Fc.RP) {
addUrcb((Urcb) fcDataObject, false);
} else if (fcDataObject.getFc() == Fc.BR) {
addBrcb((Brcb) fcDataObject);
}
}
}
@Override
public LogicalNode copy() {
List<FcDataObject> dataObjectsCopy = new ArrayList<>();
for (ModelNode obj : children.values()) {
dataObjectsCopy.add((FcDataObject) obj.copy());
}
LogicalNode copy = new LogicalNode(objectReference, dataObjectsCopy);
return copy;
}
public List<FcDataObject> getChildren(Fc fc) {
Map<String, FcDataObject> requestedDataObjectsMap = fcDataObjects.get(fc);
if (requestedDataObjectsMap == null) {
return null;
}
Collection<FcDataObject> fcChildren = requestedDataObjectsMap.values();
if (fcChildren.size() == 0) {
return null;
} else {
return new ArrayList<>(fcChildren);
}
}
void addUrcb(Urcb urcb, boolean addDataSet) {
urcbs.put(urcb.getReference().getName(), urcb);
if (addDataSet) {
String dataSetRef = urcb.getDatSet().getStringValue();
if (dataSetRef != null) {
urcb.dataSet =
((ServerModel) getParent().getParent()).getDataSet(dataSetRef.replace('$', '.'));
}
}
}
public Collection<Urcb> getUrcbs() {
return urcbs.values();
}
public Urcb getUrcb(String urcbName) {
return urcbs.get(urcbName);
}
void addBrcb(Brcb brcb) {
brcbs.put(brcb.getReference().getName(), brcb);
}
public Brcb getBrcb(String brcbName) {
return brcbs.get(brcbName);
}
public Collection<Brcb> getBrcbs() {
return brcbs.values();
}
@Override
public ModelNode getChild(String childName, Fc fc) {
if (fc != null) {
return fcDataObjects.get(fc).get(childName);
}
for (Map<String, FcDataObject> map : fcDataObjects.values()) {
FcDataObject fcDataObject = map.get(childName);
if (fcDataObject != null) {
return fcDataObject;
}
}
return null;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getReference().toString());
for (Map<String, FcDataObject> fcChildNodes : fcDataObjects.values()) {
for (ModelNode childNode : fcChildNodes.values()) {
sb.append("\n");
sb.append(childNode.toString());
}
}
return sb.toString();
}
}

@ -0,0 +1,178 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.beanit.iec61850bean.internal.mms.asn1.Data;
import com.beanit.iec61850bean.internal.mms.asn1.Identifier;
import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription;
import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription.Structure;
import com.beanit.iec61850bean.internal.mms.asn1.TypeDescription.Structure.Components;
import com.beanit.iec61850bean.internal.mms.asn1.TypeSpecification;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public abstract class ModelNode implements Iterable<ModelNode> {
protected ObjectReference objectReference;
protected Map<String, ModelNode> children;
ModelNode parent;
/**
* Returns a copy of model node with all of its children. Creates new BasicDataAttribute values
* but reuses ObjectReferences, FunctionalConstraints.
*
* @return a copy of model node with all of its children.
*/
public abstract ModelNode copy();
/**
* Returns the child node with the given name. Will always return null if called on a logical node
* because a logical node need the functional constraint to uniquely identify a child. For logical
* nodes use <code>getChild(String name, Fc fc)</code> instead.
*
* @param name the name of the requested child node
* @return the child node with the given name.
*/
public ModelNode getChild(String name) {
return getChild(name, null);
}
/**
* Returns the child node with the given name and functional constraint. The fc is ignored if this
* function is called on any model node other than logical node.
*
* @param name the name of the requested child node
* @param fc the functional constraint of the requested child node
* @return the child node with the given name and functional constrain
*/
public ModelNode getChild(String name, Fc fc) {
return children.get(name);
}
@SuppressWarnings("unchecked")
public Collection<ModelNode> getChildren() {
if (children == null) {
return null;
}
return children.values();
}
protected Iterator<Iterator<? extends ModelNode>> getIterators() {
List<Iterator<? extends ModelNode>> iterators = new ArrayList<>();
if (children != null) {
iterators.add(children.values().iterator());
}
return iterators.iterator();
}
/**
* Returns the reference of the model node.
*
* @return the reference of the model node.
*/
public ObjectReference getReference() {
return objectReference;
}
/**
* Returns the name of the model node.
*
* @return the name of the model node.
*/
public String getName() {
return objectReference.getName();
}
@Override
public Iterator<ModelNode> iterator() {
return children.values().iterator();
}
/**
* Returns a list of all leaf nodes (basic data attributes) contained in the subtree of this model
* node.
*
* @return a list of all leaf nodes (basic data attributes) contained in the subtree of this model
* node.
*/
public List<BasicDataAttribute> getBasicDataAttributes() {
List<BasicDataAttribute> subBasicDataAttributes = new ArrayList<>();
for (ModelNode child : children.values()) {
subBasicDataAttributes.addAll(child.getBasicDataAttributes());
}
return subBasicDataAttributes;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getReference().toString());
for (ModelNode childNode : children.values()) {
sb.append("\n");
sb.append(childNode.toString());
}
return sb.toString();
}
/**
* Returns the parent node of this node.
*
* @return the parent node of this node.
*/
public ModelNode getParent() {
return parent;
}
void setParent(ModelNode parent) {
this.parent = parent;
}
Data getMmsDataObj() {
return null;
}
void setValueFromMmsDataObj(Data data) throws ServiceError {}
TypeDescription getMmsTypeSpec() {
Components componentsSequenceType = new Components();
List<TypeDescription.Structure.Components.SEQUENCE> structComponents =
componentsSequenceType.getSEQUENCE();
for (ModelNode child : children.values()) {
TypeSpecification typeSpecification = new TypeSpecification();
typeSpecification.setTypeDescription(child.getMmsTypeSpec());
TypeDescription.Structure.Components.SEQUENCE component =
new TypeDescription.Structure.Components.SEQUENCE();
component.setComponentName(new Identifier(child.getName().getBytes(UTF_8)));
component.setComponentType(typeSpecification);
structComponents.add(component);
}
Structure structure = new Structure();
structure.setComponents(componentsSequenceType);
TypeDescription typeDescription = new TypeDescription();
typeDescription.setStructure(structure);
return typeDescription;
}
}

@ -0,0 +1,175 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/** ObjectReference syntax: LDName/LNName.DOName[.Name[. ...]] */
public final class ObjectReference implements Iterable<String> {
private final String objectReference;
private List<String> nodeNames = null;
// if the ObjectReference contains an array index this variable will save
// its position in the nodeNames List
private int arrayIndexPosition = -1;
public ObjectReference(String objectReference) {
if (objectReference == null || objectReference.isEmpty()) {
throw new IllegalArgumentException();
}
this.objectReference = objectReference;
}
/**
* Returns name part of the reference.
*
* @return the name
*/
public String getName() {
if (nodeNames == null) {
parseForNameList();
}
return nodeNames.get(nodeNames.size() - 1);
}
public String getLdName() {
if (nodeNames == null) {
parseForNameList();
}
return nodeNames.get(0);
}
@Override
public String toString() {
return objectReference;
}
public boolean isLogicalDeviceRef() {
if (nodeNames == null) {
parseForNameList();
}
return (nodeNames.size() == 1);
}
public boolean isLogicalNodeRef() {
if (nodeNames == null) {
parseForNameList();
}
return (nodeNames.size() == 2);
}
public boolean isDataRef() {
if (nodeNames == null) {
parseForNameList();
}
return (nodeNames.size() > 2);
}
int getArrayIndexPosition() {
if (nodeNames == null) {
parseForNameList();
}
return arrayIndexPosition;
}
@Override
public Iterator<String> iterator() {
if (nodeNames == null) {
parseForNameList();
}
return nodeNames.iterator();
}
public String get(int i) {
if (nodeNames == null) {
parseForNameList();
}
return nodeNames.get(i);
}
public int size() {
if (nodeNames == null) {
parseForNameList();
}
return nodeNames.size();
}
private void parseForNameList() {
nodeNames = new ArrayList<>();
int lastDelim = -1;
int nextDelim = objectReference.indexOf('/');
if (nextDelim == -1) {
nodeNames.add(objectReference.substring(lastDelim + 1));
return;
}
nodeNames.add(objectReference.substring(lastDelim + 1, nextDelim));
int dotIndex = -1;
int openingbracketIndex = -1;
int closingbracketIndex = -1;
while (true) {
lastDelim = nextDelim;
if (dotIndex == -1) {
dotIndex = objectReference.indexOf('.', lastDelim + 1);
if (dotIndex == -1) {
dotIndex = objectReference.length();
}
}
if (openingbracketIndex == -1) {
openingbracketIndex = objectReference.indexOf('(', lastDelim + 1);
if (openingbracketIndex == -1) {
openingbracketIndex = objectReference.length();
}
}
if (closingbracketIndex == -1) {
closingbracketIndex = objectReference.indexOf(')', lastDelim + 1);
if (closingbracketIndex == -1) {
closingbracketIndex = objectReference.length();
}
}
if (dotIndex == openingbracketIndex && dotIndex == closingbracketIndex) {
nodeNames.add(objectReference.substring(lastDelim + 1));
return;
}
if (dotIndex < openingbracketIndex && dotIndex < closingbracketIndex) {
nextDelim = dotIndex;
dotIndex = -1;
} else if (openingbracketIndex < dotIndex && openingbracketIndex < closingbracketIndex) {
nextDelim = openingbracketIndex;
openingbracketIndex = -1;
arrayIndexPosition = nodeNames.size() + 1;
} else if (closingbracketIndex < dotIndex && closingbracketIndex < openingbracketIndex) {
if (closingbracketIndex == (objectReference.length() - 1)) {
nodeNames.add(objectReference.substring(lastDelim + 1, closingbracketIndex));
return;
}
nextDelim = closingbracketIndex + 1;
closingbracketIndex = -1;
dotIndex = -1;
nodeNames.add(objectReference.substring(lastDelim + 1, nextDelim - 1));
continue;
}
nodeNames.add(objectReference.substring(lastDelim + 1, nextDelim));
}
}
}

@ -0,0 +1,117 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import java.util.List;
public abstract class Rcb extends FcDataObject {
DataSet dataSet;
protected Rcb(ObjectReference objectReference, Fc fc, List<FcModelNode> children) {
super(objectReference, fc, children);
}
/**
* Gets the RptID (Report ID). The RptID will be included in every report sent by the server. If
* it is equal to NULL, then the RptID sent will be equal to the reference of the RCB.
*
* @return the report ID
*/
public BdaVisibleString getRptId() {
return (BdaVisibleString) children.get("RptID");
}
/**
* Gets the boolean value which states whether reporting is enabled.
*
* @return BdaBoolean that contains true as value if reporting is enabled.
*/
public BdaBoolean getRptEna() {
return (BdaBoolean) children.get("RptEna");
}
/**
* Gets the object reference of the DataSet that is to be monitored for reporting events.
*
* @return the object reference of the DataSet
*/
public BdaVisibleString getDatSet() {
return (BdaVisibleString) children.get("DatSet");
}
/**
* Configuration revision The attribute ConfRev shall represent a count of the number of times
* that the configuration of the DATA-SET referenced by DatSet has been changed. Changes that
* shall be counted are:
*
* <ul>
* <li>any deletion of a member of the DATA-SET;
* <li>the reordering of members of the DATA-SET; and
* <li>Successful SetBRCBValues of the DatSet attribute where the DatSet attribute value
* changes.
* </ul>
*
* The counter shall be incremented when the configuration changes. At configuration time, the
* configuration tool will be responsible for incrementing/maintaining the ConfRev value. When
* configuration changes occur due to SetBRCBValues, the IED shall be responsible for incrementing
* the value of ConfRev.
*
* @return the configuration revision
*/
public BdaInt32U getConfRev() {
return (BdaInt32U) children.get("ConfRev");
}
/**
* Gets the optional fields parameter which specifies which optional fields should be included in
* the reports sent by this RCB.
*
* @return the optional fields parameter
*/
public BdaOptFlds getOptFlds() {
return (BdaOptFlds) children.get("OptFlds");
}
/**
* Gets the buffer time - The attribute BufTm (see Figure 27) shall specify the time interval in
* milliseconds for the buffering of internal notifications caused by data-change (dchg),
* quality-change (qchg), data update (dupd) by the BRCB for inclusion into a single report.
*
* @return the buffer time
*/
public BdaInt32U getBufTm() {
return (BdaInt32U) children.get("BufTm");
}
/**
* Gets the sequence number - The attribute SqNum shall specify the sequence number for each BRCB
* that has report enable set to TRUE. This number is to be incremented by the BRCB for each
* report generated and sent. The increment shall occur once the BRCB has formatted the report and
* requested for transmission.
*
* @return the sequence number
*/
public BdaInt8U getSqNum() {
return (BdaInt8U) children.get("SqNum");
}
public BdaTriggerConditions getTrgOps() {
return (BdaTriggerConditions) children.get("TrgOps");
}
public BdaInt32U getIntgPd() {
return (BdaInt32U) children.get("IntgPd");
}
}

@ -0,0 +1,189 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import com.beanit.iec61850bean.internal.HexString;
import java.util.List;
public class Report {
private final String rptId;
private final Integer sqNum;
private final Integer subSqNum;
private final boolean moreSegmentsFollow;
private final String dataSetRef;
private final Boolean bufOvfl;
private final Long confRev;
private final BdaEntryTime timeOfEntry;
private final BdaOctetString entryId;
private final boolean[] inclusionBitString;
private final List<FcModelNode> values;
private final List<BdaReasonForInclusion> reasonCodes;
public Report(
String rptId,
Integer sqNum,
Integer subSqNum,
boolean moreSegmentsFollow,
String dataSetRef,
Boolean bufOvfl,
Long confRev,
BdaEntryTime timeOfEntry,
BdaOctetString entryId,
boolean[] inclusionBitString,
List<FcModelNode> values,
List<BdaReasonForInclusion> reasonCodes) {
this.rptId = rptId;
this.sqNum = sqNum;
this.subSqNum = subSqNum;
this.moreSegmentsFollow = moreSegmentsFollow;
this.dataSetRef = dataSetRef;
this.bufOvfl = bufOvfl;
this.confRev = confRev;
this.timeOfEntry = timeOfEntry;
this.entryId = entryId;
this.inclusionBitString = inclusionBitString;
this.values = values;
this.reasonCodes = reasonCodes;
}
public String getRptId() {
return rptId;
}
/**
* Sequence numberThe parameter MoreSegmentsFollow indicates that more report segments with the
* same sequence number follow, counted up for every {@code Report} instance generated
*
* @return the sequence number
*/
public Integer getSqNum() {
return sqNum;
}
/**
* For the case of long reports that do not fit into one message, a single report shall be divided
* into subreports. Each segment of one report shall be numbered with the same sequence number
* and a unique SubSqNum.
*
* @return the subsequence number
*/
public Integer getSubSqNum() {
return subSqNum;
}
/**
* The parameter MoreSegmentsFollow indicates that more report segments with the same sequence
* number follow
*
* @return true if more segments follow
*/
public boolean isMoreSegmentsFollow() {
return moreSegmentsFollow;
}
public String getDataSetRef() {
return dataSetRef;
}
/**
* The parameter BufOvfl shall indicate to the client that entries within the buffer may have been
* lost. The detection of possible loss of information occurs when a client requests a
* resynchronization to a non-existent entry or to the first entry in the queue.
*
* @return true if buffer overflow is true
*/
public Boolean getBufOvfl() {
return bufOvfl;
}
public Long getConfRev() {
return confRev;
}
/**
* The parameter TimeOfEntry shall specify the time when the EntryID was created
*
* @return the time of entry
*/
public BdaEntryTime getTimeOfEntry() {
return timeOfEntry;
}
public BdaOctetString getEntryId() {
return entryId;
}
/**
* Indicator of data set members included in the report
*
* @return the inclusion bit string as a byte array
*/
public boolean[] getInclusionBitString() {
return inclusionBitString;
}
/**
* Gets the reasons for inclusion
*
* @return the reasons for inclusion
*/
public List<BdaReasonForInclusion> getReasonCodes() {
return reasonCodes;
}
public List<FcModelNode> getValues() {
return values;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Report ID: ").append(rptId);
sb.append("\nData set reference: ").append(dataSetRef);
if (sqNum != null) {
sb.append("\nSequence number: ").append(sqNum);
}
if (subSqNum != null) {
sb.append("\nSubsequence number: ").append(subSqNum);
if (moreSegmentsFollow) {
sb.append(" (more segments follow)");
}
}
if (timeOfEntry != null) {
sb.append("\nTime of entry (unix timestamp): ").append(timeOfEntry.getTimestampValue());
}
if (bufOvfl != null) {
sb.append("\nBuffer overflow: ").append(bufOvfl);
}
if (entryId != null) {
sb.append("\nEntry ID: ").append(HexString.fromBytes(entryId.getValue()));
}
if (confRev != null) {
sb.append("\nConfiguration revision: ").append(confRev.toString());
}
sb.append("\nReported data set members:");
int index = 0;
for (FcModelNode reportedDataSetMember : values) {
sb.append("\n").append(reportedDataSetMember.toString());
if (reasonCodes != null) {
sb.append(", reason: ").append(reasonCodes.get(index));
}
index++;
}
return sb.toString();
}
}

@ -0,0 +1,78 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
public class ReportEntryData {
/** Not specified in IEC61850 but useful for data persistence */
private long id;
/** Reference to to {@link DataSet}-member */
private String dataRef;
/** Attribute value to be reported */
private ModelNode value;
/** Trigger that caused the data to be put into the report */
// private TriggerConditions reasonCode;
private ReasonCode reasonCode;
/** Backreference to report */
private Report report;
public String getDataRef() {
return dataRef;
}
public void setDataRef(String dataRef) {
this.dataRef = dataRef;
}
public ModelNode getValue() {
return value;
}
public void setValue(ModelNode value) {
this.value = value;
}
public ReasonCode getReasonCode() {
return reasonCode;
}
public void setReasonCode(ReasonCode reasonCode) {
this.reasonCode = reasonCode;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public Report getReport() {
return report;
}
public void setReport(Report report) {
this.report = report;
}
public enum ReasonCode {
DCHG,
QCHG,
DUPD,
INTEGRITY,
GI,
APPTRIGGER
}
}

@ -0,0 +1,27 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
public final class SclParseException extends Exception {
private static final long serialVersionUID = 8499804369026418082L;
public SclParseException(String string) {
super(string);
}
public SclParseException(Exception e) {
super(e);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,35 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import java.util.List;
public interface ServerEventListener {
/**
* The write callback function is called if one of more basic data attributes are written using
* either the setDataValue, setDataSetValues or control services. If the complete write process
* was successful write returns either an empty list or null. If an error occurs writing one or
* more attributes then a list shall be returned that is of equal size as the list of basic data
* attributes. The returned list's element shall be null if writing the corresponding BDA was
* successful and a service error otherwise.
*
* @param bdas the list of basic data attributes that are to be set.
* @return a list of service errors indicating errors writing the corresponding basic data
* attributes.
*/
List<ServiceError> write(List<BasicDataAttribute> bdas);
void serverStoppedListening(ServerSap serverSAP);
}

@ -0,0 +1,400 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import com.beanit.iec61850bean.internal.mms.asn1.AlternateAccessSelection;
import com.beanit.iec61850bean.internal.mms.asn1.ObjectName;
import com.beanit.iec61850bean.internal.mms.asn1.ObjectName.DomainSpecific;
import com.beanit.iec61850bean.internal.mms.asn1.VariableDefs;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public final class ServerModel extends ModelNode {
private final Map<String, DataSet> dataSets = new LinkedHashMap<>();
private final Map<String, Urcb> urcbs = new HashMap<>();
private final Map<String, Brcb> brcbs = new HashMap<>();
public ServerModel(List<LogicalDevice> logicalDevices, Collection<DataSet> dataSets) {
children = new LinkedHashMap<>();
objectReference = null;
for (LogicalDevice logicalDevice : logicalDevices) {
children.put(logicalDevice.getReference().getName(), logicalDevice);
logicalDevice.setParent(this);
}
if (dataSets != null) {
addDataSets(dataSets);
}
for (LogicalDevice ld : logicalDevices) {
for (ModelNode ln : ld.getChildren()) {
for (Urcb urcb : ((LogicalNode) ln).getUrcbs()) {
urcbs.put(urcb.getReference().toString(), urcb);
urcb.dataSet = getDataSet(urcb.getDatSet().getStringValue().replace('$', '.'));
}
for (Brcb brcb : ((LogicalNode) ln).getBrcbs()) {
brcbs.put(brcb.getReference().toString(), brcb);
brcb.dataSet = getDataSet(brcb.getDatSet().getStringValue().replace('$', '.'));
}
}
}
}
@Override
public ServerModel copy() {
List<LogicalDevice> childCopies = new ArrayList<>(children.size());
for (ModelNode childNode : children.values()) {
childCopies.add((LogicalDevice) childNode.copy());
}
List<DataSet> dataSetCopies = new ArrayList<>(dataSets.size());
for (DataSet dataSet : dataSets.values()) {
dataSetCopies.add(dataSet);
}
return new ServerModel(childCopies, dataSetCopies);
}
/**
* Get the data set with the given reference. Return null if none is found.
*
* @param reference the reference of the requested data set.
* @return the data set with the given reference.
*/
public DataSet getDataSet(String reference) {
return dataSets.get(reference);
}
void addDataSet(DataSet dataSet) {
dataSets.put(dataSet.getReferenceStr().replace('$', '.'), dataSet);
for (ModelNode ld : children.values()) {
for (ModelNode ln : ld.getChildren()) {
for (Urcb urcb : ((LogicalNode) ln).getUrcbs()) {
urcb.dataSet = getDataSet(urcb.getDatSet().getStringValue().replace('$', '.'));
}
for (Brcb brcb : ((LogicalNode) ln).getBrcbs()) {
brcb.dataSet = getDataSet(brcb.getDatSet().getStringValue().replace('$', '.'));
}
}
}
}
void addDataSets(Collection<DataSet> dataSets) {
for (DataSet dataSet : dataSets) {
addDataSet(dataSet);
}
for (ModelNode ld : children.values()) {
for (ModelNode ln : ld.getChildren()) {
for (Urcb urcb : ((LogicalNode) ln).getUrcbs()) {
urcb.dataSet = getDataSet(urcb.getDatSet().getStringValue().replace('$', '.'));
}
for (Brcb brcb : ((LogicalNode) ln).getBrcbs()) {
brcb.dataSet = getDataSet(brcb.getDatSet().getStringValue().replace('$', '.'));
}
}
}
}
List<String> getDataSetNames(String ldName) {
// TODO make thread save
List<String> dataSetNames = new ArrayList<>();
for (String dataSetRef : dataSets.keySet()) {
if (dataSetRef.startsWith(ldName)) {
dataSetNames.add(dataSetRef.substring(dataSetRef.indexOf('/') + 1).replace('.', '$'));
}
}
return dataSetNames;
}
/**
* Get a collection of all data sets that exist in this model.
*
* @return a collection of all data sets
*/
public Collection<DataSet> getDataSets() {
return dataSets.values();
}
/**
* @param dataSetReference the data set reference
* @return returns the DataSet that was removed, null if no DataSet with the given reference was
* found or the data set is not deletable.
*/
DataSet removeDataSet(String dataSetReference) {
DataSet dataSet = dataSets.get(dataSetReference);
if (dataSet == null || !dataSet.isDeletable()) {
return null;
}
DataSet removedDataSet = dataSets.remove(dataSetReference);
for (ModelNode ld : children.values()) {
for (ModelNode ln : ld.getChildren()) {
for (Urcb urcb : ((LogicalNode) ln).getUrcbs()) {
urcb.dataSet = getDataSet(urcb.getDatSet().getStringValue().replace('$', '.'));
}
for (Brcb brcb : ((LogicalNode) ln).getBrcbs()) {
brcb.dataSet = getDataSet(brcb.getDatSet().getStringValue().replace('$', '.'));
}
}
}
return removedDataSet;
}
void addUrcb(Urcb urcb) {
urcbs.put(urcb.getReference().getName(), urcb);
}
/**
* Get the unbuffered report control block (URCB) with the given reference.
*
* @param reference the reference of the requested URCB.
* @return the reference to the requested URCB or null if none with the given reference is found.
*/
public Urcb getUrcb(String reference) {
return urcbs.get(reference);
}
/**
* Get a collection of all unbuffered report control blocks (URCB) that exist in this model.
*
* @return a collection of all unbuffered report control blocks (URCB)
*/
public Collection<Urcb> getUrcbs() {
return urcbs.values();
}
/**
* Get the buffered report control block (BRCB) with the given reference.
*
* @param reference the reference of the requested BRCB.
* @return the reference to the requested BRCB or null if none with the given reference is found.
*/
public Brcb getBrcb(String reference) {
return brcbs.get(reference);
}
/**
* Get a collection of all buffered report control blocks (BRCB) that exist in this model.
*
* @return a collection of all buffered report control blocks (BRCB)
*/
public Collection<Brcb> getBrcbs() {
return brcbs.values();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (ModelNode logicalDevice : children.values()) {
sb.append(logicalDevice.toString());
}
sb.append("\n\n\n---------------------\nURCBs:");
for (Urcb urcb : getUrcbs()) {
sb.append("\n\n").append(urcb);
}
sb.append("\n\n\n---------------------\nBRCBs:");
for (Brcb brcb : getBrcbs()) {
sb.append("\n\n").append(brcb);
}
sb.append("\n\n\n---------------------\nData sets:");
for (DataSet dataSet : getDataSets()) {
sb.append("\n\n").append(dataSet);
}
return sb.toString();
}
/**
* Searches and returns the model node with the given object reference and FC. If searching for
* Logical Devices and Logical Nodes the given fc parameter may be <code>null</code>.
*
* @param objectReference the object reference of the node that is being searched for. It has a
* syntax like "ldname/ln.do....".
* @param fc the functional constraint of the requested model node. May be null for Logical Device
* and Logical Node references.
* @return the model node if it was found or null otherwise
*/
public ModelNode findModelNode(ObjectReference objectReference, Fc fc) {
ModelNode currentNode = this;
Iterator<String> searchedNodeReferenceIterator = objectReference.iterator();
while (searchedNodeReferenceIterator.hasNext()) {
currentNode = currentNode.getChild(searchedNodeReferenceIterator.next(), fc);
if (currentNode == null) {
return null;
}
}
return currentNode;
}
/**
* Searches and returns the model node with the given object reference and FC. If searching for
* Logical Devices and Logical Nodes the given fc parameter may be <code>null</code>.
*
* @param objectReference the object reference of the node that is being searched for. It has a
* syntax like "ldname/ln.do....".
* @param fc the functional constraint of the requested model node. May be null for Logical Device
* and Logical Node references.
* @return the model node if it was found or null otherwise
*/
public ModelNode findModelNode(String objectReference, Fc fc) {
return findModelNode(new ObjectReference(objectReference), fc);
}
/**
* Returns the subModelNode that is referenced by the given VariableDef. Return null in case the
* referenced ModelNode is not found.
*
* @param variableDef the variableDef
* @return the subModelNode that is referenced by the given VariableDef
* @throws ServiceError if an error occurs
*/
FcModelNode getNodeFromVariableDef(VariableDefs.SEQUENCE variableDef) throws ServiceError {
ObjectName objectName = variableDef.getVariableSpecification().getName();
if (objectName == null) {
throw new ServiceError(
ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT,
"name in objectName is not selected");
}
DomainSpecific domainSpecific = objectName.getDomainSpecific();
if (domainSpecific == null) {
throw new ServiceError(
ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT,
"domain_specific in name is not selected");
}
ModelNode modelNode = getChild(domainSpecific.getDomainID().toString());
if (modelNode == null) {
return null;
}
String mmsItemId = domainSpecific.getItemID().toString();
int index1 = mmsItemId.indexOf('$');
if (index1 == -1) {
throw new ServiceError(
ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT,
"invalid mms item id: " + domainSpecific.getItemID());
}
LogicalNode ln = (LogicalNode) modelNode.getChild(mmsItemId.substring(0, index1));
if (ln == null) {
return null;
}
int index2 = mmsItemId.indexOf('$', index1 + 1);
if (index2 == -1) {
throw new ServiceError(
ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, "invalid mms item id");
}
Fc fc = Fc.fromString(mmsItemId.substring(index1 + 1, index2));
if (fc == null) {
throw new ServiceError(
ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT,
"unknown functional constraint: " + mmsItemId.substring(index1 + 1, index2));
}
index1 = index2;
index2 = mmsItemId.indexOf('$', index1 + 1);
if (index2 == -1) {
if (fc == Fc.RP) {
return ln.getUrcb(mmsItemId.substring(index1 + 1));
}
if (fc == Fc.BR) {
return ln.getBrcb(mmsItemId.substring(index1 + 1));
}
return (FcModelNode) ln.getChild(mmsItemId.substring(index1 + 1), fc);
}
if (fc == Fc.RP) {
modelNode = ln.getUrcb(mmsItemId.substring(index1 + 1, index2));
} else if (fc == Fc.BR) {
modelNode = ln.getBrcb(mmsItemId.substring(index1 + 1, index2));
} else {
modelNode = ln.getChild(mmsItemId.substring(index1 + 1, index2), fc);
}
index1 = index2;
index2 = mmsItemId.indexOf('$', index1 + 1);
while (index2 != -1) {
modelNode = modelNode.getChild(mmsItemId.substring(index1 + 1, index2));
index1 = index2;
index2 = mmsItemId.indexOf('$', index1 + 1);
}
modelNode = modelNode.getChild(mmsItemId.substring(index1 + 1));
if (variableDef.getAlternateAccess() == null) {
// no array is in this node path
return (FcModelNode) modelNode;
}
AlternateAccessSelection altAccIt =
variableDef.getAlternateAccess().getCHOICE().get(0).getUnnamed();
if (altAccIt.getSelectAlternateAccess() != null) {
// path to node below an array element
modelNode =
((Array) modelNode)
.getChild(
altAccIt.getSelectAlternateAccess().getAccessSelection().getIndex().intValue());
String mmsSubArrayItemId =
altAccIt
.getSelectAlternateAccess()
.getAlternateAccess()
.getCHOICE()
.get(0)
.getUnnamed()
.getSelectAccess()
.getComponent()
.getBasic()
.toString();
index1 = -1;
index2 = mmsSubArrayItemId.indexOf('$');
while (index2 != -1) {
modelNode = modelNode.getChild(mmsSubArrayItemId.substring(index1 + 1, index2));
index1 = index2;
index2 = mmsItemId.indexOf('$', index1 + 1);
}
return (FcModelNode) modelNode.getChild(mmsSubArrayItemId.substring(index1 + 1));
} else {
// path to an array element
return (FcModelNode)
((Array) modelNode).getChild(altAccIt.getSelectAccess().getIndex().intValue());
}
}
}

@ -0,0 +1,370 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import com.beanit.josistack.AcseAssociation;
import com.beanit.josistack.ServerAcseSap;
import java.io.IOException;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import javax.net.ServerSocketFactory;
/**
* The <code>ServerSap</code> class represents the IEC 61850 service access point for server
* applications. It corresponds to the AccessPoint defined in the ICD/SCL file. A server application
* that is to listen for client connections should first get an instance of <code>ServerSap</code>
* using the static function ServerSap.getSapsFromSclFile(). Next all the necessary configuration
* parameters can be set. Finally the <code>startListening</code> function is called to listen for
* client associations. Changing properties of a ServerSap after starting to listen is not
* recommended and has unknown effects.
*/
public final class ServerSap {
static final int MINIMUM_MMS_PDU_SIZE = 64;
private static final int MAXIMUM_MMS_PDU_SIZE = 65000;
final ServerModel serverModel;
final List<ServerAssociation> associations = new ArrayList<>();
byte[] servicesSupportedCalled =
new byte[] {(byte) 0xee, 0x1c, 0, 0, 0x04, 0x08, 0, 0, 0x79, (byte) 0xef, 0x18};
byte[] cbbBitString = {(byte) 0xfb, 0x00};
ServerEventListener serverEventListener;
Timer timer;
boolean listening = false;
private int proposedMaxMmsPduSize = 65000;
private int proposedMaxServOutstandingCalling = 5;
private int proposedMaxServOutstandingCalled = 5;
private int proposedDataStructureNestingLevel = 10;
private int maxAssociations = 100;
private ServerAcseSap acseSap;
private int port = 102;
private int backlog = 0;
private InetAddress bindAddr = null;
private ServerSocketFactory serverSocketFactory = null;
/**
* Creates a ServerSap.
*
* @param port local port to listen on for new connections
* @param backlog The maximum queue length for incoming connection indications (a request to
* connect) is set to the backlog parameter. If a connection indication arrives when the queue
* is full, the connection is refused. Set to 0 or less for the default value.
* @param bindAddr local IP address to bind to, pass null to bind to all
* @param serverModel the server model
* @param serverSocketFactory the factory class to generate the ServerSocket. Could be used to
* create SSLServerSockets. null = default
*/
public ServerSap(
int port,
int backlog,
InetAddress bindAddr,
ServerModel serverModel,
ServerSocketFactory serverSocketFactory) {
this.port = port;
this.backlog = backlog;
this.bindAddr = bindAddr;
this.serverSocketFactory = serverSocketFactory;
this.serverModel = serverModel;
}
public int getPort() {
return port;
}
/**
* Sets local port to listen on for new connections.
*
* @param port local port to listen on for new connections
*/
public void setPort(int port) {
this.port = port;
}
public int getBacklog() {
return backlog;
}
/**
* Sets the maximum queue length for incoming connection indications (a request to connect) is set
* to the backlog parameter. If a connection indication arrives when the queue is full, the
* connection is refused. Set to 0 or less for the default value.
*
* @param backlog the maximum queue length for incoming connections.
*/
public void setBacklog(int backlog) {
this.backlog = backlog;
}
public InetAddress getBindAddress() {
return bindAddr;
}
/**
* Sets the local IP address to bind to, pass null to bind to all
*
* @param bindAddr the local IP address to bind to
*/
public void setBindAddress(InetAddress bindAddr) {
this.bindAddr = bindAddr;
}
/**
* Sets the factory class to generate the ServerSocket. The ServerSocketFactory could be used to
* create SSLServerSockets. Set to <code>null</code> to use <code>ServerSocketFactory.getDefault()
* </code>.
*
* @param serverSocketFactory the factory class to generate the ServerSocket.
*/
public void setServerSocketFactory(ServerSocketFactory serverSocketFactory) {
this.serverSocketFactory = serverSocketFactory;
}
/**
* Gets the maximum MMS PDU size.
*
* @return the maximum MMS PDU size.
*/
public int getMaxMmsPduSize() {
return proposedMaxMmsPduSize;
}
/**
* Sets the maximum MMS PDU size in bytes that the server will support. If the client requires the
* use of a smaller maximum MMS PDU size, then the smaller size will be accepted by the server.
* The default size is 65000.
*
* @param size cannot be less than 64. The upper limit is 65000 so that segmentation at the lower
* transport layer is avoided. The Transport Layer's maximum PDU size is 65531.
*/
public void setMaxMmsPduSize(int size) {
if (size >= MINIMUM_MMS_PDU_SIZE && size <= MAXIMUM_MMS_PDU_SIZE) {
proposedMaxMmsPduSize = size;
} else {
throw new IllegalArgumentException("maximum size is out of bound");
}
}
/**
* Set the maximum number of associations that are allowed in parallel by the server.
*
* @param maxAssociations the number of associations allowed (default is 100)
*/
public void setMaxAssociations(int maxAssociations) {
this.maxAssociations = maxAssociations;
}
/**
* Sets the message fragment timeout. This is the timeout that the socket timeout is set to after
* the first byte of a message has been received. If such a timeout is thrown, the
* association/socket is closed.
*
* @param timeout the message fragment timeout in milliseconds. The default is 60000.
*/
public void setMessageFragmentTimeout(int timeout) {
acseSap.serverTSap.setMessageFragmentTimeout(timeout);
}
/**
* Gets the ProposedMaxServOutstandingCalling parameter.
*
* @return the ProposedMaxServOutstandingCalling parameter.
*/
public int getProposedMaxServOutstandingCalling() {
return proposedMaxServOutstandingCalling;
}
/**
* Sets the ProposedMaxServOutstandingCalling parameter. The given parameter has no affect on the
* functionality of this server.
*
* @param maxCalling the ProposedMaxServOutstandingCalling parameter. The default is 5.
*/
public void setProposedMaxServOutstandingCalling(int maxCalling) {
proposedMaxServOutstandingCalling = maxCalling;
}
/**
* Gets the ProposedMaxServOutstandingCalled parameter.
*
* @return the ProposedMaxServOutstandingCalled parameter.
*/
public int getProposedMaxServOutstandingCalled() {
return proposedMaxServOutstandingCalled;
}
/**
* Sets the ProposedMaxServOutstandingCalled parameter.The given parameter has no affect on the
* functionality of this server.
*
* @param maxCalled the ProposedMaxServOutstandingCalled parameter. The default is 5.
*/
public void setProposedMaxServOutstandingCalled(int maxCalled) {
proposedMaxServOutstandingCalled = maxCalled;
}
/**
* Gets the ProposedDataStructureNestingLevel parameter.
*
* @return the ProposedDataStructureNestingLevel parameter.
*/
public int getProposedDataStructureNestingLevel() {
return proposedDataStructureNestingLevel;
}
/**
* Sets the ProposedDataStructureNestingLevel parameter. The given parameter has no affect on the
* functionality of this server.runServer
*
* @param nestingLevel the ProposedDataStructureNestingLevel parameter. The default is 10.
*/
public void setProposedDataStructureNestingLevel(int nestingLevel) {
proposedDataStructureNestingLevel = nestingLevel;
}
/**
* Gets the ServicesSupportedCalled parameter.
*
* @return the ServicesSupportedCalled parameter.
*/
public byte[] getServicesSupportedCalled() {
return servicesSupportedCalled;
}
/**
* Sets the SevicesSupportedCalled parameter. The given parameter has no affect on the
* functionality of this server.
*
* @param services the ServicesSupportedCalled parameter
*/
public void setServicesSupportedCalled(byte[] services) {
if (services.length != 11) {
throw new IllegalArgumentException("The services parameter needs to be of lenth 11");
}
servicesSupportedCalled = services;
}
/**
* Creates a server socket waiting on the configured port for incoming association requests.
*
* @param serverEventListener the listener that is notified of incoming writes and when the server
* stopped listening for new connections.
* @throws IOException if an error occurs binding to the port.
*/
public void startListening(ServerEventListener serverEventListener) throws IOException {
timer = new Timer();
if (serverSocketFactory == null) {
serverSocketFactory = ServerSocketFactory.getDefault();
}
acseSap =
new ServerAcseSap(port, backlog, bindAddr, new AcseListener(this), serverSocketFactory);
acseSap.serverTSap.setMaxConnections(maxAssociations);
this.serverEventListener = serverEventListener;
listening = true;
acseSap.startListening();
}
/** Stops listening for new connections and closes all existing connections/associations. */
public void stop() {
acseSap.stopListening();
synchronized (associations) {
listening = false;
for (ServerAssociation association : associations) {
association.close();
}
associations.clear();
}
timer.cancel();
timer.purge();
}
void connectionIndication(AcseAssociation acseAssociation, ByteBuffer psdu) {
ServerAssociation association;
synchronized (associations) {
if (listening) {
association = new ServerAssociation(this);
associations.add(association);
} else {
acseAssociation.close();
return;
}
}
try {
association.handleNewAssociation(acseAssociation, psdu);
} catch (Exception e) {
// Association closed because of an unexpected exception.
}
association.close();
synchronized (associations) {
associations.remove(association);
}
}
void serverStoppedListeningIndication(IOException e) {
if (serverEventListener != null) {
serverEventListener.serverStoppedListening(this);
}
}
public ServerModel getModelCopy() {
return serverModel.copy();
}
public void setValues(List<BasicDataAttribute> bdas) {
synchronized (serverModel) {
for (BasicDataAttribute bda : bdas) {
// if (bda.getFunctionalConstraint() != FunctionalConstraint.ST) {
// logger.debug("fc:" + bda.getFunctionalConstraint());
// throw new IllegalArgumentException(
// "One can only set values of BDAs with Functional Constraint ST(status)");
// }
BasicDataAttribute bdaMirror = bda.mirror;
if (bdaMirror.dchg && bdaMirror.chgRcbs.size() != 0 && !bda.equals(bdaMirror)) {
bdaMirror.setValueFrom(bda);
synchronized (bdaMirror.chgRcbs) {
for (Urcb urcb : bdaMirror.chgRcbs) {
if (bdaMirror.dupd && urcb.getTrgOps().isDataUpdate()) {
urcb.report(bdaMirror, true, false, true);
} else {
urcb.report(bdaMirror, true, false, false);
}
}
}
} else if (bdaMirror.dupd && bdaMirror.dupdRcbs.size() != 0) {
bdaMirror.setValueFrom(bda);
synchronized (bdaMirror.dupdRcbs) {
for (Urcb urcb : bdaMirror.dupdRcbs) {
urcb.report(bdaMirror, false, false, true);
}
}
} else if (bdaMirror.qchg && bdaMirror.chgRcbs.size() != 0 && !bda.equals(bdaMirror)) {
bdaMirror.setValueFrom(bda);
synchronized (bdaMirror.chgRcbs) {
for (Urcb urcb : bdaMirror.chgRcbs) {
urcb.report(bdaMirror, false, true, false);
}
}
} else {
bdaMirror.setValueFrom(bda);
}
}
}
}
}

@ -0,0 +1,122 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
public final class ServiceError extends Exception {
public static final int NO_ERROR = 0;
public static final int INSTANCE_NOT_AVAILABLE = 1;
public static final int INSTANCE_IN_USE = 2;
public static final int ACCESS_VIOLATION = 3;
public static final int ACCESS_NOT_ALLOWED_IN_CURRENT_STATE = 4;
public static final int PARAMETER_VALUE_INAPPROPRIATE = 5;
public static final int PARAMETER_VALUE_INCONSISTENT = 6;
public static final int CLASS_NOT_SUPPORTED = 7;
public static final int INSTANCE_LOCKED_BY_OTHER_CLIENT = 8;
public static final int CONTROL_MUST_BE_SELECTED = 9;
public static final int TYPE_CONFLICT = 10;
public static final int FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT = 11;
public static final int FAILED_DUE_TO_SERVER_CONSTRAINT = 12;
public static final int APPLICATION_UNREACHABLE = 13;
public static final int CONNECTION_LOST = 14;
public static final int MEMORY_UNAVAILABLE = 15;
public static final int PROCESSOR_RESOURCE_UNAVAILABLE = 16;
public static final int FILE_NONE_EXISTENT = 17;
public static final int FATAL = 20;
// added to handle data access errors mentioned in iec61850-8-1
// public static final int DATA_ACCESS_ERROR = 21;
// added to report timeouts
public static final int TIMEOUT = 22;
public static final int UNKNOWN = 23;
private static final long serialVersionUID = 4290107163231828564L;
private final int errorCode;
public ServiceError(int errorCode) {
this(errorCode, "", null);
}
public ServiceError(int errorCode, String s) {
this(errorCode, s, null);
}
public ServiceError(int errorCode, Throwable cause) {
this(errorCode, "", cause);
}
public ServiceError(int errorCode, String s, Throwable cause) {
super(
"Service error: "
+ getErrorName(errorCode)
+ "("
+ errorCode
+ ")"
+ (s.isEmpty() ? "" : (" " + s)),
cause);
this.errorCode = errorCode;
}
private static String getErrorName(int code) {
switch (code) {
case NO_ERROR:
return "NO_ERROR";
case INSTANCE_NOT_AVAILABLE:
return "INSTANCE_NOT_AVAILABLE";
case INSTANCE_IN_USE:
return "INSTANCE_IN_USE";
case ACCESS_VIOLATION:
return "ACCESS_VIOLATION";
case ACCESS_NOT_ALLOWED_IN_CURRENT_STATE:
return "ACCESS_NOT_ALLOWED_IN_CURRENT_STATE";
case PARAMETER_VALUE_INAPPROPRIATE:
return "PARAMETER_VALUE_INAPPROPRIATE";
case PARAMETER_VALUE_INCONSISTENT:
return "PARAMETER_VALUE_INCONSISTENT";
case CLASS_NOT_SUPPORTED:
return "CLASS_NOT_SUPPORTED";
case INSTANCE_LOCKED_BY_OTHER_CLIENT:
return "INSTANCE_LOCKED_BY_OTHER_CLIENT";
case CONTROL_MUST_BE_SELECTED:
return "CONTROL_MUST_BE_SELECTED";
case TYPE_CONFLICT:
return "TYPE_CONFLICT";
case FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT:
return "FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT";
case FAILED_DUE_TO_SERVER_CONSTRAINT:
return "FAILED_DUE_TO_SERVER_CONSTRAINT";
case APPLICATION_UNREACHABLE:
return "APPLICATION_UNREACHABLE";
case CONNECTION_LOST:
return "CONNECTION_LOST";
case MEMORY_UNAVAILABLE:
return "MEMORY_UNAVAILABLE";
case PROCESSOR_RESOURCE_UNAVAILABLE:
return "PROCESSOR_RESOURCE_UNAVAILABLE";
case FILE_NONE_EXISTENT:
return "FILE_NONE_EXISTENT";
case FATAL:
return "FATAL";
case TIMEOUT:
return "TIMEOUT_ERROR";
case UNKNOWN:
return "UNKNOWN";
default:
return "Unknown ServiceError code";
}
}
public int getErrorCode() {
return errorCode;
}
}

@ -0,0 +1,27 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
public final class ServiceSupport {
public boolean dynAssociation = false;
public boolean getDirectory = false;
public boolean getDataObjectDefinition = false;
public boolean getDataSetValue = false;
public boolean dataSetDirectory = false;
public boolean readWrite = false;
public boolean getCBValues = false;
public boolean goose = false;
public int gooseMax = 0;
}

@ -0,0 +1,388 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.beanit.asn1bean.ber.types.BerBitString;
import com.beanit.iec61850bean.internal.mms.asn1.AccessResult;
import com.beanit.iec61850bean.internal.mms.asn1.Data;
import com.beanit.iec61850bean.internal.mms.asn1.Identifier;
import com.beanit.iec61850bean.internal.mms.asn1.InformationReport;
import com.beanit.iec61850bean.internal.mms.asn1.MMSpdu;
import com.beanit.iec61850bean.internal.mms.asn1.ObjectName;
import com.beanit.iec61850bean.internal.mms.asn1.UnconfirmedPDU;
import com.beanit.iec61850bean.internal.mms.asn1.UnconfirmedService;
import com.beanit.iec61850bean.internal.mms.asn1.VariableAccessSpecification;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class Urcb extends Rcb {
final HashMap<FcModelNode, BdaReasonForInclusion> membersToBeReported = new LinkedHashMap<>();
ServerAssociation reserved = null;
boolean enabled = false;
private Timer integrityTimer;
// private ScheduledFuture<?> integrityFuture = null;
private ScheduledFuture<?> bufTmFuture = null;
public Urcb(ObjectReference objectReference, List<FcModelNode> children) {
super(objectReference, Fc.RP, children);
}
/**
* Reserve URCB - The attribute Resv (if set to TRUE) shall indicate that the URCB is currently
* exclusively reserved for the client that has set the value to TRUE. Other clients shall not be
* allowed to set any attribute of that URCB.
*
* @return the Resv child
*/
public BdaBoolean getResv() {
return (BdaBoolean) children.get("Resv");
}
void enable() {
for (FcModelNode dataSetMember : dataSet) {
for (BasicDataAttribute bda : dataSetMember.getBasicDataAttributes()) {
if (bda.dchg) {
if (getTrgOps().isDataChange()) {
synchronized (bda.chgRcbs) {
bda.chgRcbs.add(this);
}
}
} else if (bda.qchg) {
if (getTrgOps().isQualityChange()) {
synchronized (bda.chgRcbs) {
bda.chgRcbs.add(this);
}
}
}
if (bda.dupd) {
if (getTrgOps().isDataUpdate()) {
synchronized (bda.dupdRcbs) {
bda.dupdRcbs.add(this);
}
}
}
}
}
if (getTrgOps().isIntegrity() && !(getIntgPd().getValue() < 10l)) {
integrityTimer = new Timer();
integrityTimer.schedule(
new TimerTask() {
// integrityFuture = reserved.executor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
synchronized (Urcb.this) {
if (!enabled) {
return;
}
reserved.sendAnMmsPdu(getMmsReport(true, false));
}
}
// }, getIntgPd().getValue(), getIntgPd().getValue(), TimeUnit.MILLISECONDS);
},
getIntgPd().getValue(),
getIntgPd().getValue());
}
enabled = true;
}
void disable() {
for (FcModelNode dataSetMember : dataSet) {
for (BasicDataAttribute bda : dataSetMember.getBasicDataAttributes()) {
if (bda.dchg) {
if (getTrgOps().isDataChange()) {
synchronized (bda.chgRcbs) {
bda.chgRcbs.remove(this);
}
}
} else if (bda.qchg) {
if (getTrgOps().isQualityChange()) {
synchronized (bda.chgRcbs) {
bda.chgRcbs.remove(this);
}
}
}
if (bda.dupd) {
if (getTrgOps().isDataUpdate()) {
synchronized (bda.dupdRcbs) {
bda.dupdRcbs.remove(this);
}
}
}
}
}
// if (integrityFuture != null) {
// integrityFuture.cancel(false);
// }
if (integrityTimer != null) {
integrityTimer.cancel();
}
enabled = false;
}
void generalInterrogation() {
reserved.executor.execute(
new Runnable() {
@Override
public void run() {
synchronized (Urcb.this) {
if (!enabled) {
return;
}
reserved.sendAnMmsPdu(getMmsReport(false, true));
}
}
});
}
private MMSpdu getMmsReport(boolean integrity, boolean gi) {
InformationReport.ListOfAccessResult listOfAccessResult =
new InformationReport.ListOfAccessResult();
List<AccessResult> accessResults = listOfAccessResult.getAccessResult();
AccessResult accessResult = new AccessResult();
accessResult.setSuccess(getRptId().getMmsDataObj());
accessResults.add(accessResult);
accessResult = new AccessResult();
accessResult.setSuccess(getOptFlds().getMmsDataObj());
accessResults.add(accessResult);
if (getOptFlds().isSequenceNumber()) {
accessResult = new AccessResult();
accessResult.setSuccess(getSqNum().getMmsDataObj());
accessResults.add(accessResult);
}
getSqNum().setValue((short) (getSqNum().getValue() + 1));
if (getOptFlds().isReportTimestamp()) {
BdaEntryTime entryTime = new BdaEntryTime(null, null, null, false, false);
entryTime.setTimestamp(System.currentTimeMillis());
accessResult = new AccessResult();
accessResult.setSuccess(entryTime.getMmsDataObj());
accessResults.add(accessResult);
}
if (getOptFlds().isDataSetName()) {
accessResult = new AccessResult();
accessResult.setSuccess(getDatSet().getMmsDataObj());
accessResults.add(accessResult);
}
if (getOptFlds().isConfigRevision()) {
accessResult = new AccessResult();
accessResult.setSuccess(getConfRev().getMmsDataObj());
accessResults.add(accessResult);
}
// segmentation not supported
List<FcModelNode> dataSetMembers = dataSet.getMembers();
int dataSetSize = dataSetMembers.size();
// inclusion bitstring
byte[] inclusionStringArray = new byte[(dataSetSize - 1) / 8 + 1];
if (integrity || gi) {
for (int i = 0; i < dataSetSize; i++) {
inclusionStringArray[i / 8] = (byte) (inclusionStringArray[i / 8] | 1 << (7 - i % 8));
}
BerBitString inclusionString = new BerBitString(inclusionStringArray, dataSetSize);
Data data = new Data();
data.setBitString(inclusionString);
accessResult = new AccessResult();
accessResult.setSuccess(data);
accessResults.add(accessResult);
// data reference sending not supported for now
for (FcModelNode dataSetMember : dataSetMembers) {
accessResult = new AccessResult();
accessResult.setSuccess(dataSetMember.getMmsDataObj());
accessResults.add(accessResult);
}
BdaReasonForInclusion reasonForInclusion = new BdaReasonForInclusion(null);
if (integrity) {
reasonForInclusion.setIntegrity(true);
} else {
reasonForInclusion.setGeneralInterrogation(true);
}
if (getOptFlds().isReasonForInclusion()) {
for (int i = 0; i < dataSetMembers.size(); i++) {
accessResult = new AccessResult();
accessResult.setSuccess(reasonForInclusion.getMmsDataObj());
accessResults.add(accessResult);
}
}
} else {
int index = 0;
for (FcModelNode dataSetMember : dataSet) {
if (membersToBeReported.get(dataSetMember) != null) {
inclusionStringArray[index / 8] =
(byte) (inclusionStringArray[index / 8] | 1 << (7 - index % 8));
}
index++;
}
BerBitString inclusionString = new BerBitString(inclusionStringArray, dataSetSize);
Data data = new Data();
data.setBitString(inclusionString);
accessResult = new AccessResult();
accessResult.setSuccess(data);
accessResults.add(accessResult);
// data reference sending not supported for now
for (FcModelNode dataSetMember : dataSetMembers) {
if (membersToBeReported.get(dataSetMember) != null) {
accessResult = new AccessResult();
accessResult.setSuccess(dataSetMember.getMmsDataObj());
accessResults.add(accessResult);
}
}
if (getOptFlds().isReasonForInclusion()) {
for (FcModelNode dataSetMember : dataSetMembers) {
BdaReasonForInclusion reasonForInclusion = membersToBeReported.get(dataSetMember);
if (reasonForInclusion != null) {
accessResult = new AccessResult();
accessResult.setSuccess(reasonForInclusion.getMmsDataObj());
accessResults.add(accessResult);
}
}
}
membersToBeReported.clear();
bufTmFuture = null;
}
ObjectName objectName = new ObjectName();
objectName.setVmdSpecific(new Identifier("RPT".getBytes(UTF_8)));
VariableAccessSpecification varAccSpec = new VariableAccessSpecification();
varAccSpec.setVariableListName(objectName);
InformationReport infoReport = new InformationReport();
infoReport.setVariableAccessSpecification(varAccSpec);
infoReport.setListOfAccessResult(listOfAccessResult);
UnconfirmedService unconfirmedService = new UnconfirmedService();
unconfirmedService.setInformationReport(infoReport);
UnconfirmedPDU unconfirmedPDU = new UnconfirmedPDU();
unconfirmedPDU.setService(unconfirmedService);
MMSpdu mmsPdu = new MMSpdu();
mmsPdu.setUnconfirmedPDU(unconfirmedPDU);
return mmsPdu;
}
@Override
public FcDataObject copy() {
List<FcModelNode> childCopies = new ArrayList<>(children.size());
for (ModelNode childNode : children.values()) {
childCopies.add((FcModelNode) childNode.copy());
}
Urcb urcb = new Urcb(objectReference, childCopies);
urcb.dataSet = dataSet;
return urcb;
}
void report(BasicDataAttribute bda, boolean dchg, boolean qchg, boolean dupd) {
synchronized (this) {
if (!enabled) {
return;
}
FcModelNode memberFound = null;
FcModelNode fcModelNode = bda;
while (memberFound == null) {
for (FcModelNode member : dataSet) {
if (member == fcModelNode) {
memberFound = fcModelNode;
break;
}
}
if (memberFound != null) {
break;
}
if (!(fcModelNode.parent instanceof FcModelNode)) {
// Unable to report Basic Data Attribute because it is not part of the referenced data set
return;
}
fcModelNode = (FcModelNode) fcModelNode.parent;
}
BdaReasonForInclusion reasonForInclusion = membersToBeReported.get(fcModelNode);
if (reasonForInclusion == null) {
reasonForInclusion = new BdaReasonForInclusion(null);
membersToBeReported.put(fcModelNode, reasonForInclusion);
}
if (dchg) {
reasonForInclusion.setDataChange(true);
}
if (dupd) {
reasonForInclusion.setDataUpdate(true);
} else if (qchg) {
reasonForInclusion.setQualityChange(true);
}
// if bufTmFuture is not null then it is already scheduled and will send the combined report
if (bufTmFuture == null) {
bufTmFuture =
reserved.executor.schedule(
new Runnable() {
@Override
public void run() {
synchronized (Urcb.this) {
if (!enabled) {
return;
}
reserved.sendAnMmsPdu(getMmsReport(false, false));
}
}
},
getBufTm().getValue(),
TimeUnit.MILLISECONDS);
}
}
}
}

@ -0,0 +1,436 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.app;
import com.beanit.iec61850bean.BdaTriggerConditions;
import com.beanit.iec61850bean.Brcb;
import com.beanit.iec61850bean.ClientAssociation;
import com.beanit.iec61850bean.ClientEventListener;
import com.beanit.iec61850bean.ClientSap;
import com.beanit.iec61850bean.DataSet;
import com.beanit.iec61850bean.Fc;
import com.beanit.iec61850bean.FcModelNode;
import com.beanit.iec61850bean.ModelNode;
import com.beanit.iec61850bean.Report;
import com.beanit.iec61850bean.SclParseException;
import com.beanit.iec61850bean.SclParser;
import com.beanit.iec61850bean.ServerModel;
import com.beanit.iec61850bean.ServiceError;
import com.beanit.iec61850bean.Urcb;
import com.beanit.iec61850bean.internal.cli.Action;
import com.beanit.iec61850bean.internal.cli.ActionException;
import com.beanit.iec61850bean.internal.cli.ActionListener;
import com.beanit.iec61850bean.internal.cli.ActionProcessor;
import com.beanit.iec61850bean.internal.cli.CliParameter;
import com.beanit.iec61850bean.internal.cli.CliParameterBuilder;
import com.beanit.iec61850bean.internal.cli.CliParseException;
import com.beanit.iec61850bean.internal.cli.CliParser;
import com.beanit.iec61850bean.internal.cli.IntCliParameter;
import com.beanit.iec61850bean.internal.cli.StringCliParameter;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
public class ConsoleClient {
private static final String PRINT_MODEL_KEY = "m";
private static final String PRINT_MODEL_KEY_DESCRIPTION = "print model";
private static final String GET_DATA_VALUES_KEY = "g";
private static final String GET_DATA_VALUES_KEY_DESCRIPTION = "send GetDataValues request";
private static final String READ_ALL_DATA_KEY = "ga";
private static final String READ_ALL_DATA_KEY_DESCRIPTION = "update all data in the model";
private static final String CREATE_DATA_SET_KEY = "cds";
private static final String CREATE_DATA_SET_KEY_DESCRIPTION = "create data set";
private static final String DELETE_DATA_SET_KEY = "dds";
private static final String DELETE_DATA_SET_KEY_DESCRIPTION = "delete data set";
private static final String REPORTING_KEY = "r";
private static final String REPORTING_KEY_DESCRIPTION = "configure reporting";
private static final StringCliParameter hostParam =
new CliParameterBuilder("-h")
.setDescription("The IP/domain address of the server you want to access.")
.setMandatory()
.buildStringParameter("host");
private static final IntCliParameter portParam =
new CliParameterBuilder("-p")
.setDescription("The port to connect to.")
.buildIntParameter("port", 102);
private static final StringCliParameter modelFileParam =
new CliParameterBuilder("-m")
.setDescription(
"The file name of the SCL file to read the model from. If this parameter is omitted the model will be read from the server device after connection.")
.buildStringParameter("model-file");
private static final ActionProcessor actionProcessor = new ActionProcessor(new ActionExecutor());
private static volatile ClientAssociation association;
private static ServerModel serverModel;
public static void main(String[] args) {
List<CliParameter> cliParameters = new ArrayList<>();
cliParameters.add(hostParam);
cliParameters.add(portParam);
cliParameters.add(modelFileParam);
CliParser cliParser =
new CliParser(
"iec61850bean-console-client", "A client application to access IEC 61850 MMS servers.");
cliParser.addParameters(cliParameters);
try {
cliParser.parseArguments(args);
} catch (CliParseException e1) {
System.err.println("Error parsing command line parameters: " + e1.getMessage());
System.out.println(cliParser.getUsageString());
System.exit(1);
}
InetAddress address;
try {
address = InetAddress.getByName(hostParam.getValue());
} catch (UnknownHostException e) {
System.out.println("Unknown host: " + hostParam.getValue());
return;
}
ClientSap clientSap = new ClientSap();
try {
association = clientSap.associate(address, portParam.getValue(), null, new EventListener());
} catch (IOException e) {
System.out.println("Unable to connect to remote host.");
return;
}
Runtime.getRuntime()
.addShutdownHook(
new Thread() {
@Override
public void run() {
association.close();
}
});
System.out.println("successfully connected");
if (modelFileParam.isSelected()) {
System.out.println("reading model from file...");
try {
serverModel = SclParser.parse(modelFileParam.getValue()).get(0);
} catch (SclParseException e1) {
System.out.println("Error parsing SCL file: " + e1.getMessage());
return;
}
association.setServerModel(serverModel);
System.out.println("successfully read model");
} else {
System.out.println("retrieving model...");
try {
serverModel = association.retrieveModel();
} catch (ServiceError e) {
System.out.println("Service error: " + e.getMessage());
return;
} catch (IOException e) {
System.out.println("Fatal error: " + e.getMessage());
return;
}
System.out.println("successfully read model");
}
actionProcessor.addAction(new Action(PRINT_MODEL_KEY, PRINT_MODEL_KEY_DESCRIPTION));
actionProcessor.addAction(new Action(GET_DATA_VALUES_KEY, GET_DATA_VALUES_KEY_DESCRIPTION));
actionProcessor.addAction(new Action(READ_ALL_DATA_KEY, READ_ALL_DATA_KEY_DESCRIPTION));
actionProcessor.addAction(new Action(CREATE_DATA_SET_KEY, CREATE_DATA_SET_KEY_DESCRIPTION));
actionProcessor.addAction(new Action(DELETE_DATA_SET_KEY, DELETE_DATA_SET_KEY_DESCRIPTION));
actionProcessor.addAction(new Action(REPORTING_KEY, REPORTING_KEY_DESCRIPTION));
actionProcessor.start();
}
private static class EventListener implements ClientEventListener {
@Override
public void newReport(Report report) {
System.out.println("\n----------------");
System.out.println("Received report: ");
System.err.println(report);
System.out.println("------------------");
}
@Override
public void associationClosed(IOException e) {
System.out.print("Received connection closed signal. Reason: ");
if (!e.getMessage().isEmpty()) {
System.out.println(e.getMessage());
} else {
System.out.println("unknown");
}
actionProcessor.close();
}
}
private static class ActionExecutor implements ActionListener {
@Override
public void actionCalled(String actionKey) throws ActionException {
try {
switch (actionKey) {
case PRINT_MODEL_KEY:
System.out.println(serverModel);
break;
case READ_ALL_DATA_KEY:
System.out.print("Reading all data...");
try {
association.getAllDataValues();
} catch (ServiceError e) {
System.err.println("Service error: " + e.getMessage());
}
System.out.println("done");
break;
case GET_DATA_VALUES_KEY:
{
if (serverModel == null) {
System.out.println("You have to retrieve the model before reading data.");
return;
}
FcModelNode fcModelNode = askForFcModelNode();
System.out.println("Sending GetDataValues request...");
try {
association.getDataValues(fcModelNode);
} catch (ServiceError e) {
System.out.println("Service error: " + e.getMessage());
return;
} catch (IOException e) {
System.out.println("Fatal error: " + e.getMessage());
return;
}
System.out.println("Successfully read data.");
System.out.println(fcModelNode);
break;
}
case CREATE_DATA_SET_KEY:
{
System.out.println(
"Enter the reference of the data set to create (e.g. myld/MYLN0.dataset1): ");
String reference = actionProcessor.getReader().readLine();
System.out.println("How many entries shall the data set have: ");
String numberOfEntriesString = actionProcessor.getReader().readLine();
int numDataSetEntries = Integer.parseInt(numberOfEntriesString);
List<FcModelNode> dataSetMembers = new ArrayList<>();
for (int i = 0; i < numDataSetEntries; i++) {
dataSetMembers.add(askForFcModelNode());
}
DataSet dataSet = new DataSet(reference, dataSetMembers);
System.out.print("Creating data set..");
association.createDataSet(dataSet);
System.out.println("done");
break;
}
case DELETE_DATA_SET_KEY:
{
System.out.println(
"Enter the reference of the data set to delete (e.g. myld/MYLN0.dataset1): ");
String reference = actionProcessor.getReader().readLine();
DataSet dataSet = serverModel.getDataSet(reference);
if (dataSet == null) {
throw new ActionException("Unable to find data set with the given reference.");
}
System.out.print("Deleting data set..");
association.deleteDataSet(dataSet);
System.out.println("done");
break;
}
case REPORTING_KEY:
{
System.out.println("Enter the URCB reference: ");
String reference = actionProcessor.getReader().readLine();
Urcb urcb = serverModel.getUrcb(reference);
if (urcb == null) {
Brcb brcb = serverModel.getBrcb(reference);
if (brcb != null) {
throw new ActionException(
"Though buffered reporting is supported by the library it is not yet supported by the console application.");
}
throw new ActionException("Unable to find RCB with the given reference.");
}
while (true) {
association.getRcbValues(urcb);
System.out.println();
System.out.println(urcb);
System.out.println();
System.out.println("What do you want to configure?");
System.out.println("1 - reserve");
System.out.println("2 - cancel reservation");
System.out.println("3 - enable");
System.out.println("4 - disable");
System.out.println("5 - set data set");
System.out.println("6 - set trigger options");
System.out.println("7 - set integrity period");
System.out.println("8 - send general interrogation");
System.out.println("0 - quit");
try {
int rcbAction = Integer.parseInt(actionProcessor.getReader().readLine());
switch (rcbAction) {
case 0:
return;
case 1:
System.out.print("Reserving RCB..");
association.reserveUrcb(urcb);
System.out.println("done");
break;
case 2:
System.out.print("Canceling RCB reservation..");
association.cancelUrcbReservation(urcb);
System.out.println("done");
break;
case 3:
System.out.print("Enabling reporting..");
association.enableReporting(urcb);
System.out.println("done");
break;
case 4:
System.out.print("Disabling reporting..");
association.disableReporting(urcb);
System.out.println("done");
break;
case 5:
{
System.out.print("Set data set reference:");
String dataSetReference = actionProcessor.getReader().readLine();
urcb.getDatSet().setValue(dataSetReference);
List<ServiceError> serviceErrors =
association.setRcbValues(
urcb, false, true, false, false, false, false, false, false);
if (serviceErrors.get(0) != null) {
throw serviceErrors.get(0);
}
System.out.println("done");
break;
}
case 6:
{
System.out.print(
"Set the trigger options (data change, data update, quality change, interity, GI):");
String triggerOptionsString = actionProcessor.getReader().readLine();
String[] triggerOptionsStrings = triggerOptionsString.split(",", -1);
BdaTriggerConditions triggerOptions = urcb.getTrgOps();
triggerOptions.setDataChange(
Boolean.parseBoolean(triggerOptionsStrings[0]));
triggerOptions.setDataUpdate(
Boolean.parseBoolean(triggerOptionsStrings[1]));
triggerOptions.setQualityChange(
Boolean.parseBoolean(triggerOptionsStrings[2]));
triggerOptions.setIntegrity(Boolean.parseBoolean(triggerOptionsStrings[3]));
triggerOptions.setGeneralInterrogation(
Boolean.parseBoolean(triggerOptionsStrings[4]));
List<ServiceError> serviceErrors =
association.setRcbValues(
urcb, false, false, false, false, true, false, false, false);
if (serviceErrors.get(0) != null) {
throw serviceErrors.get(0);
}
System.out.println("done");
break;
}
case 7:
{
System.out.print("Specify integrity period in ms:");
String integrityPeriodString = actionProcessor.getReader().readLine();
urcb.getIntgPd().setValue(Long.parseLong(integrityPeriodString));
List<ServiceError> serviceErrors =
association.setRcbValues(
urcb, false, false, false, false, false, true, false, false);
if (serviceErrors.get(0) != null) {
throw serviceErrors.get(0);
}
System.out.println("done");
break;
}
case 8:
System.out.print("Sending GI..");
association.startGi(urcb);
System.out.println("done");
break;
default:
System.err.println("Unknown option.");
break;
}
} catch (ServiceError e) {
System.err.println("Service error: " + e.getMessage());
} catch (NumberFormatException e) {
System.err.println("Cannot parse number: " + e.getMessage());
}
}
}
default:
break;
}
} catch (Exception e) {
throw new ActionException(e);
}
}
private FcModelNode askForFcModelNode() throws IOException, ActionException {
System.out.println("Enter reference (e.g. myld/MYLN0.do.da.bda): ");
String reference = actionProcessor.getReader().readLine();
System.out.println("Enter functional constraint of referenced node: ");
String fcString = actionProcessor.getReader().readLine();
Fc fc = Fc.fromString(fcString);
if (fc == null) {
throw new ActionException("Unknown functional constraint.");
}
ModelNode modelNode = serverModel.findModelNode(reference, Fc.fromString(fcString));
if (modelNode == null) {
throw new ActionException(
"A model node with the given reference and functional constraint could not be found.");
}
if (!(modelNode instanceof FcModelNode)) {
throw new ActionException(
"The given model node is not a functionally constraint model node.");
}
FcModelNode fcModelNode = (FcModelNode) modelNode;
return fcModelNode;
}
@Override
public void quit() {
System.out.println("** Closing connection.");
association.close();
return;
}
}
}

@ -0,0 +1,250 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.app;
import com.beanit.iec61850bean.BasicDataAttribute;
import com.beanit.iec61850bean.BdaBoolean;
import com.beanit.iec61850bean.BdaFloat32;
import com.beanit.iec61850bean.BdaFloat64;
import com.beanit.iec61850bean.BdaInt16;
import com.beanit.iec61850bean.BdaInt16U;
import com.beanit.iec61850bean.BdaInt32;
import com.beanit.iec61850bean.BdaInt32U;
import com.beanit.iec61850bean.BdaInt64;
import com.beanit.iec61850bean.BdaInt8;
import com.beanit.iec61850bean.BdaInt8U;
import com.beanit.iec61850bean.Fc;
import com.beanit.iec61850bean.ModelNode;
import com.beanit.iec61850bean.SclParseException;
import com.beanit.iec61850bean.SclParser;
import com.beanit.iec61850bean.ServerEventListener;
import com.beanit.iec61850bean.ServerModel;
import com.beanit.iec61850bean.ServerSap;
import com.beanit.iec61850bean.ServiceError;
import com.beanit.iec61850bean.internal.cli.Action;
import com.beanit.iec61850bean.internal.cli.ActionException;
import com.beanit.iec61850bean.internal.cli.ActionListener;
import com.beanit.iec61850bean.internal.cli.ActionProcessor;
import com.beanit.iec61850bean.internal.cli.CliParameter;
import com.beanit.iec61850bean.internal.cli.CliParameterBuilder;
import com.beanit.iec61850bean.internal.cli.CliParseException;
import com.beanit.iec61850bean.internal.cli.CliParser;
import com.beanit.iec61850bean.internal.cli.IntCliParameter;
import com.beanit.iec61850bean.internal.cli.StringCliParameter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class ConsoleServer {
private static final String WRITE_VALUE_KEY = "w";
private static final String WRITE_VALUE_KEY_DESCRIPTION = "write value to model node";
private static final String PRINT_SERVER_MODEL_KEY = "p";
private static final String PRINT_SERVER_MODEL_KEY_DESCRIPTION = "print server's model";
private static final IntCliParameter portParam =
new CliParameterBuilder("-p")
.setDescription(
"The port to listen on. On unix based systems you need root privilages for ports < 1000.")
.buildIntParameter("port", 102);
private static final StringCliParameter modelFileParam =
new CliParameterBuilder("-m")
.setDescription("The SCL file that contains the server's information model.")
.setMandatory()
.buildStringParameter("model-file");
private static final ActionProcessor actionProcessor = new ActionProcessor(new ActionExecutor());
private static ServerModel serverModel;
private static ServerSap serverSap = null;
public static void main(String[] args) throws IOException {
List<CliParameter> cliParameters = new ArrayList<>();
cliParameters.add(modelFileParam);
cliParameters.add(portParam);
CliParser cliParser =
new CliParser("iec61850bean-console-server", "An IEC 61850 MMS console server.");
cliParser.addParameters(cliParameters);
try {
cliParser.parseArguments(args);
} catch (CliParseException e1) {
System.err.println("Error parsing command line parameters: " + e1.getMessage());
System.out.println(cliParser.getUsageString());
System.exit(1);
}
List<ServerModel> serverModels = null;
try {
serverModels = SclParser.parse(modelFileParam.getValue());
} catch (SclParseException e) {
System.out.println("Error parsing SCL/ICD file: " + e.getMessage());
return;
}
serverSap = new ServerSap(102, 0, null, serverModels.get(0), null);
serverSap.setPort(portParam.getValue());
Runtime.getRuntime()
.addShutdownHook(
new Thread() {
@Override
public void run() {
if (serverSap != null) {
serverSap.stop();
}
System.out.println("Server was stopped.");
}
});
serverModel = serverSap.getModelCopy();
serverSap.startListening(new EventListener());
actionProcessor.addAction(
new Action(PRINT_SERVER_MODEL_KEY, PRINT_SERVER_MODEL_KEY_DESCRIPTION));
actionProcessor.addAction(new Action(WRITE_VALUE_KEY, WRITE_VALUE_KEY_DESCRIPTION));
actionProcessor.start();
}
private static class EventListener implements ServerEventListener {
@Override
public void serverStoppedListening(ServerSap serverSap) {
System.out.println("The SAP stopped listening");
}
@Override
public List<ServiceError> write(List<BasicDataAttribute> bdas) {
for (BasicDataAttribute bda : bdas) {
System.out.println("got a write request: " + bda);
}
return null;
}
}
private static class ActionExecutor implements ActionListener {
@Override
public void actionCalled(String actionKey) throws ActionException {
try {
switch (actionKey) {
case PRINT_SERVER_MODEL_KEY:
System.out.println("** Printing model.");
System.out.println(serverModel);
break;
case WRITE_VALUE_KEY:
System.out.println("Enter reference to write (e.g. myld/MYLN0.do.da.bda): ");
String reference = actionProcessor.getReader().readLine();
System.out.println("Enter functional constraint of referenced node: ");
String fcString = actionProcessor.getReader().readLine();
Fc fc = Fc.fromString(fcString);
if (fc == null) {
System.out.println("Unknown functional constraint.");
return;
}
ModelNode modelNode = serverModel.findModelNode(reference, Fc.fromString(fcString));
if (modelNode == null) {
System.out.println(
"A model node with the given reference and functional constraint could not be found.");
return;
}
if (!(modelNode instanceof BasicDataAttribute)) {
System.out.println("The given model node is not a basic data attribute.");
return;
}
BasicDataAttribute bda =
(BasicDataAttribute) serverModel.findModelNode(reference, Fc.fromString(fcString));
System.out.println("Enter value to write: ");
String valueString = actionProcessor.getReader().readLine();
try {
setBdaValue(bda, valueString);
} catch (Exception e) {
System.out.println(
"The console server does not support writing this type of basic data attribute.");
return;
}
List<BasicDataAttribute> bdas = new ArrayList<>();
bdas.add(bda);
serverSap.setValues(bdas);
System.out.println("Successfully wrote data.");
System.out.println(bda);
break;
default:
break;
}
} catch (Exception e) {
throw new ActionException(e);
}
}
private void setBdaValue(BasicDataAttribute bda, String valueString) {
if (bda instanceof BdaFloat32) {
float value = Float.parseFloat(valueString);
((BdaFloat32) bda).setFloat(value);
} else if (bda instanceof BdaFloat64) {
double value = Float.parseFloat(valueString);
((BdaFloat64) bda).setDouble(value);
} else if (bda instanceof BdaInt8) {
byte value = Byte.parseByte(valueString);
((BdaInt8) bda).setValue(value);
} else if (bda instanceof BdaInt8U) {
short value = Short.parseShort(valueString);
((BdaInt8U) bda).setValue(value);
} else if (bda instanceof BdaInt16) {
short value = Short.parseShort(valueString);
((BdaInt16) bda).setValue(value);
} else if (bda instanceof BdaInt16U) {
int value = Integer.parseInt(valueString);
((BdaInt16U) bda).setValue(value);
} else if (bda instanceof BdaInt32) {
int value = Integer.parseInt(valueString);
((BdaInt32) bda).setValue(value);
} else if (bda instanceof BdaInt32U) {
long value = Long.parseLong(valueString);
((BdaInt32U) bda).setValue(value);
} else if (bda instanceof BdaInt64) {
long value = Long.parseLong(valueString);
((BdaInt64) bda).setValue(value);
} else if (bda instanceof BdaBoolean) {
boolean value = Boolean.parseBoolean(valueString);
((BdaBoolean) bda).setValue(value);
} else {
throw new IllegalArgumentException();
}
}
@Override
public void quit() {
System.out.println("** Stopping server.");
serverSap.stop();
return;
}
}
}

@ -0,0 +1,66 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui;
import com.beanit.iec61850bean.BasicDataAttribute;
import com.beanit.iec61850bean.BdaType;
import javax.swing.JComponent;
import javax.swing.JLabel;
public abstract class BasicDataBind<E extends BasicDataAttribute> {
protected final E data;
private JComponent valueField;
protected BasicDataBind(E data, BdaType type) {
if (data.getBasicType() != type) {
throw new IllegalArgumentException(data.getName() + " is no " + type);
}
this.data = data;
}
public JLabel getNameLabel() {
return new JLabel(data.getName());
}
public JComponent getValueField() {
if (valueField == null) {
valueField = init();
}
return valueField;
}
public void reset() {
if (valueField == null) {
valueField = init();
}
resetImpl();
}
public void write() {
if (valueField == null) {
valueField = init();
}
writeImpl();
}
protected abstract JComponent init();
protected abstract void resetImpl();
protected abstract void writeImpl();
}

@ -0,0 +1,441 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui;
import com.beanit.iec61850bean.ClientAssociation;
import com.beanit.iec61850bean.ClientSap;
import com.beanit.iec61850bean.ServerModel;
import com.beanit.iec61850bean.ServiceError;
import com.beanit.iec61850bean.clientgui.util.Counter;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Properties;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.ToolTipManager;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
public class ClientGui extends JFrame implements ActionListener, TreeSelectionListener {
private static final String ADDRESS_KEY = "serverAddress";
private static final String PORT_KEY = "serverPort";
private static final String TSEL_LOCAL_KEY = "tselLocal";
private static final String TSEL_REMOTE_KEY = "tselRemote";
private static final String LASTCONNECTION_FILE = "lastconnection.properties";
private static final long serialVersionUID = -1938913902977758367L;
private final JTextField ipTextField = new JTextField("127.0.0.1");
private final JTextField portTextField = new JTextField("10002");
private final JTree tree = new JTree(new DefaultMutableTreeNode("No server connected"));
private final JPanel detailsPanel = new JPanel();
private final GridBagLayout detailsLayout = new GridBagLayout();
private final SettingsFrame settingsFrame = new SettingsFrame();
private ClientAssociation association;
private DataTreeNode selectedNode;
public ClientGui() {
super("IEC61850bean Client GUI");
Properties lastConnection = new Properties();
InputStream in = null;
try {
in = new FileInputStream(LASTCONNECTION_FILE);
lastConnection.load(in);
ipTextField.setText(lastConnection.getProperty(ADDRESS_KEY));
portTextField.setText(lastConnection.getProperty(PORT_KEY));
String[] tselString = lastConnection.getProperty(TSEL_LOCAL_KEY).split(",");
byte[] tsel =
new byte[] {
(byte) Integer.parseInt(tselString[0]), (byte) Integer.parseInt(tselString[1])
};
settingsFrame.setTselLocal(tsel);
tselString = lastConnection.getProperty(TSEL_REMOTE_KEY).split(",");
tsel =
new byte[] {
(byte) Integer.parseInt(tselString[0]), (byte) Integer.parseInt(tselString[1])
};
settingsFrame.setTselRemote(tsel);
} catch (Exception ex) {
// no lastconnection.properties file found, use default.
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException ignored) {
// there is nothing that can be done if closing fails
}
}
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException e) {
System.out.println("Class not found: " + e.getMessage());
} catch (InstantiationException e) {
System.out.println("Object not instantiated: " + e.getMessage());
} catch (IllegalAccessException e) {
System.out.println("Illegal acces: " + e.getMessage());
} catch (UnsupportedLookAndFeelException e) {
System.out.println("Unsupported LookAndFeel: " + e.getMessage());
}
GridBagLayout gbl = new GridBagLayout();
setLayout(gbl);
JPanel topPanel = new JPanel();
topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.X_AXIS));
GridBagConstraints topPanelConstraint = new GridBagConstraints();
topPanelConstraint.fill = GridBagConstraints.HORIZONTAL;
topPanelConstraint.gridwidth = GridBagConstraints.REMAINDER;
topPanelConstraint.gridx = 0;
topPanelConstraint.gridy = 0;
topPanelConstraint.insets = new Insets(5, 5, 5, 5);
topPanelConstraint.anchor = GridBagConstraints.NORTH;
gbl.setConstraints(topPanel, topPanelConstraint);
add(topPanel);
JLabel label = new JLabel("IP: ");
topPanel.add(label);
topPanel.add(ipTextField);
topPanel.add(Box.createRigidArea(new Dimension(5, 0)));
label = new JLabel("Port: ");
topPanel.add(label);
topPanel.add(portTextField);
topPanel.add(Box.createRigidArea(new Dimension(5, 0)));
JButton newServerButton = new JButton("Connect to Server");
newServerButton.addActionListener(this);
newServerButton.setActionCommand("Connect");
topPanel.add(newServerButton);
topPanel.add(Box.createRigidArea(new Dimension(5, 0)));
JButton settingsButton = new JButton("Settings");
settingsButton.addActionListener(this);
settingsButton.setActionCommand("Settings");
topPanel.add(settingsButton);
ToolTipManager.sharedInstance().registerComponent(tree);
tree.setCellRenderer(new DataObjectTreeCellRenderer());
tree.setMinimumSize(new Dimension(100, 0));
tree.addTreeSelectionListener(this);
JScrollPane treeScrollPane = new JScrollPane(tree);
treeScrollPane.setMinimumSize(new Dimension(100, 0));
treeScrollPane.setVisible(true);
GridBagConstraints treeScrollPaneConstraint = new GridBagConstraints();
treeScrollPaneConstraint.fill = GridBagConstraints.BOTH;
treeScrollPaneConstraint.gridx = 0;
treeScrollPaneConstraint.gridy = 1;
treeScrollPaneConstraint.weightx = 0.2;
treeScrollPaneConstraint.weighty = 1;
treeScrollPaneConstraint.insets = new Insets(5, 5, 5, 5);
gbl.setConstraints(treeScrollPane, treeScrollPaneConstraint);
add(treeScrollPane);
detailsPanel.setLayout(detailsLayout);
detailsPanel.setAlignmentY(TOP_ALIGNMENT);
JScrollPane detailsScrollPane = new JScrollPane(detailsPanel);
detailsPanel.setMaximumSize(detailsScrollPane.getSize());
detailsScrollPane.setMinimumSize(new Dimension(0, 0));
detailsScrollPane.setPreferredSize(new Dimension(200, 0));
detailsScrollPane.setVisible(true);
GridBagConstraints detailsScrollPaneConstraint = new GridBagConstraints();
detailsScrollPaneConstraint.fill = GridBagConstraints.BOTH;
detailsScrollPaneConstraint.gridx = 1;
detailsScrollPaneConstraint.gridy = 1;
detailsScrollPaneConstraint.weightx = 0.8;
detailsScrollPaneConstraint.weighty = 1;
detailsScrollPaneConstraint.insets = new Insets(5, 5, 5, 5);
gbl.setConstraints(detailsScrollPane, detailsScrollPaneConstraint);
add(detailsScrollPane);
// Display the window.
setSize(700, 500);
setMinimumSize(new Dimension(420, 0));
setVisible(true);
}
public static void main(String[] args) {
ClientGui clientGui = new ClientGui();
clientGui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
clientGui.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent arg0) {
if ("connect".equalsIgnoreCase(arg0.getActionCommand())) {
connect();
} else if ("reload".equalsIgnoreCase(arg0.getActionCommand())) {
reload();
} else if ("write".equalsIgnoreCase(arg0.getActionCommand())) {
write();
} else if ("settings".equalsIgnoreCase(arg0.getActionCommand())) {
settingsFrame.setVisible(true);
}
}
@Override
public void valueChanged(TreeSelectionEvent e) {
detailsPanel.removeAll();
detailsPanel.repaint();
if (e.getNewLeadSelectionPath() != null) {
selectedNode = (DataTreeNode) e.getNewLeadSelectionPath().getLastPathComponent();
if (selectedNode.readable()) {
showDataDetails(selectedNode, new Counter());
JPanel filler = new JPanel();
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
gbc.gridx = 0;
gbc.gridy = GridBagConstraints.RELATIVE;
gbc.gridwidth = 3;
gbc.gridheight = 1;
gbc.weightx = 0;
gbc.weighty = 1;
detailsLayout.setConstraints(filler, gbc);
detailsPanel.add(filler);
JButton button = new JButton("Reload values");
button.addActionListener(this);
button.setActionCommand("reload");
gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.NONE;
gbc.gridx = 0;
gbc.gridy = GridBagConstraints.RELATIVE;
gbc.gridwidth = 2;
gbc.gridheight = 1;
gbc.weightx = 0;
gbc.weighty = 0;
gbc.anchor = GridBagConstraints.SOUTHWEST;
gbc.insets = new Insets(0, 5, 5, 0);
detailsLayout.setConstraints(button, gbc);
detailsPanel.add(button);
if (selectedNode.writable()) {
button = new JButton("Write values");
button.addActionListener(this);
button.setActionCommand("write");
gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.NONE;
gbc.gridx = 2;
gbc.gridy = GridBagConstraints.RELATIVE;
gbc.gridwidth = 1;
gbc.gridheight = 1;
gbc.weightx = 0;
gbc.weighty = 0;
gbc.anchor = GridBagConstraints.SOUTHEAST;
gbc.insets = new Insets(0, 0, 5, 5);
detailsLayout.setConstraints(button, gbc);
detailsPanel.add(button);
}
}
} else {
selectedNode = null;
}
validate();
}
private void connect() {
ClientSap clientSap = new ClientSap();
InetAddress address = null;
try {
address = InetAddress.getByName(ipTextField.getText());
} catch (UnknownHostException e1) {
e1.printStackTrace();
return;
}
int remotePort = 10002;
try {
remotePort = Integer.parseInt(portTextField.getText());
if (remotePort < 1 || remotePort > 0xFFFF) {
throw new NumberFormatException("port must be in range [1, 65535]");
}
} catch (NumberFormatException e) {
e.printStackTrace();
return;
}
clientSap.setTSelLocal(settingsFrame.getTselLocal());
clientSap.setTSelRemote(settingsFrame.getTselRemote());
try {
association = clientSap.associate(address, remotePort, null, null);
} catch (IOException e) {
System.out.println("Error connecting to server: " + e.getMessage());
return;
}
ServerModel serverModel;
try {
serverModel = association.retrieveModel();
association.getAllDataValues();
} catch (ServiceError e) {
System.out.println("Service Error requesting model." + e.getMessage());
association.close();
return;
} catch (IOException e) {
System.out.println("Fatal IOException requesting model." + e.getMessage());
return;
}
ServerModelParser parser = new ServerModelParser(serverModel);
tree.setModel(new DefaultTreeModel(parser.getModelTree()));
Properties lastConnectSettings = new Properties();
FileOutputStream out = null;
try {
lastConnectSettings.setProperty(ADDRESS_KEY, ipTextField.getText());
lastConnectSettings.setProperty(PORT_KEY, portTextField.getText());
byte[] tsel = settingsFrame.getTselLocal();
lastConnectSettings.setProperty(TSEL_LOCAL_KEY, tsel[0] + "," + tsel[1]);
tsel = settingsFrame.getTselRemote();
lastConnectSettings.setProperty(TSEL_REMOTE_KEY, tsel[0] + "," + tsel[1]);
out = new FileOutputStream(LASTCONNECTION_FILE);
lastConnectSettings.store(out, null);
} catch (IOException ex) {
System.out.println("Writing properties file failed. Reason: " + ex.getMessage());
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
// nothing meaningful can be done if closing fails
}
}
validate();
}
private void reload() {
if (selectedNode.readable()) {
try {
selectedNode.reset(association);
} catch (ServiceError e) {
System.out.println("ServiceError on reading" + e.getMessage());
return;
} catch (IOException e) {
System.out.println("IOException on reading" + e.getMessage());
return;
}
validate();
}
}
private void write() {
if (selectedNode.writable()) {
try {
selectedNode.writeValues(association);
} catch (ServiceError e) {
System.out.println("ServiceError on writing" + e.getMessage());
return;
} catch (IOException e) {
System.out.println("IOException on writing" + e.getMessage());
return;
}
validate();
}
}
private void showDataDetails(DataTreeNode node, Counter y) {
if (node.getData() != null) {
BasicDataBind<?> data = node.getData();
JLabel nameLabel = data.getNameLabel();
nameLabel.setText(nameLabel.getText() + ": ");
addDetailsComponent(nameLabel, 0, y.getValue(), 1, 1, 0, 0);
addDetailsComponent(data.getValueField(), 1, y.getValue(), 2, 1, 1, 0);
y.increment();
} else {
for (int i = 0; i < node.getChildCount(); i++) {
y.increment();
DataObjectTreeNode childNode = (DataObjectTreeNode) node.getChildAt(i);
showDataDetails(childNode, childNode.toString(), y);
}
}
}
private void showDataDetails(DataTreeNode node, String pre, Counter y) {
if (node.getData() != null) {
BasicDataBind<?> data = node.getData();
JLabel nameLabel = data.getNameLabel();
nameLabel.setText(pre + ": ");
addDetailsComponent(nameLabel, 0, y.getValue(), 1, 1, 0, 0);
addDetailsComponent(data.getValueField(), 1, y.getValue(), 2, 1, 1, 0);
y.increment();
} else {
for (int i = 0; i < node.getChildCount(); i++) {
y.increment();
DataObjectTreeNode childNode = (DataObjectTreeNode) node.getChildAt(i);
showDataDetails(childNode, pre + "." + childNode.toString(), y);
detailsPanel.add(new JSeparator());
addDetailsComponent(new JSeparator(), 0, y.getValue(), 3, 1, 1, 0);
}
}
}
private void addDetailsComponent(
Component c, int x, int y, int width, int height, double weightx, double weighty) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridx = x;
gbc.gridy = y;
gbc.gridwidth = width;
gbc.gridheight = height;
gbc.weightx = weightx;
gbc.weighty = weighty;
gbc.anchor = GridBagConstraints.NORTH;
gbc.insets = new Insets(3, 3, 3, 3);
detailsLayout.setConstraints(c, gbc);
detailsPanel.add(c);
}
}

@ -0,0 +1,52 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui;
import com.beanit.iec61850bean.BasicDataAttribute;
import com.beanit.iec61850bean.FcModelNode;
import java.awt.Component;
import javax.swing.JTree;
import javax.swing.tree.DefaultTreeCellRenderer;
public class DataObjectTreeCellRenderer extends DefaultTreeCellRenderer {
private static final long serialVersionUID = 1682378972258556129L;
@Override
public Component getTreeCellRendererComponent(
JTree tree,
Object value,
boolean sel,
boolean expanded,
boolean leaf,
int row,
boolean hasFocus) {
super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
if (value instanceof DataObjectTreeNode) {
DataObjectTreeNode treeNode = (DataObjectTreeNode) value;
if (!leaf && treeNode.getNode() instanceof FcModelNode) {
setIcon(getLeafIcon());
}
if (treeNode.getNode() instanceof BasicDataAttribute) {
BasicDataAttribute attribute = (BasicDataAttribute) treeNode.getNode();
String tooltip = attribute.getSAddr();
setToolTipText(tooltip);
}
}
return this;
}
}

@ -0,0 +1,199 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui;
import com.beanit.iec61850bean.BasicDataAttribute;
import com.beanit.iec61850bean.BdaBoolean;
import com.beanit.iec61850bean.BdaCheck;
import com.beanit.iec61850bean.BdaDoubleBitPos;
import com.beanit.iec61850bean.BdaEntryTime;
import com.beanit.iec61850bean.BdaFloat32;
import com.beanit.iec61850bean.BdaFloat64;
import com.beanit.iec61850bean.BdaInt16;
import com.beanit.iec61850bean.BdaInt16U;
import com.beanit.iec61850bean.BdaInt32;
import com.beanit.iec61850bean.BdaInt32U;
import com.beanit.iec61850bean.BdaInt64;
import com.beanit.iec61850bean.BdaInt8;
import com.beanit.iec61850bean.BdaInt8U;
import com.beanit.iec61850bean.BdaOctetString;
import com.beanit.iec61850bean.BdaOptFlds;
import com.beanit.iec61850bean.BdaQuality;
import com.beanit.iec61850bean.BdaReasonForInclusion;
import com.beanit.iec61850bean.BdaTapCommand;
import com.beanit.iec61850bean.BdaTimestamp;
import com.beanit.iec61850bean.BdaTriggerConditions;
import com.beanit.iec61850bean.BdaUnicodeString;
import com.beanit.iec61850bean.BdaVisibleString;
import com.beanit.iec61850bean.ClientAssociation;
import com.beanit.iec61850bean.Fc;
import com.beanit.iec61850bean.FcModelNode;
import com.beanit.iec61850bean.ModelNode;
import com.beanit.iec61850bean.ServiceError;
import com.beanit.iec61850bean.clientgui.databind.BooleanDataBind;
import com.beanit.iec61850bean.clientgui.databind.CheckDataBind;
import com.beanit.iec61850bean.clientgui.databind.DoubleBitPosDataBind;
import com.beanit.iec61850bean.clientgui.databind.EntryTimeDataBind;
import com.beanit.iec61850bean.clientgui.databind.Float32DataBind;
import com.beanit.iec61850bean.clientgui.databind.Float64DataBind;
import com.beanit.iec61850bean.clientgui.databind.Int16DataBind;
import com.beanit.iec61850bean.clientgui.databind.Int16UDataBind;
import com.beanit.iec61850bean.clientgui.databind.Int32DataBind;
import com.beanit.iec61850bean.clientgui.databind.Int32UDataBind;
import com.beanit.iec61850bean.clientgui.databind.Int64DataBind;
import com.beanit.iec61850bean.clientgui.databind.Int8DataBind;
import com.beanit.iec61850bean.clientgui.databind.Int8UDataBind;
import com.beanit.iec61850bean.clientgui.databind.OctetStringDataBind;
import com.beanit.iec61850bean.clientgui.databind.OptfldsDataBind;
import com.beanit.iec61850bean.clientgui.databind.QualityDataBind;
import com.beanit.iec61850bean.clientgui.databind.ReasonForInclusionDataBind;
import com.beanit.iec61850bean.clientgui.databind.TapCommandDataBind;
import com.beanit.iec61850bean.clientgui.databind.TimeStampDataBind;
import com.beanit.iec61850bean.clientgui.databind.TriggerConditionDataBind;
import com.beanit.iec61850bean.clientgui.databind.UnicodeStringDataBind;
import com.beanit.iec61850bean.clientgui.databind.VisibleStringDataBind;
import java.io.IOException;
import javax.swing.tree.DefaultMutableTreeNode;
public class DataObjectTreeNode extends DefaultMutableTreeNode implements DataTreeNode {
private static final long serialVersionUID = -3596243932937737877L;
private final ModelNode node;
private final BasicDataBind<?> data;
public DataObjectTreeNode(String name, ModelNode node) {
super(name);
this.node = node;
if (node != null && node.getChildren() == null) {
// for (ModelNode child : node.getChildren()) {
// if (child instanceof BasicDataAttribute) {
// data.add(createDataBind((BasicDataAttribute) child));
// }
// }
data = createDataBind((BasicDataAttribute) node);
} else {
data = null;
}
}
private static BasicDataBind<?> createDataBind(BasicDataAttribute bda) {
switch (bda.getBasicType()) {
case BOOLEAN:
return new BooleanDataBind((BdaBoolean) bda);
case ENTRY_TIME:
return new EntryTimeDataBind((BdaEntryTime) bda);
case FLOAT32:
return new Float32DataBind((BdaFloat32) bda);
case FLOAT64:
return new Float64DataBind((BdaFloat64) bda);
case INT16:
return new Int16DataBind((BdaInt16) bda);
case INT16U:
return new Int16UDataBind((BdaInt16U) bda);
case INT32:
return new Int32DataBind((BdaInt32) bda);
case INT32U:
return new Int32UDataBind((BdaInt32U) bda);
case INT64:
return new Int64DataBind((BdaInt64) bda);
case INT8:
return new Int8DataBind((BdaInt8) bda);
case INT8U:
return new Int8UDataBind((BdaInt8U) bda);
case OCTET_STRING:
return new OctetStringDataBind((BdaOctetString) bda);
case TIMESTAMP:
return new TimeStampDataBind((BdaTimestamp) bda);
case UNICODE_STRING:
return new UnicodeStringDataBind((BdaUnicodeString) bda);
case VISIBLE_STRING:
return new VisibleStringDataBind((BdaVisibleString) bda);
case CHECK:
return new CheckDataBind((BdaCheck) bda);
case DOUBLE_BIT_POS:
return new DoubleBitPosDataBind((BdaDoubleBitPos) bda);
case OPTFLDS:
return new OptfldsDataBind((BdaOptFlds) bda);
case QUALITY:
return new QualityDataBind((BdaQuality) bda);
case REASON_FOR_INCLUSION:
return new ReasonForInclusionDataBind((BdaReasonForInclusion) bda);
case TAP_COMMAND:
return new TapCommandDataBind((BdaTapCommand) bda);
case TRIGGER_CONDITIONS:
return new TriggerConditionDataBind((BdaTriggerConditions) bda);
default:
throw new IllegalArgumentException("BasicType " + bda.getBasicType() + " unknown");
}
}
public ModelNode getNode() {
return node;
}
@Override
public BasicDataBind<?> getData() {
return data;
}
@Override
public void reset(ClientAssociation association) throws ServiceError, IOException {
if (association != null) {
association.getDataValues((FcModelNode) node);
}
if (data != null) {
data.reset();
} else {
for (int i = 0; i < getChildCount(); i++) {
if (getChildAt(i) instanceof DataObjectTreeNode) {
DataTreeNode child = (DataTreeNode) getChildAt(i);
child.reset(null);
}
}
}
}
@Override
public void writeValues(ClientAssociation association) throws ServiceError, IOException {
if (data != null) {
data.write();
} else {
for (int i = 0; i < getChildCount(); i++) {
if (getChildAt(i) instanceof DataObjectTreeNode) {
DataTreeNode child = (DataTreeNode) getChildAt(i);
child.writeValues(null);
}
}
}
if (association != null) {
association.setDataValues((FcModelNode) node);
}
}
@Override
public boolean writable() {
if (node instanceof FcModelNode) {
FcModelNode modelNode = (FcModelNode) node;
Fc constraint = modelNode.getFc();
return constraint != Fc.ST && constraint != Fc.MX;
}
return false;
}
@Override
public boolean readable() {
return node instanceof FcModelNode;
}
}

@ -0,0 +1,77 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui;
import com.beanit.iec61850bean.ClientAssociation;
import com.beanit.iec61850bean.DataSet;
import com.beanit.iec61850bean.ServiceError;
import java.io.IOException;
import javax.swing.tree.DefaultMutableTreeNode;
public class DataSetTreeNode extends DefaultMutableTreeNode implements DataTreeNode {
private static final long serialVersionUID = 7919716359809465616L;
private final DataSet node;
public DataSetTreeNode(String name, DataSet node) {
super(name);
this.node = node;
}
public DataSet getNode() {
return node;
}
@Override
public void reset(ClientAssociation association) throws ServiceError, IOException {
if (association != null) {
association.getDataSetValues(node);
}
for (int i = 0; i < getChildCount(); i++) {
if (getChildAt(i) instanceof DataObjectTreeNode) {
DataTreeNode child = (DataTreeNode) getChildAt(i);
child.reset(null);
}
}
}
@Override
public void writeValues(ClientAssociation association) throws ServiceError, IOException {
for (int i = 0; i < getChildCount(); i++) {
if (getChildAt(i) instanceof DataObjectTreeNode) {
DataTreeNode child = (DataTreeNode) getChildAt(i);
child.writeValues(null);
}
}
if (association != null) {
association.setDataSetValues(node);
}
}
@Override
public BasicDataBind<?> getData() {
return null;
}
@Override
public boolean writable() {
return true;
}
@Override
public boolean readable() {
return true;
}
}

@ -0,0 +1,36 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui;
import com.beanit.iec61850bean.ClientAssociation;
import com.beanit.iec61850bean.ServiceError;
import java.io.IOException;
import javax.swing.tree.TreeNode;
public interface DataTreeNode {
BasicDataBind<?> getData();
void reset(ClientAssociation association) throws ServiceError, IOException;
void writeValues(ClientAssociation association) throws ServiceError, IOException;
int getChildCount();
TreeNode getChildAt(int index);
boolean writable();
boolean readable();
}

@ -0,0 +1,131 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui;
import com.beanit.iec61850bean.DataSet;
import com.beanit.iec61850bean.Fc;
import com.beanit.iec61850bean.FcModelNode;
import com.beanit.iec61850bean.LogicalDevice;
import com.beanit.iec61850bean.LogicalNode;
import com.beanit.iec61850bean.ModelNode;
import com.beanit.iec61850bean.ServerModel;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.swing.tree.TreeNode;
public class ServerModelParser {
private final ServerModel model;
private DataObjectTreeNode modelTree;
public ServerModelParser(ServerModel model) {
this.model = model;
}
public TreeNode getModelTree() {
if (modelTree == null) {
createModelTree();
}
return modelTree;
}
private synchronized void createModelTree() {
if (modelTree == null) {
modelTree = new DataObjectTreeNode("server", null);
for (ModelNode node : model.getChildren()) {
if (node instanceof LogicalDevice == false) {
System.out.println(
"Node " + node.getName() + " is " + node.getClass() + " (should be LogicalDevice)");
continue;
}
addLogicalDevice(modelTree, (LogicalDevice) node);
}
for (DataSet dataSet : model.getDataSets()) {
addDataSet(modelTree, dataSet);
}
}
}
private void addLogicalDevice(DataObjectTreeNode root, LogicalDevice node) {
DataObjectTreeNode treeLD = new DataObjectTreeNode(node.getName(), node);
root.add(treeLD);
for (ModelNode subNode : node.getChildren()) {
if (subNode instanceof LogicalNode == false) {
System.out.println(
"Node " + subNode.getName() + " is " + subNode.getClass() + " (should be LogicalNode)");
continue;
}
addLogicalNode(treeLD, (LogicalNode) subNode);
}
}
private void addLogicalNode(DataObjectTreeNode parent, LogicalNode node) {
DataObjectTreeNode treeLN = new DataObjectTreeNode(node.getName(), node);
parent.add(treeLN);
Collection<ModelNode> children = node.getChildren();
Map<String, Set<Fc>> childMap = new HashMap<>();
for (ModelNode child : children) {
if (!childMap.containsKey(child.getName())) {
childMap.put(child.getName(), new HashSet<Fc>());
}
childMap.get(child.getName()).add(((FcModelNode) child).getFc());
}
for (Map.Entry<String, Set<Fc>> childEntry : childMap.entrySet()) {
addFunctionalConstraintObject(treeLN, node, childEntry.getKey(), childEntry.getValue());
}
}
private void addDataSet(DataObjectTreeNode parent, DataSet node) {
DataSetTreeNode treeDS = new DataSetTreeNode(node.getReferenceStr(), node);
parent.add(treeDS);
Collection<FcModelNode> children = node.getMembers();
for (ModelNode child : children) {
addFunctionalConstraintObject(treeDS, child);
}
}
private void addFunctionalConstraintObject(
DataObjectTreeNode parent, LogicalNode parentNode, String childName, Set<Fc> childFcs) {
DataObjectTreeNode treeFCDO = new DataObjectTreeNode(childName, null);
parent.add(treeFCDO);
for (Fc constraint : childFcs) {
ModelNode subNode = parentNode.getChild(childName, constraint);
addDataObject(treeFCDO, "[" + constraint + "]", subNode);
}
}
private void addFunctionalConstraintObject(DataSetTreeNode parent, ModelNode node) {
DataObjectTreeNode treeFCDO = new DataObjectTreeNode(node.getReference().toString(), node);
parent.add(treeFCDO);
if (node.getChildren() != null) {
for (ModelNode subNode : node.getChildren()) {
addDataObject(treeFCDO, subNode.getName(), subNode);
}
}
}
private void addDataObject(DataObjectTreeNode parent, String name, ModelNode node) {
DataObjectTreeNode treeDO = new DataObjectTreeNode(name, node);
parent.add(treeDO);
if (node.getChildren() != null) {
for (ModelNode subNode : node.getChildren()) {
addDataObject(treeDO, subNode.getName(), subNode);
}
}
}
}

@ -0,0 +1,202 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JTextField;
public class SettingsFrame extends JDialog implements ActionListener {
private static final long serialVersionUID = -411845634137160667L;
private int tselLocal1 = 0;
private final JTextField tselLocalField1 = new JTextField(Integer.toString(tselLocal1));
private int tselLocal2 = 0;
private final JTextField tselLocalField2 = new JTextField(Integer.toString(tselLocal2));
private int tselRemote1 = 0;
private final JTextField tselRemoteField1 = new JTextField(Integer.toString(tselRemote1));
private int tselRemote2 = 1;
private final JTextField tselRemoteField2 = new JTextField(Integer.toString(tselRemote2));
public SettingsFrame() {
setModalityType(ModalityType.APPLICATION_MODAL);
final GridBagLayout layout = new GridBagLayout();
setLayout(layout);
this.setSize(200, 120);
setLocationRelativeTo(null);
JLabel label = new JLabel("TSelLocal: ");
GridBagConstraints constraint = new GridBagConstraints();
constraint.gridwidth = 1;
constraint.gridheight = 1;
constraint.gridx = 0;
constraint.gridy = 0;
constraint.insets = new Insets(5, 5, 5, 5);
constraint.anchor = GridBagConstraints.WEST;
layout.setConstraints(label, constraint);
add(label);
constraint = new GridBagConstraints();
constraint.fill = GridBagConstraints.HORIZONTAL;
constraint.gridwidth = 1;
constraint.gridheight = 1;
constraint.gridx = 1;
constraint.gridy = 0;
constraint.weightx = 1;
constraint.insets = new Insets(5, 5, 5, 5);
constraint.anchor = GridBagConstraints.WEST;
layout.setConstraints(tselLocalField1, constraint);
add(tselLocalField1);
constraint = new GridBagConstraints();
constraint.fill = GridBagConstraints.HORIZONTAL;
constraint.gridwidth = 1;
constraint.gridheight = 1;
constraint.gridx = 2;
constraint.gridy = 0;
constraint.weightx = 1;
constraint.insets = new Insets(5, 5, 5, 5);
constraint.anchor = GridBagConstraints.WEST;
layout.setConstraints(tselLocalField2, constraint);
add(tselLocalField2);
label = new JLabel("TSelRemote: ");
constraint = new GridBagConstraints();
constraint.gridwidth = 1;
constraint.gridheight = 1;
constraint.gridx = 0;
constraint.gridy = 1;
constraint.insets = new Insets(5, 5, 5, 5);
constraint.anchor = GridBagConstraints.WEST;
layout.setConstraints(label, constraint);
add(label);
constraint = new GridBagConstraints();
constraint.fill = GridBagConstraints.HORIZONTAL;
constraint.gridwidth = 1;
constraint.gridheight = 1;
constraint.gridx = 1;
constraint.gridy = 1;
constraint.weightx = 1;
constraint.insets = new Insets(5, 5, 5, 5);
constraint.anchor = GridBagConstraints.WEST;
layout.setConstraints(tselRemoteField1, constraint);
add(tselRemoteField1);
constraint = new GridBagConstraints();
constraint.fill = GridBagConstraints.HORIZONTAL;
constraint.gridwidth = 1;
constraint.gridheight = 1;
constraint.gridx = 2;
constraint.gridy = 1;
constraint.weightx = 1;
constraint.insets = new Insets(5, 5, 5, 5);
constraint.anchor = GridBagConstraints.WEST;
layout.setConstraints(tselRemoteField2, constraint);
add(tselRemoteField2);
JButton button = new JButton("Cancel");
button.setActionCommand("Cancel");
button.addActionListener(this);
constraint.gridwidth = 1;
constraint.gridheight = 1;
constraint.gridx = 0;
constraint.gridy = 2;
constraint.insets = new Insets(5, 5, 5, 5);
constraint.anchor = GridBagConstraints.SOUTHWEST;
layout.setConstraints(button, constraint);
add(button);
button = new JButton("OK");
button.setActionCommand("Okay");
button.addActionListener(this);
constraint.gridwidth = 2;
constraint.gridheight = 1;
constraint.gridx = 1;
constraint.gridy = 2;
constraint.insets = new Insets(5, 5, 5, 5);
constraint.anchor = GridBagConstraints.SOUTHWEST;
layout.setConstraints(button, constraint);
add(button);
}
@Override
public void actionPerformed(ActionEvent e) {
if ("cancel".equalsIgnoreCase(e.getActionCommand())) {
tselLocalField1.setText(Integer.toString(tselLocal1 & 0xFF));
tselLocalField2.setText(Integer.toString(tselLocal2 & 0xFF));
tselRemoteField1.setText(Integer.toString(tselRemote1 & 0xFF));
tselRemoteField2.setText(Integer.toString(tselRemote2 & 0xFF));
setVisible(false);
} else if ("okay".equalsIgnoreCase(e.getActionCommand())) {
tselLocal1 = parseTextField(tselLocalField1, tselLocal1);
tselLocal2 = parseTextField(tselLocalField2, tselLocal2);
tselRemote1 = parseTextField(tselRemoteField1, tselRemote1);
tselRemote2 = parseTextField(tselRemoteField2, tselRemote2);
setVisible(false);
}
}
public byte[] getTselLocal() {
return new byte[] {(byte) tselLocal1, (byte) tselLocal2};
}
public void setTselLocal(byte[] tsel) {
if (tsel.length != 2) {
throw new IllegalArgumentException("TSel must consist of 2 bytes");
}
tselLocal1 = tsel[0];
tselLocal2 = tsel[1];
tselLocalField1.setText(Integer.toString(tselLocal1 & 0xFF));
tselLocalField2.setText(Integer.toString(tselLocal2 & 0xFF));
}
public byte[] getTselRemote() {
return new byte[] {(byte) tselRemote1, (byte) tselRemote2};
}
public void setTselRemote(byte[] tsel) {
if (tsel.length != 2) {
throw new IllegalArgumentException("TSel must consist of 2 bytes");
}
tselRemote1 = tsel[0];
tselRemote2 = tsel[1];
tselRemoteField1.setText(Integer.toString(tselRemote1 & 0xFF));
tselRemoteField2.setText(Integer.toString(tselRemote2 & 0xFF));
}
private int parseTextField(JTextField field, int oldValue) {
int value = oldValue;
try {
int newValue = Integer.parseInt(field.getText());
if (newValue >= 0 && newValue <= 255) {
value = newValue;
}
} catch (NumberFormatException e) {
return oldValue;
}
return value;
}
}

@ -0,0 +1,47 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui.databind;
import com.beanit.iec61850bean.BdaBoolean;
import com.beanit.iec61850bean.BdaType;
import com.beanit.iec61850bean.clientgui.BasicDataBind;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
public class BooleanDataBind extends BasicDataBind<BdaBoolean> {
private JCheckBox checkbox;
public BooleanDataBind(BdaBoolean data) {
super(data, BdaType.BOOLEAN);
}
@Override
protected JComponent init() {
checkbox = new JCheckBox();
checkbox.setBorder(null);
checkbox.setSelected(data.getValue());
return checkbox;
}
@Override
protected void resetImpl() {
checkbox.setSelected(data.getValue());
}
@Override
protected void writeImpl() {
data.setValue(checkbox.isSelected());
}
}

@ -0,0 +1,55 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui.databind;
import com.beanit.iec61850bean.BdaCheck;
import com.beanit.iec61850bean.BdaType;
import com.beanit.iec61850bean.clientgui.BasicDataBind;
import java.awt.Component;
import javax.swing.BoxLayout;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JPanel;
public class CheckDataBind extends BasicDataBind<BdaCheck> {
private final JCheckBox interlock = new JCheckBox("Interlock");
private final JCheckBox synchron = new JCheckBox("Synchron");
public CheckDataBind(BdaCheck data) {
super(data, BdaType.CHECK);
}
@Override
protected JComponent init() {
interlock.setAlignmentX(Component.LEFT_ALIGNMENT);
JPanel valuePanel = new JPanel();
valuePanel.setLayout(new BoxLayout(valuePanel, BoxLayout.PAGE_AXIS));
valuePanel.add(interlock);
valuePanel.add(synchron);
return valuePanel;
}
@Override
protected void resetImpl() {
interlock.setSelected(data.getInterlockCheck());
synchron.setSelected(data.getSynchrocheck());
}
@Override
protected void writeImpl() {
data.setInterlockCheck(interlock.isSelected());
data.setSynchrocheck(synchron.isSelected());
}
}

@ -0,0 +1,46 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui.databind;
import com.beanit.iec61850bean.BdaDoubleBitPos;
import com.beanit.iec61850bean.BdaType;
import com.beanit.iec61850bean.clientgui.BasicDataBind;
import javax.swing.JComboBox;
import javax.swing.JComponent;
public class DoubleBitPosDataBind extends BasicDataBind<BdaDoubleBitPos> {
@SuppressWarnings("unchecked")
private final JComboBox valueField = new JComboBox(BdaDoubleBitPos.DoubleBitPos.values());
public DoubleBitPosDataBind(BdaDoubleBitPos data) {
super(data, BdaType.DOUBLE_BIT_POS);
}
@Override
protected JComponent init() {
return valueField;
}
@Override
protected void resetImpl() {
valueField.setSelectedItem(data.getDoubleBitPos());
}
@Override
protected void writeImpl() {
// TODO uncomment once data.setTapCommand() is implemented
// data.setTapCommand(valueField.getSelectedItem());
}
}

@ -0,0 +1,53 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui.databind;
import com.beanit.iec61850bean.BdaEntryTime;
import com.beanit.iec61850bean.BdaType;
import com.beanit.iec61850bean.clientgui.BasicDataBind;
import javax.swing.JComponent;
import javax.swing.JLabel;
public class EntryTimeDataBind extends BasicDataBind<BdaEntryTime> {
public EntryTimeDataBind(BdaEntryTime data) {
super(data, BdaType.ENTRY_TIME);
}
@Override
protected JComponent init() {
byte[] value = data.getValue();
StringBuilder sb;
sb = new StringBuilder("EntryTime [");
for (int i = 0; i < value.length; i++) {
sb.append(Integer.toHexString(value[i] & 0xff));
if (i != value.length - 1) {
sb.append(", ");
}
}
sb.append("]");
return new JLabel(sb.toString());
}
@Override
protected void resetImpl() {
// ignore for now
}
@Override
protected void writeImpl() {
// ignore for now
}
}

@ -0,0 +1,49 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui.databind;
import com.beanit.iec61850bean.BdaFloat32;
import com.beanit.iec61850bean.BdaType;
public class Float32DataBind extends TextFieldDataBind<BdaFloat32> {
private static final FloatFilter FILTER = new FloatFilter();
public Float32DataBind(BdaFloat32 data) {
super(data, BdaType.FLOAT32, FILTER);
}
@Override
protected void resetImpl() {
inputField.setText(data.getFloat().toString());
}
@Override
protected void writeImpl() {
float newFloat = Float.parseFloat(inputField.getText());
data.setFloat(newFloat);
}
private static class FloatFilter extends AbstractFilter {
@Override
protected boolean test(String text) {
try {
Float.parseFloat(text);
return true;
} catch (NumberFormatException e) {
return false;
}
}
}
}

@ -0,0 +1,49 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui.databind;
import com.beanit.iec61850bean.BdaFloat64;
import com.beanit.iec61850bean.BdaType;
public class Float64DataBind extends TextFieldDataBind<BdaFloat64> {
private static final DoubleFilter FILTER = new DoubleFilter();
public Float64DataBind(BdaFloat64 data) {
super(data, BdaType.FLOAT64, FILTER);
}
@Override
protected void resetImpl() {
inputField.setText(data.getDouble().toString());
}
@Override
protected void writeImpl() {
double newDouble = Double.parseDouble(inputField.getText());
data.setDouble(newDouble);
}
private static class DoubleFilter extends AbstractFilter {
@Override
protected boolean test(String text) {
try {
Double.parseDouble(text);
return true;
} catch (NumberFormatException e) {
return false;
}
}
}
}

@ -0,0 +1,48 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui.databind;
import com.beanit.iec61850bean.BdaInt16;
import com.beanit.iec61850bean.BdaType;
public class Int16DataBind extends TextFieldDataBind<BdaInt16> {
private static final Int16Filter FILTER = new Int16Filter();
public Int16DataBind(BdaInt16 data) {
super(data, BdaType.INT16, FILTER);
}
@Override
protected void resetImpl() {
inputField.setText(Short.toString(data.getValue()));
}
@Override
protected void writeImpl() {
data.setValue(Short.parseShort(inputField.getText()));
}
private static class Int16Filter extends AbstractFilter {
@Override
protected boolean test(String text) {
try {
Short.parseShort(text);
return true;
} catch (NumberFormatException e) {
return false;
}
}
}
}

@ -0,0 +1,48 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui.databind;
import com.beanit.iec61850bean.BdaInt16U;
import com.beanit.iec61850bean.BdaType;
public class Int16UDataBind extends TextFieldDataBind<BdaInt16U> {
private static final UInt16Filter FILTER = new UInt16Filter();
public Int16UDataBind(BdaInt16U data) {
super(data, BdaType.INT16U, FILTER);
}
@Override
protected void resetImpl() {
inputField.setText(Integer.toString(data.getValue()));
}
@Override
protected void writeImpl() {
data.setValue(Integer.parseInt(inputField.getText()));
}
private static class UInt16Filter extends AbstractFilter {
@Override
protected boolean test(String text) {
try {
int value = Integer.parseInt(text);
return value >= 0 && value <= 0xFFFF;
} catch (NumberFormatException e) {
return false;
}
}
}
}

@ -0,0 +1,48 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui.databind;
import com.beanit.iec61850bean.BdaInt32;
import com.beanit.iec61850bean.BdaType;
public class Int32DataBind extends TextFieldDataBind<BdaInt32> {
private static final Int32Filter FILTER = new Int32Filter();
public Int32DataBind(BdaInt32 data) {
super(data, BdaType.INT32, FILTER);
}
@Override
protected void resetImpl() {
inputField.setText(Integer.toString(data.getValue()));
}
@Override
protected void writeImpl() {
data.setValue(Integer.parseInt(inputField.getText()));
}
private static class Int32Filter extends AbstractFilter {
@Override
protected boolean test(String text) {
try {
Integer.parseInt(text);
return true;
} catch (NumberFormatException e) {
return false;
}
}
}
}

@ -0,0 +1,48 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui.databind;
import com.beanit.iec61850bean.BdaInt32U;
import com.beanit.iec61850bean.BdaType;
public class Int32UDataBind extends TextFieldDataBind<BdaInt32U> {
private static final UInt32Filter FILTER = new UInt32Filter();
public Int32UDataBind(BdaInt32U data) {
super(data, BdaType.INT32U, FILTER);
}
@Override
protected void resetImpl() {
inputField.setText(Long.toString(data.getValue()));
}
@Override
protected void writeImpl() {
data.setValue(Long.parseLong(inputField.getText()));
}
private static class UInt32Filter extends AbstractFilter {
@Override
protected boolean test(String text) {
try {
long value = Long.parseLong(text);
return value >= 0 && value <= 0xFFFFFFFFL;
} catch (NumberFormatException e) {
return false;
}
}
}
}

@ -0,0 +1,48 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui.databind;
import com.beanit.iec61850bean.BdaInt64;
import com.beanit.iec61850bean.BdaType;
public class Int64DataBind extends TextFieldDataBind<BdaInt64> {
private static final Int64Filter FILTER = new Int64Filter();
public Int64DataBind(BdaInt64 data) {
super(data, BdaType.INT64, FILTER);
}
@Override
protected void resetImpl() {
inputField.setText(Long.toString(data.getValue()));
}
@Override
protected void writeImpl() {
data.setValue(Long.parseLong(inputField.getText()));
}
private static class Int64Filter extends AbstractFilter {
@Override
protected boolean test(String text) {
try {
Long.parseLong(text);
return true;
} catch (NumberFormatException e) {
return false;
}
}
}
}

@ -0,0 +1,48 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui.databind;
import com.beanit.iec61850bean.BdaInt8;
import com.beanit.iec61850bean.BdaType;
public class Int8DataBind extends TextFieldDataBind<BdaInt8> {
private static final Int8Filter FILTER = new Int8Filter();
public Int8DataBind(BdaInt8 data) {
super(data, BdaType.INT8, FILTER);
}
@Override
protected void resetImpl() {
inputField.setText(Byte.toString(data.getValue()));
}
@Override
protected void writeImpl() {
data.setValue(Byte.parseByte(inputField.getText()));
}
private static class Int8Filter extends AbstractFilter {
@Override
protected boolean test(String text) {
try {
Byte.parseByte(text);
return true;
} catch (NumberFormatException e) {
return false;
}
}
}
}

@ -0,0 +1,48 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui.databind;
import com.beanit.iec61850bean.BdaInt8U;
import com.beanit.iec61850bean.BdaType;
public class Int8UDataBind extends TextFieldDataBind<BdaInt8U> {
private static final UInt8Filter FILTER = new UInt8Filter();
public Int8UDataBind(BdaInt8U data) {
super(data, BdaType.INT8U, FILTER);
}
@Override
protected void resetImpl() {
inputField.setText(Short.toString(data.getValue()));
}
@Override
protected void writeImpl() {
data.setValue(Short.parseShort(inputField.getText()));
}
private static class UInt8Filter extends AbstractFilter {
@Override
protected boolean test(String text) {
try {
short value = Short.parseShort(text);
return value >= 0 && value <= 0xFF;
} catch (NumberFormatException e) {
return false;
}
}
}
}

@ -0,0 +1,53 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui.databind;
import com.beanit.iec61850bean.BdaOctetString;
import com.beanit.iec61850bean.BdaType;
import com.beanit.iec61850bean.clientgui.BasicDataBind;
import javax.swing.JComponent;
import javax.swing.JLabel;
public class OctetStringDataBind extends BasicDataBind<BdaOctetString> {
public OctetStringDataBind(BdaOctetString data) {
super(data, BdaType.OCTET_STRING);
}
@Override
protected JComponent init() {
byte[] value = data.getValue();
StringBuilder sb;
sb = new StringBuilder("OctetString [");
for (int i = 0; i < value.length; i++) {
sb.append(Integer.toHexString(value[i] & 0xff));
if (i != value.length - 1) {
sb.append(", ");
}
}
sb.append("]");
return new JLabel(sb.toString());
}
@Override
protected void resetImpl() {
// ignore for now
}
@Override
protected void writeImpl() {
// ignore for now
}
}

@ -0,0 +1,83 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui.databind;
import com.beanit.iec61850bean.BdaOptFlds;
import com.beanit.iec61850bean.BdaType;
import com.beanit.iec61850bean.clientgui.BasicDataBind;
import java.awt.Component;
import javax.swing.BoxLayout;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JPanel;
public class OptfldsDataBind extends BasicDataBind<BdaOptFlds> {
private final JCheckBox bufferOverflow = new JCheckBox("BufferOverflow");
private final JCheckBox configRevision = new JCheckBox("ConfigRevision");
private final JCheckBox dataReference = new JCheckBox("DataReference");
private final JCheckBox dataSetName = new JCheckBox("DataSetName");
private final JCheckBox entryId = new JCheckBox("EntryId");
private final JCheckBox reasonForInclusion = new JCheckBox("ReasonForInclusion");
private final JCheckBox reportTimestamp = new JCheckBox("ReportTimestamp");
private final JCheckBox segmentation = new JCheckBox("Segmentation");
private final JCheckBox sequenceNumber = new JCheckBox("SequenceNumber");
public OptfldsDataBind(BdaOptFlds data) {
super(data, BdaType.OPTFLDS);
}
@Override
protected JComponent init() {
bufferOverflow.setAlignmentX(Component.LEFT_ALIGNMENT);
JPanel valuePanel = new JPanel();
valuePanel.setLayout(new BoxLayout(valuePanel, BoxLayout.PAGE_AXIS));
valuePanel.add(bufferOverflow);
valuePanel.add(configRevision);
valuePanel.add(dataReference);
valuePanel.add(dataSetName);
valuePanel.add(entryId);
valuePanel.add(reasonForInclusion);
valuePanel.add(reportTimestamp);
valuePanel.add(segmentation);
valuePanel.add(sequenceNumber);
return valuePanel;
}
@Override
protected void resetImpl() {
bufferOverflow.setSelected(data.isBufferOverflow());
configRevision.setSelected(data.isConfigRevision());
dataReference.setSelected(data.isDataReference());
dataSetName.setSelected(data.isDataSetName());
entryId.setSelected(data.isEntryId());
reasonForInclusion.setSelected(data.isReasonForInclusion());
reportTimestamp.setSelected(data.isReportTimestamp());
segmentation.setSelected(data.isSegmentation());
sequenceNumber.setSelected(data.isSequenceNumber());
}
@Override
protected void writeImpl() {
data.setBufferOverflow(bufferOverflow.isSelected());
data.setConfigRevision(configRevision.isSelected());
data.setDataReference(dataReference.isSelected());
data.setDataSetName(dataSetName.isSelected());
data.setEntryId(entryId.isSelected());
data.setReasonForInclusion(reasonForInclusion.isSelected());
data.setReportTimestamp(reportTimestamp.isSelected());
data.setSegmentation(segmentation.isSelected());
data.setSequenceNumber(sequenceNumber.isSelected());
}
}

@ -0,0 +1,100 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui.databind;
import com.beanit.iec61850bean.BdaQuality;
import com.beanit.iec61850bean.BdaType;
import com.beanit.iec61850bean.clientgui.BasicDataBind;
import java.awt.Component;
import javax.swing.BoxLayout;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JPanel;
public class QualityDataBind extends BasicDataBind<BdaQuality> {
@SuppressWarnings("unchecked")
private final JComboBox validity = new JComboBox(BdaQuality.Validity.values());
private final JCheckBox badReference = new JCheckBox("BadReference");
private final JCheckBox failure = new JCheckBox("Failure");
private final JCheckBox inaccurate = new JCheckBox("Inaccurate");
private final JCheckBox inconsistent = new JCheckBox("Inconsistent");
private final JCheckBox oldData = new JCheckBox("OldData");
private final JCheckBox operatorBlocked = new JCheckBox("OperatorBlocked");
private final JCheckBox oscillatory = new JCheckBox("Oscillatory");
private final JCheckBox outOfRange = new JCheckBox("OutOfRange");
private final JCheckBox overflow = new JCheckBox("Overflow");
private final JCheckBox substituded = new JCheckBox("Substituded");
private final JCheckBox test = new JCheckBox("Test");
public QualityDataBind(BdaQuality data) {
super(data, BdaType.QUALITY);
}
@Override
protected JComponent init() {
validity.setAlignmentX(Component.LEFT_ALIGNMENT);
JPanel valuePanel = new JPanel();
valuePanel.setLayout(new BoxLayout(valuePanel, BoxLayout.PAGE_AXIS));
valuePanel.setAlignmentX(Component.LEFT_ALIGNMENT);
valuePanel.add(validity);
valuePanel.add(badReference);
valuePanel.add(failure);
valuePanel.add(inaccurate);
valuePanel.add(inconsistent);
valuePanel.add(oldData);
valuePanel.add(operatorBlocked);
valuePanel.add(oscillatory);
valuePanel.add(outOfRange);
valuePanel.add(overflow);
valuePanel.add(substituded);
valuePanel.add(test);
return valuePanel;
}
@Override
protected void resetImpl() {
validity.setSelectedItem(data.getValidity());
badReference.setSelected(data.isBadReference());
failure.setSelected(data.isFailure());
inaccurate.setSelected(data.isInaccurate());
inconsistent.setSelected(data.isInconsistent());
oldData.setSelected(data.isOldData());
operatorBlocked.setSelected(data.isOperatorBlocked());
oscillatory.setSelected(data.isOscillatory());
outOfRange.setSelected(data.isOutOfRange());
overflow.setSelected(data.isOverflow());
substituded.setSelected(data.isSubstituted());
test.setSelected(data.isTest());
}
@Override
protected void writeImpl() {
// TODO uncomment once mutators are implemented
// data.setValidity(validity.getSelectedItem());
// data.setBadReference(badReference.isSelected());
// data.setFailure(failure.isSelected());
// data.setInaccurate(inaccurate.isSelected());
// data.setInconsistent(inconsistent.isSelected());
// data.setOldData(oldData.isSelected());
// data.setOperatorBlocked(operatorBlocked.isSelected());
// data.setOlscillatory(oscillatory.isSelected());
// data.setOutOfRange(outOfRange.isSelected());
// data.setOverflow(overflow.isSelected());
// data.setSubstituded(substituded.isSelected());
// data.setTest(test.isSelected());
}
}

@ -0,0 +1,71 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui.databind;
import com.beanit.iec61850bean.BdaReasonForInclusion;
import com.beanit.iec61850bean.BdaType;
import com.beanit.iec61850bean.clientgui.BasicDataBind;
import java.awt.Component;
import javax.swing.BoxLayout;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JPanel;
public class ReasonForInclusionDataBind extends BasicDataBind<BdaReasonForInclusion> {
private final JCheckBox applicationTrigger = new JCheckBox("ApplicationTrigger");
private final JCheckBox dataChange = new JCheckBox("DataChange");
private final JCheckBox dataUpdate = new JCheckBox("DataUpdate");
private final JCheckBox generalInterrogation = new JCheckBox("GeneralInterrogation");
private final JCheckBox integrity = new JCheckBox("Integrity");
private final JCheckBox qualitychanged = new JCheckBox("QualityChanged");
public ReasonForInclusionDataBind(BdaReasonForInclusion data) {
super(data, BdaType.REASON_FOR_INCLUSION);
}
@Override
protected JComponent init() {
applicationTrigger.setAlignmentX(Component.LEFT_ALIGNMENT);
JPanel valuePanel = new JPanel();
valuePanel.setLayout(new BoxLayout(valuePanel, BoxLayout.PAGE_AXIS));
valuePanel.add(applicationTrigger);
valuePanel.add(dataChange);
valuePanel.add(dataUpdate);
valuePanel.add(generalInterrogation);
valuePanel.add(integrity);
valuePanel.add(qualitychanged);
return valuePanel;
}
@Override
protected void resetImpl() {
applicationTrigger.setSelected(data.isApplicationTrigger());
dataChange.setSelected(data.isDataChange());
dataUpdate.setSelected(data.isDataUpdate());
generalInterrogation.setSelected(data.isGeneralInterrogation());
integrity.setSelected(data.isIntegrity());
qualitychanged.setSelected(data.isQualityChange());
}
@Override
protected void writeImpl() {
data.setApplicationTrigger(applicationTrigger.isSelected());
data.setDataChange(dataChange.isSelected());
data.setDataUpdate(dataUpdate.isSelected());
data.setGeneralInterrogation(generalInterrogation.isSelected());
data.setIntegrity(integrity.isSelected());
data.setQualityChange(qualitychanged.isSelected());
}
}

@ -0,0 +1,46 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui.databind;
import com.beanit.iec61850bean.BdaTapCommand;
import com.beanit.iec61850bean.BdaType;
import com.beanit.iec61850bean.clientgui.BasicDataBind;
import javax.swing.JComboBox;
import javax.swing.JComponent;
public class TapCommandDataBind extends BasicDataBind<BdaTapCommand> {
@SuppressWarnings("unchecked")
private final JComboBox tapCommand = new JComboBox(BdaTapCommand.TapCommand.values());
public TapCommandDataBind(BdaTapCommand data) {
super(data, BdaType.TAP_COMMAND);
}
@Override
protected JComponent init() {
return tapCommand;
}
@Override
protected void resetImpl() {
tapCommand.setSelectedItem(data.getTapCommand());
}
@Override
protected void writeImpl() {
// TODO uncomment once data.setTapCommand is implemented
// data.setTapCommand(tapCommand.getSelectedItem());
}
}

@ -0,0 +1,90 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui.databind;
import com.beanit.iec61850bean.BasicDataAttribute;
import com.beanit.iec61850bean.BdaType;
import com.beanit.iec61850bean.clientgui.BasicDataBind;
import javax.swing.JComponent;
import javax.swing.JTextField;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.DocumentFilter;
import javax.swing.text.PlainDocument;
public abstract class TextFieldDataBind<E extends BasicDataAttribute> extends BasicDataBind<E> {
private final DocumentFilter filter;
protected JTextField inputField;
TextFieldDataBind(E data, BdaType type, AbstractFilter filter) {
super(data, type);
this.filter = filter;
}
@Override
protected JComponent init() {
inputField = new JTextField();
PlainDocument doc = (PlainDocument) inputField.getDocument();
doc.setDocumentFilter(filter);
resetImpl();
return inputField;
}
protected abstract static class AbstractFilter extends DocumentFilter {
@Override
public final void insertString(FilterBypass fb, int offset, String string, AttributeSet attr)
throws BadLocationException {
Document doc = fb.getDocument();
StringBuilder sb = new StringBuilder();
sb.append(doc.getText(0, doc.getLength()));
sb.insert(offset, string);
if (test(sb.toString())) {
super.insertString(fb, offset, string, attr);
}
}
@Override
public final void replace(
FilterBypass fb, int offset, int length, String text, AttributeSet attrs)
throws BadLocationException {
Document doc = fb.getDocument();
StringBuilder sb = new StringBuilder();
sb.append(doc.getText(0, doc.getLength()));
sb.replace(offset, offset + length, text);
if (test(sb.toString())) {
super.replace(fb, offset, length, text, attrs);
}
}
@Override
public final void remove(FilterBypass fb, int offset, int length) throws BadLocationException {
Document doc = fb.getDocument();
StringBuilder sb = new StringBuilder();
sb.append(doc.getText(0, doc.getLength()));
sb.delete(offset, offset + length);
if (test(sb.toString())) {
super.remove(fb, offset, length);
}
}
protected abstract boolean test(String text);
}
}

@ -0,0 +1,50 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui.databind;
import com.beanit.iec61850bean.BdaTimestamp;
import com.beanit.iec61850bean.BdaType;
import java.time.Instant;
import java.time.format.DateTimeParseException;
public class TimeStampDataBind extends TextFieldDataBind<BdaTimestamp> {
private static final TimestampFilter FILTER = new TimestampFilter();
public TimeStampDataBind(BdaTimestamp data) {
super(data, BdaType.TIMESTAMP, FILTER);
}
@Override
protected void resetImpl() {
inputField.setText(data.getInstant().toString());
}
@Override
protected void writeImpl() {
data.setInstant(Instant.parse(inputField.getText()));
}
private static class TimestampFilter extends AbstractFilter {
@Override
protected boolean test(String text) {
try {
Instant.parse(text);
return true;
} catch (DateTimeParseException e) {
return false;
}
}
}
}

@ -0,0 +1,67 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui.databind;
import com.beanit.iec61850bean.BdaTriggerConditions;
import com.beanit.iec61850bean.BdaType;
import com.beanit.iec61850bean.clientgui.BasicDataBind;
import java.awt.Component;
import javax.swing.BoxLayout;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JPanel;
public class TriggerConditionDataBind extends BasicDataBind<BdaTriggerConditions> {
private final JCheckBox dataChange = new JCheckBox("DataChange");
private final JCheckBox dataUpdate = new JCheckBox("DataUpdate");
private final JCheckBox generalInterrogation = new JCheckBox("GeneralInterrogation");
private final JCheckBox integrity = new JCheckBox("Integrity");
private final JCheckBox qualityChange = new JCheckBox("QualityChange");
public TriggerConditionDataBind(BdaTriggerConditions data) {
super(data, BdaType.TRIGGER_CONDITIONS);
}
@Override
protected JComponent init() {
dataChange.setAlignmentX(Component.LEFT_ALIGNMENT);
JPanel valuePanel = new JPanel();
valuePanel.setLayout(new BoxLayout(valuePanel, BoxLayout.PAGE_AXIS));
valuePanel.add(dataChange);
valuePanel.add(dataUpdate);
valuePanel.add(generalInterrogation);
valuePanel.add(integrity);
valuePanel.add(qualityChange);
return valuePanel;
}
@Override
protected void resetImpl() {
dataChange.setSelected(data.isDataChange());
dataUpdate.setSelected(data.isDataUpdate());
generalInterrogation.setSelected(data.isGeneralInterrogation());
integrity.setSelected(data.isIntegrity());
qualityChange.setSelected(data.isQualityChange());
}
@Override
protected void writeImpl() {
data.setDataChange(dataChange.isSelected());
data.setDataUpdate(dataUpdate.isSelected());
data.setGeneralInterrogation(generalInterrogation.isSelected());
data.setIntegrity(integrity.isSelected());
data.setQualityChange(qualityChange.isSelected());
}
}

@ -0,0 +1,60 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui.databind;
import com.beanit.iec61850bean.BdaType;
import com.beanit.iec61850bean.BdaUnicodeString;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.StandardCharsets;
public class UnicodeStringDataBind extends TextFieldDataBind<BdaUnicodeString> {
private static final Charset UTF8 = StandardCharsets.UTF_8;
public UnicodeStringDataBind(BdaUnicodeString data) {
super(data, BdaType.UNICODE_STRING, new Utf8Filter(data.getMaxLength()));
}
@Override
protected void resetImpl() {
inputField.setText(new String(data.getValue(), UTF8));
}
@Override
protected void writeImpl() {
data.setValue(UTF8.encode(inputField.getText()).array());
}
private static class Utf8Filter extends AbstractFilter {
private final CharsetEncoder encoder = StandardCharsets.UTF_8.newEncoder();
private final int maxBytes;
public Utf8Filter(int maxBytes) {
this.maxBytes = maxBytes;
}
@Override
protected boolean test(String text) {
try {
byte[] codedString = encoder.encode(CharBuffer.wrap(text)).array();
return codedString.length <= maxBytes;
} catch (CharacterCodingException e) {
return false;
}
}
}
}

@ -0,0 +1,60 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui.databind;
import com.beanit.iec61850bean.BdaType;
import com.beanit.iec61850bean.BdaVisibleString;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.StandardCharsets;
public class VisibleStringDataBind extends TextFieldDataBind<BdaVisibleString> {
private static final Charset ASCII = StandardCharsets.US_ASCII;
public VisibleStringDataBind(BdaVisibleString data) {
super(data, BdaType.VISIBLE_STRING, new AsciiFilter(data.getMaxLength()));
}
@Override
protected void resetImpl() {
inputField.setText(new String(data.getValue(), ASCII));
}
@Override
protected void writeImpl() {
data.setValue(ASCII.encode(inputField.getText()).array());
}
private static class AsciiFilter extends TextFieldDataBind.AbstractFilter {
private final CharsetEncoder encoder = StandardCharsets.US_ASCII.newEncoder();
private final int maxBytes;
public AsciiFilter(int maxBytes) {
this.maxBytes = maxBytes;
}
@Override
protected boolean test(String text) {
try {
byte[] codedString = encoder.encode(CharBuffer.wrap(text)).array();
return codedString.length <= maxBytes;
} catch (CharacterCodingException e) {
return false;
}
}
}
}

@ -0,0 +1,34 @@
/*
* Copyright 2011 The IEC61850bean Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.clientgui.util;
public class Counter {
private int value;
public Counter(int value) {
this.value = value;
}
public Counter() {
this(0);
}
public void increment() {
value++;
}
public int getValue() {
return value;
}
}

@ -0,0 +1,117 @@
/*
* Copyright 2012 The jASN1 Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.internal;
import com.beanit.asn1bean.ber.BerLength;
import com.beanit.asn1bean.ber.BerTag;
import com.beanit.asn1bean.ber.ReverseByteArrayOutputStream;
import com.beanit.asn1bean.ber.types.BerType;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
public class BerBoolean implements Serializable, BerType {
public static final BerTag tag =
new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.PRIMITIVE, BerTag.BOOLEAN_TAG);
private static final long serialVersionUID = 1L;
public boolean value;
private byte[] code = null;
public BerBoolean() {}
public BerBoolean(byte[] code) {
this.code = code;
}
public BerBoolean(boolean value) {
this.value = value;
}
@Override
public int encode(OutputStream reverseOS) throws IOException {
return encode(reverseOS, true);
}
public int encode(OutputStream reverseOS, boolean withTag) throws IOException {
if (code != null) {
reverseOS.write(code);
if (withTag) {
return tag.encode(reverseOS) + code.length;
}
return code.length;
}
int codeLength = 1;
if (value) {
reverseOS.write(0x01);
} else {
reverseOS.write(0);
}
codeLength += BerLength.encodeLength(reverseOS, codeLength);
if (withTag) {
codeLength += tag.encode(reverseOS);
}
return codeLength;
}
@Override
public int decode(InputStream is) throws IOException {
return decode(is, true);
}
public int decode(InputStream is, boolean withTag) throws IOException {
int codeLength = 0;
if (withTag) {
codeLength += tag.decodeAndCheck(is);
}
BerLength length = new BerLength();
codeLength += length.decode(is);
if (length.val != 1) {
throw new IOException("Decoded length of BerBoolean is not correct");
}
int nextByte = is.read();
if (nextByte == -1) {
throw new EOFException("Unexpected end of input stream.");
}
codeLength++;
value = nextByte != 0;
return codeLength;
}
public void encodeAndSave(int encodingSizeGuess) throws IOException {
ReverseByteArrayOutputStream os = new ReverseByteArrayOutputStream(encodingSizeGuess);
encode(os, false);
code = os.getArray();
}
@Override
public String toString() {
return "" + value;
}
}

@ -0,0 +1,152 @@
/*
* Copyright 2019 beanit
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.internal;
import java.nio.ByteBuffer;
import java.util.Objects;
public class HexString {
private static final char[] hexArray = "0123456789ABCDEF".toCharArray();
/** Don't let anyone instantiate this class. */
private HexString() {}
/**
* Returns the byte as a hex string. If b is less than 16 the hex string returned contains a
* leading zero.
*
* @param b the byte to be converted
* @return the hex string.
*/
public static String fromByte(byte b) {
return fromBytes(new byte[] {b});
}
public static String fromByte(int b) {
return fromBytes(new byte[] {(byte) b});
}
/**
* Returns the integer value as hex string filled with leading zeros.
*
* @param i the integer value to be converted
* @return the hex string
*/
public static String fromInt(int i) {
byte[] bytes = new byte[] {(byte) (i >> 24), (byte) (i >> 16), (byte) (i >> 8), (byte) i};
return fromBytes(bytes);
}
/**
* Returns the long value as hex string filled with leading zeros.
*
* @param l the long value to be converted
* @return the hex string
*/
public static String fromLong(long l) {
byte[] bytes =
new byte[] {
(byte) (l >> 56),
(byte) (l >> 48),
(byte) (l >> 40),
(byte) (l >> 32),
(byte) (l >> 24),
(byte) (l >> 16),
(byte) (l >> 8),
(byte) l
};
return fromBytes(bytes);
}
public static String fromBytes(byte[] bytes) {
return fromBytes(bytes, 0, bytes.length);
}
public static String fromBytesFormatted(byte[] bytes) {
return fromBytesFormatted(bytes, 0, bytes.length);
}
public static String fromBytes(byte[] bytes, int offset, int length) {
char[] hexChars = new char[length * 2];
for (int j = 0; j < length; j++) {
int v = bytes[j + offset] & 0xff;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0f];
}
return new String(hexChars);
}
public static String fromBytes(ByteBuffer buffer) {
return fromBytes(buffer.array(), buffer.arrayOffset(), buffer.arrayOffset() + buffer.limit());
}
public static String fromBytesFormatted(byte[] bytes, int offset, int length) {
StringBuilder builder = new StringBuilder();
int l = 1;
for (int i = offset; i < (offset + length); i++) {
if ((l != 1) && ((l - 1) % 8 == 0)) {
builder.append(' ');
}
if ((l != 1) && ((l - 1) % 16 == 0)) {
builder.append('\n');
}
l++;
appendFromByte(bytes[i], builder);
if (i != offset + length - 1) {
builder.append(' ');
}
}
return builder.toString();
}
/**
* Converts the given hex string to a byte array.
*
* @param hexString the hex string
* @return the bytes
* @throws NumberFormatException if the string is not a valid hex string
*/
public static byte[] toBytes(String hexString) {
Objects.requireNonNull(hexString);
if ((hexString.length() == 0) || ((hexString.length() % 2) != 0)) {
throw new NumberFormatException("argument is not a valid hex string");
}
int length = hexString.length();
byte[] data = new byte[length / 2];
for (int i = 0; i < length; i += 2) {
int firstCharacter = Character.digit(hexString.charAt(i), 16);
int secondCharacter = Character.digit(hexString.charAt(i + 1), 16);
if (firstCharacter == -1 || secondCharacter == -1) {
throw new NumberFormatException("argument is not a valid hex string");
}
data[i / 2] = (byte) ((firstCharacter << 4) + secondCharacter);
}
return data;
}
public static void appendFromByte(byte b, StringBuilder builder) {
builder.append(fromByte(b));
}
public static void appendFromBytes(StringBuilder builder, byte[] bytes, int offset, int length) {
builder.append(fromBytes(bytes, offset, length));
}
}

@ -0,0 +1,41 @@
/*
* Copyright 2018 beanit
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.internal;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
public class NamedThreadFactory implements ThreadFactory {
private final AtomicInteger threadCounter = new AtomicInteger(1);
private final String namePrefix;
/**
* Creates a thread factory with the given pool name as a name prefix. Threads created will have
* the name {@code <poolName>-thread-<thread-counter>}. A common pool name is of format {@code
* <pool-name>-<pool-id>}.
*
* @param poolName the thread pool name
*/
public NamedThreadFactory(String poolName) {
this.namePrefix = poolName + "-thread-";
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName(namePrefix + threadCounter.getAndIncrement());
return thread;
}
}

@ -0,0 +1,33 @@
/*
* Copyright 2018 beanit
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.internal.cli;
public class Action {
private final String key;
private final String description;
public Action(String key, String description) {
this.key = key;
this.description = description;
}
public String getKey() {
return key;
}
public String getDescription() {
return description;
}
}

@ -0,0 +1,35 @@
/*
* Copyright 2018 beanit
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.internal.cli;
public final class ActionException extends Exception {
private static final long serialVersionUID = 4806947065917148946L;
public ActionException() {
super();
}
public ActionException(String s) {
super(s);
}
public ActionException(Throwable cause) {
super(cause);
}
public ActionException(String s, Throwable cause) {
super(s, cause);
}
}

@ -0,0 +1,21 @@
/*
* Copyright 2018 beanit
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.internal.cli;
public interface ActionListener {
void actionCalled(String actionKey) throws ActionException;
void quit();
}

@ -0,0 +1,131 @@
/*
* Copyright 2018 beanit
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.internal.cli;
import static java.lang.System.exit;
import static java.lang.System.out;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedHashMap;
import java.util.Map;
public class ActionProcessor {
private static final String SEPARATOR_LINE =
"------------------------------------------------------";
private final BufferedReader reader;
private final ActionListener actionListener;
private final Map<String, Action> actionMap = new LinkedHashMap<>();
private final Action helpAction = new Action("h", "print help message");
private final Action quitAction = new Action("q", "quit the application");
private volatile boolean closed = false;
public ActionProcessor(ActionListener actionListener) {
reader = new BufferedReader(new InputStreamReader(System.in, UTF_8));
this.actionListener = actionListener;
}
public void addAction(Action action) {
actionMap.put(action.getKey(), action);
}
public BufferedReader getReader() {
return reader;
}
public void start() {
actionMap.put(helpAction.getKey(), helpAction);
actionMap.put(quitAction.getKey(), quitAction);
printHelp();
try {
String actionKey;
while (true) {
if (closed) {
exit(1);
return;
}
System.out.println("\n** Enter action key: ");
try {
actionKey = reader.readLine();
} catch (IOException e) {
System.err.printf("%s. Application is being shut down.\n", e.getMessage());
exit(2);
return;
}
if (closed) {
exit(1);
return;
}
if (actionMap.get(actionKey) == null) {
System.err.println("Illegal action key.\n");
printHelp();
continue;
}
if (actionKey.equals(helpAction.getKey())) {
printHelp();
continue;
}
if (actionKey.equals(quitAction.getKey())) {
actionListener.quit();
return;
}
actionListener.actionCalled(actionKey);
}
} catch (Exception e) {
e.printStackTrace();
actionListener.quit();
} finally {
close();
}
}
private void printHelp() {
final String message = " %s - %s\n";
out.flush();
out.println();
out.println(SEPARATOR_LINE);
for (Action action : actionMap.values()) {
out.printf(message, action.getKey(), action.getDescription());
}
out.println(SEPARATOR_LINE);
}
public void close() {
closed = true;
try {
reader.close();
} catch (IOException ignored) {
// if closing fails there is nothing meaningful that can be done
}
}
}

@ -0,0 +1,50 @@
/*
* Copyright 2018 beanit
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.internal.cli;
public abstract class CliParameter {
final String name;
final String description;
final boolean optional;
boolean selected;
CliParameter(CliParameterBuilder builder) {
name = builder.name;
description = builder.description;
optional = builder.optional;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public boolean isOptional() {
return optional;
}
public boolean isSelected() {
return selected;
}
abstract int parse(String[] args, int i) throws CliParseException;
abstract int appendSynopsis(StringBuilder sb);
abstract void appendDescription(StringBuilder sb);
}

@ -0,0 +1,74 @@
/*
* Copyright 2018 beanit
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.beanit.iec61850bean.internal.cli;
import java.util.List;
public class CliParameterBuilder {
final String name;
String description;
boolean optional = true;
public CliParameterBuilder(String name) {
this.name = name;
}
public CliParameterBuilder setDescription(String description) {
this.description = description;
return this;
}
public CliParameterBuilder setMandatory() {
optional = false;
return this;
}
public LongCliParameter buildLongParameter(String parameterName, long defaultValue) {
return new LongCliParameter(this, parameterName, defaultValue);
}
public LongCliParameter buildLongParameter(String parameterName) {
return new LongCliParameter(this, parameterName);
}
public IntCliParameter buildIntParameter(String parameterName, int defaultValue) {
return new IntCliParameter(this, parameterName, defaultValue);
}
public IntCliParameter buildIntParameter(String parameterName) {
return new IntCliParameter(this, parameterName);
}
public StringCliParameter buildStringParameter(String parameterName, String defaultValue) {
return new StringCliParameter(this, parameterName, defaultValue);
}
public StringCliParameter buildStringParameter(String parameterName) {
return new StringCliParameter(this, parameterName);
}
public StringListCliParameter buildStringListParameter(String parameterName) {
return new StringListCliParameter(this, parameterName);
}
public StringListCliParameter buildStringListParameter(
String parameterName, List<String> defaultValue) {
return new StringListCliParameter(this, parameterName, defaultValue);
}
public FlagCliParameter buildFlagParameter() {
return new FlagCliParameter(this);
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save