diff --git a/asn1/mms/mms.asn b/asn1/mms/mms.asn index 3440db3..b9ce8ba 100644 --- a/asn1/mms/mms.asn +++ b/asn1/mms/mms.asn @@ -30,9 +30,10 @@ ConfirmedServiceRequest ::= CHOICE { defineNamedVariableList [11] IMPLICIT DefineNamedVariableList-Request, getNamedVariableListAttributes [12] GetNamedVariableListAttributes-Request, deleteNamedVariableList [13] IMPLICIT DeleteNamedVariableList-Request, --- fileOpen [72] IMPLICIT FileOpen-Request, --- fileRead [73] IMPLICIT FileRead-Request, --- fileClose [74] IMPLICIT FileClose-Request, + fileOpen [72] IMPLICIT FileOpen-Request, + fileRead [73] IMPLICIT FileRead-Request, + fileClose [74] IMPLICIT FileClose-Request, + fileDelete [76] IMPLICIT FileDelete-Request, fileDirectory [77] IMPLICIT FileDirectory-Request } @@ -57,9 +58,10 @@ ConfirmedServiceResponse ::= CHOICE { defineNamedVariableList [11] IMPLICIT DefineNamedVariableList-Response, getNamedVariableListAttributes [12] IMPLICIT GetNamedVariableListAttributes-Response, deleteNamedVariableList [13] IMPLICIT DeleteNamedVariableList-Response, --- fileOpen [72] IMPLICIT FileOpen-Response, --- fileRead [73] IMPLICIT FileRead-Response, --- fileClose [74] IMPLICIT FileClose-Response, + fileOpen [72] IMPLICIT FileOpen-Response, + fileRead [73] IMPLICIT FileRead-Response, + fileClose [74] IMPLICIT FileClose-Response, + fileDelete [76] IMPLICIT FileDelete-Response, fileDirectory [77] IMPLICIT FileDirectory-Response } @@ -589,6 +591,31 @@ DeleteNamedVariableList-Response ::= SEQUENCE { numberDeleted [1] IMPLICIT Unsigned32 } +FileOpen-Request ::= SEQUENCE { + fileName [0] IMPLICIT FileName, + initialPosition [1] IMPLICIT Unsigned32 +} + +FileOpen-Response ::= SEQUENCE { + frsmID [0] IMPLICIT Integer32, + fileAttributes [1] IMPLICIT FileAttributes +} + +FileRead-Request ::= Integer32 -- FRSM ID + +FileRead-Response ::= SEQUENCE { + fileData [0] IMPLICIT OCTET STRING, + moreFollows [1] IMPLICIT BOOLEAN DEFAULT TRUE +} + +FileClose-Request ::= Integer32 -- FRSM ID + +FileClose-Response ::= NULL + +FileDelete-Request ::= FileName + +FileDelete-Response ::= NULL + FileDirectory-Request ::= SEQUENCE { fileSpecification [0] IMPLICIT FileName OPTIONAL, continueAfter [1] IMPLICIT FileName OPTIONAL diff --git a/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/ConfirmedServiceRequest.java b/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/ConfirmedServiceRequest.java index afd3617..d227dc8 100644 --- a/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/ConfirmedServiceRequest.java +++ b/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/ConfirmedServiceRequest.java @@ -31,6 +31,10 @@ public class ConfirmedServiceRequest implements Serializable { private DefineNamedVariableListRequest defineNamedVariableList = null; private GetNamedVariableListAttributesRequest getNamedVariableListAttributes = null; private DeleteNamedVariableListRequest deleteNamedVariableList = null; + private FileOpenRequest fileOpen = null; + private FileReadRequest fileRead = null; + private FileCloseRequest fileClose = null; + private FileDeleteRequest fileDelete = null; private FileDirectoryRequest fileDirectory = null; public ConfirmedServiceRequest() { @@ -96,6 +100,38 @@ public class ConfirmedServiceRequest implements Serializable { return deleteNamedVariableList; } + public void setFileOpen(FileOpenRequest fileOpen) { + this.fileOpen = fileOpen; + } + + public FileOpenRequest getFileOpen() { + return fileOpen; + } + + public void setFileRead(FileReadRequest fileRead) { + this.fileRead = fileRead; + } + + public FileReadRequest getFileRead() { + return fileRead; + } + + public void setFileClose(FileCloseRequest fileClose) { + this.fileClose = fileClose; + } + + public FileCloseRequest getFileClose() { + return fileClose; + } + + public void setFileDelete(FileDeleteRequest fileDelete) { + this.fileDelete = fileDelete; + } + + public FileDeleteRequest getFileDelete() { + return fileDelete; + } + public void setFileDirectory(FileDirectoryRequest fileDirectory) { this.fileDirectory = fileDirectory; } @@ -125,6 +161,42 @@ public class ConfirmedServiceRequest implements Serializable { return codeLength; } + if (fileDelete != null) { + codeLength += fileDelete.encode(os, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 76 + os.write(0x4C); + os.write(0xBF); + codeLength += 2; + return codeLength; + } + + if (fileClose != null) { + codeLength += fileClose.encode(os, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 74 + os.write(0x4A); + os.write(0x9F); + codeLength += 2; + return codeLength; + } + + if (fileRead != null) { + codeLength += fileRead.encode(os, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 73 + os.write(0x49); + os.write(0x9F); + codeLength += 2; + return codeLength; + } + + if (fileOpen != null) { + codeLength += fileOpen.encode(os, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 72 + os.write(0x48); + os.write(0xBF); + codeLength += 2; + return codeLength; + } + if (deleteNamedVariableList != null) { codeLength += deleteNamedVariableList.encode(os, false); // write tag: CONTEXT_CLASS, CONSTRUCTED, 13 @@ -246,6 +318,30 @@ public class ConfirmedServiceRequest implements Serializable { return codeLength; } + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 72)) { + fileOpen = new FileOpenRequest(); + codeLength += fileOpen.decode(is, false); + return codeLength; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 73)) { + fileRead = new FileReadRequest(); + codeLength += fileRead.decode(is, false); + return codeLength; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 74)) { + fileClose = new FileCloseRequest(); + codeLength += fileClose.decode(is, false); + return codeLength; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 76)) { + fileDelete = new FileDeleteRequest(); + codeLength += fileDelete.decode(is, false); + return codeLength; + } + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 77)) { fileDirectory = new FileDirectoryRequest(); codeLength += fileDirectory.decode(is, false); @@ -315,6 +411,28 @@ public class ConfirmedServiceRequest implements Serializable { return; } + if (fileOpen != null) { + sb.append("fileOpen: "); + fileOpen.appendAsString(sb, indentLevel + 1); + return; + } + + if (fileRead != null) { + sb.append("fileRead: ").append(fileRead); + return; + } + + if (fileClose != null) { + sb.append("fileClose: ").append(fileClose); + return; + } + + if (fileDelete != null) { + sb.append("fileDelete: "); + fileDelete.appendAsString(sb, indentLevel + 1); + return; + } + if (fileDirectory != null) { sb.append("fileDirectory: "); fileDirectory.appendAsString(sb, indentLevel + 1); diff --git a/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/ConfirmedServiceResponse.java b/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/ConfirmedServiceResponse.java index 4293ae4..7528609 100644 --- a/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/ConfirmedServiceResponse.java +++ b/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/ConfirmedServiceResponse.java @@ -31,6 +31,10 @@ public class ConfirmedServiceResponse implements Serializable { private DefineNamedVariableListResponse defineNamedVariableList = null; private GetNamedVariableListAttributesResponse getNamedVariableListAttributes = null; private DeleteNamedVariableListResponse deleteNamedVariableList = null; + private FileOpenResponse fileOpen = null; + private FileReadResponse fileRead = null; + private FileCloseResponse fileClose = null; + private FileDeleteResponse fileDelete = null; private FileDirectoryResponse fileDirectory = null; public ConfirmedServiceResponse() { @@ -96,6 +100,38 @@ public class ConfirmedServiceResponse implements Serializable { return deleteNamedVariableList; } + public void setFileOpen(FileOpenResponse fileOpen) { + this.fileOpen = fileOpen; + } + + public FileOpenResponse getFileOpen() { + return fileOpen; + } + + public void setFileRead(FileReadResponse fileRead) { + this.fileRead = fileRead; + } + + public FileReadResponse getFileRead() { + return fileRead; + } + + public void setFileClose(FileCloseResponse fileClose) { + this.fileClose = fileClose; + } + + public FileCloseResponse getFileClose() { + return fileClose; + } + + public void setFileDelete(FileDeleteResponse fileDelete) { + this.fileDelete = fileDelete; + } + + public FileDeleteResponse getFileDelete() { + return fileDelete; + } + public void setFileDirectory(FileDirectoryResponse fileDirectory) { this.fileDirectory = fileDirectory; } @@ -123,6 +159,42 @@ public class ConfirmedServiceResponse implements Serializable { return codeLength; } + if (fileDelete != null) { + codeLength += fileDelete.encode(os, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 76 + os.write(0x4C); + os.write(0x9F); + codeLength += 2; + return codeLength; + } + + if (fileClose != null) { + codeLength += fileClose.encode(os, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 74 + os.write(0x4A); + os.write(0x9F); + codeLength += 2; + return codeLength; + } + + if (fileRead != null) { + codeLength += fileRead.encode(os, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 73 + os.write(0x49); + os.write(0xBF); + codeLength += 2; + return codeLength; + } + + if (fileOpen != null) { + codeLength += fileOpen.encode(os, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 72 + os.write(0x48); + os.write(0xBF); + codeLength += 2; + return codeLength; + } + if (deleteNamedVariableList != null) { codeLength += deleteNamedVariableList.encode(os, false); // write tag: CONTEXT_CLASS, CONSTRUCTED, 13 @@ -238,6 +310,30 @@ public class ConfirmedServiceResponse implements Serializable { return codeLength; } + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 72)) { + fileOpen = new FileOpenResponse(); + codeLength += fileOpen.decode(is, false); + return codeLength; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 73)) { + fileRead = new FileReadResponse(); + codeLength += fileRead.decode(is, false); + return codeLength; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 74)) { + fileClose = new FileCloseResponse(); + codeLength += fileClose.decode(is, false); + return codeLength; + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 76)) { + fileDelete = new FileDeleteResponse(); + codeLength += fileDelete.decode(is, false); + return codeLength; + } + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 77)) { fileDirectory = new FileDirectoryResponse(); codeLength += fileDirectory.decode(is, false); @@ -306,6 +402,28 @@ public class ConfirmedServiceResponse implements Serializable { return; } + if (fileOpen != null) { + sb.append("fileOpen: "); + fileOpen.appendAsString(sb, indentLevel + 1); + return; + } + + if (fileRead != null) { + sb.append("fileRead: "); + fileRead.appendAsString(sb, indentLevel + 1); + return; + } + + if (fileClose != null) { + sb.append("fileClose: ").append(fileClose); + return; + } + + if (fileDelete != null) { + sb.append("fileDelete: ").append(fileDelete); + return; + } + if (fileDirectory != null) { sb.append("fileDirectory: "); fileDirectory.appendAsString(sb, indentLevel + 1); diff --git a/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/FileCloseRequest.java b/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/FileCloseRequest.java new file mode 100644 index 0000000..a63ffee --- /dev/null +++ b/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/FileCloseRequest.java @@ -0,0 +1,41 @@ +/** + * This class file was automatically generated by jASN1 v1.9.1-SNAPSHOT (http://www.openmuc.org) + */ + +package org.openmuc.openiec61850.internal.mms.asn1; + +import java.io.IOException; +import java.io.EOFException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.io.Serializable; +import org.openmuc.jasn1.ber.*; +import org.openmuc.jasn1.ber.types.*; +import org.openmuc.jasn1.ber.types.string.*; + + +public class FileCloseRequest extends Integer32 { + + private static final long serialVersionUID = 1L; + + public FileCloseRequest() { + } + + public FileCloseRequest(byte[] code) { + super(code); + } + + public FileCloseRequest(BigInteger value) { + super(value); + } + + public FileCloseRequest(long value) { + super(value); + } + +} diff --git a/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/FileCloseResponse.java b/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/FileCloseResponse.java new file mode 100644 index 0000000..2b82165 --- /dev/null +++ b/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/FileCloseResponse.java @@ -0,0 +1,33 @@ +/** + * This class file was automatically generated by jASN1 v1.9.1-SNAPSHOT (http://www.openmuc.org) + */ + +package org.openmuc.openiec61850.internal.mms.asn1; + +import java.io.IOException; +import java.io.EOFException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.io.Serializable; +import org.openmuc.jasn1.ber.*; +import org.openmuc.jasn1.ber.types.*; +import org.openmuc.jasn1.ber.types.string.*; + + +public class FileCloseResponse extends BerNull { + + private static final long serialVersionUID = 1L; + + public FileCloseResponse() { + } + + public FileCloseResponse(byte[] code) { + super(code); + } + +} diff --git a/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/FileDeleteRequest.java b/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/FileDeleteRequest.java new file mode 100644 index 0000000..7a06204 --- /dev/null +++ b/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/FileDeleteRequest.java @@ -0,0 +1,33 @@ +/** + * This class file was automatically generated by jASN1 v1.9.1-SNAPSHOT (http://www.openmuc.org) + */ + +package org.openmuc.openiec61850.internal.mms.asn1; + +import java.io.IOException; +import java.io.EOFException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.io.Serializable; +import org.openmuc.jasn1.ber.*; +import org.openmuc.jasn1.ber.types.*; +import org.openmuc.jasn1.ber.types.string.*; + + +public class FileDeleteRequest extends FileName { + + private static final long serialVersionUID = 1L; + + public FileDeleteRequest() { + } + + public FileDeleteRequest(byte[] code) { + super(code); + } + +} diff --git a/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/FileDeleteResponse.java b/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/FileDeleteResponse.java new file mode 100644 index 0000000..d1e13fd --- /dev/null +++ b/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/FileDeleteResponse.java @@ -0,0 +1,33 @@ +/** + * This class file was automatically generated by jASN1 v1.9.1-SNAPSHOT (http://www.openmuc.org) + */ + +package org.openmuc.openiec61850.internal.mms.asn1; + +import java.io.IOException; +import java.io.EOFException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.io.Serializable; +import org.openmuc.jasn1.ber.*; +import org.openmuc.jasn1.ber.types.*; +import org.openmuc.jasn1.ber.types.string.*; + + +public class FileDeleteResponse extends BerNull { + + private static final long serialVersionUID = 1L; + + public FileDeleteResponse() { + } + + public FileDeleteResponse(byte[] code) { + super(code); + } + +} diff --git a/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/FileOpenRequest.java b/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/FileOpenRequest.java new file mode 100644 index 0000000..36e52d2 --- /dev/null +++ b/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/FileOpenRequest.java @@ -0,0 +1,179 @@ +/** + * This class file was automatically generated by jASN1 v1.9.1-SNAPSHOT (http://www.openmuc.org) + */ + +package org.openmuc.openiec61850.internal.mms.asn1; + +import java.io.IOException; +import java.io.EOFException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.io.Serializable; +import org.openmuc.jasn1.ber.*; +import org.openmuc.jasn1.ber.types.*; +import org.openmuc.jasn1.ber.types.string.*; + + +public class FileOpenRequest implements Serializable { + + private static final long serialVersionUID = 1L; + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + + public byte[] code = null; + private FileName fileName = null; + private Unsigned32 initialPosition = null; + + public FileOpenRequest() { + } + + public FileOpenRequest(byte[] code) { + this.code = code; + } + + public void setFileName(FileName fileName) { + this.fileName = fileName; + } + + public FileName getFileName() { + return fileName; + } + + public void setInitialPosition(Unsigned32 initialPosition) { + this.initialPosition = initialPosition; + } + + public Unsigned32 getInitialPosition() { + return initialPosition; + } + + public int encode(OutputStream os) throws IOException { + return encode(os, true); + } + + public int encode(OutputStream os, boolean withTag) throws IOException { + + if (code != null) { + for (int i = code.length - 1; i >= 0; i--) { + os.write(code[i]); + } + if (withTag) { + return tag.encode(os) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += initialPosition.encode(os, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + os.write(0x81); + codeLength += 1; + + codeLength += fileName.encode(os, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 0 + os.write(0xA0); + codeLength += 1; + + codeLength += BerLength.encodeLength(os, codeLength); + + if (withTag) { + codeLength += tag.encode(os); + } + + return codeLength; + + } + + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int codeLength = 0; + int subCodeLength = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + codeLength += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + codeLength += length.decode(is); + + int totalLength = length.val; + codeLength += totalLength; + + subCodeLength += berTag.decode(is); + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 0)) { + fileName = new FileName(); + subCodeLength += fileName.decode(is, false); + subCodeLength += berTag.decode(is); + } + else { + throw new IOException("Tag does not match the mandatory sequence element tag."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + initialPosition = new Unsigned32(); + subCodeLength += initialPosition.decode(is, false); + if (subCodeLength == totalLength) { + return codeLength; + } + } + throw new IOException("Unexpected end of sequence, length tag: " + totalLength + ", actual sequence length: " + subCodeLength); + + + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream os = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(os, false); + code = os.getArray(); + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (fileName != null) { + sb.append("fileName: "); + fileName.appendAsString(sb, indentLevel + 1); + } + else { + sb.append("fileName: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (initialPosition != null) { + sb.append("initialPosition: ").append(initialPosition); + } + else { + sb.append("initialPosition: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + +} + diff --git a/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/FileOpenResponse.java b/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/FileOpenResponse.java new file mode 100644 index 0000000..607b3ad --- /dev/null +++ b/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/FileOpenResponse.java @@ -0,0 +1,179 @@ +/** + * This class file was automatically generated by jASN1 v1.9.1-SNAPSHOT (http://www.openmuc.org) + */ + +package org.openmuc.openiec61850.internal.mms.asn1; + +import java.io.IOException; +import java.io.EOFException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.io.Serializable; +import org.openmuc.jasn1.ber.*; +import org.openmuc.jasn1.ber.types.*; +import org.openmuc.jasn1.ber.types.string.*; + + +public class FileOpenResponse implements Serializable { + + private static final long serialVersionUID = 1L; + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + + public byte[] code = null; + private Integer32 frsmID = null; + private FileAttributes fileAttributes = null; + + public FileOpenResponse() { + } + + public FileOpenResponse(byte[] code) { + this.code = code; + } + + public void setFrsmID(Integer32 frsmID) { + this.frsmID = frsmID; + } + + public Integer32 getFrsmID() { + return frsmID; + } + + public void setFileAttributes(FileAttributes fileAttributes) { + this.fileAttributes = fileAttributes; + } + + public FileAttributes getFileAttributes() { + return fileAttributes; + } + + public int encode(OutputStream os) throws IOException { + return encode(os, true); + } + + public int encode(OutputStream os, boolean withTag) throws IOException { + + if (code != null) { + for (int i = code.length - 1; i >= 0; i--) { + os.write(code[i]); + } + if (withTag) { + return tag.encode(os) + code.length; + } + return code.length; + } + + int codeLength = 0; + codeLength += fileAttributes.encode(os, false); + // write tag: CONTEXT_CLASS, CONSTRUCTED, 1 + os.write(0xA1); + codeLength += 1; + + codeLength += frsmID.encode(os, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + os.write(0x80); + codeLength += 1; + + codeLength += BerLength.encodeLength(os, codeLength); + + if (withTag) { + codeLength += tag.encode(os); + } + + return codeLength; + + } + + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int codeLength = 0; + int subCodeLength = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + codeLength += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + codeLength += length.decode(is); + + int totalLength = length.val; + codeLength += totalLength; + + subCodeLength += berTag.decode(is); + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + frsmID = new Integer32(); + subCodeLength += frsmID.decode(is, false); + subCodeLength += berTag.decode(is); + } + else { + throw new IOException("Tag does not match the mandatory sequence element tag."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.CONSTRUCTED, 1)) { + fileAttributes = new FileAttributes(); + subCodeLength += fileAttributes.decode(is, false); + if (subCodeLength == totalLength) { + return codeLength; + } + } + throw new IOException("Unexpected end of sequence, length tag: " + totalLength + ", actual sequence length: " + subCodeLength); + + + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream os = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(os, false); + code = os.getArray(); + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (frsmID != null) { + sb.append("frsmID: ").append(frsmID); + } + else { + sb.append("frsmID: "); + } + + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (fileAttributes != null) { + sb.append("fileAttributes: "); + fileAttributes.appendAsString(sb, indentLevel + 1); + } + else { + sb.append("fileAttributes: "); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + +} + diff --git a/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/FileReadRequest.java b/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/FileReadRequest.java new file mode 100644 index 0000000..fad8b73 --- /dev/null +++ b/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/FileReadRequest.java @@ -0,0 +1,41 @@ +/** + * This class file was automatically generated by jASN1 v1.9.1-SNAPSHOT (http://www.openmuc.org) + */ + +package org.openmuc.openiec61850.internal.mms.asn1; + +import java.io.IOException; +import java.io.EOFException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.io.Serializable; +import org.openmuc.jasn1.ber.*; +import org.openmuc.jasn1.ber.types.*; +import org.openmuc.jasn1.ber.types.string.*; + + +public class FileReadRequest extends Integer32 { + + private static final long serialVersionUID = 1L; + + public FileReadRequest() { + } + + public FileReadRequest(byte[] code) { + super(code); + } + + public FileReadRequest(BigInteger value) { + super(value); + } + + public FileReadRequest(long value) { + super(value); + } + +} diff --git a/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/FileReadResponse.java b/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/FileReadResponse.java new file mode 100644 index 0000000..80e284a --- /dev/null +++ b/src/main/java-gen/org/openmuc/openiec61850/internal/mms/asn1/FileReadResponse.java @@ -0,0 +1,180 @@ +/** + * This class file was automatically generated by jASN1 v1.9.1-SNAPSHOT (http://www.openmuc.org) + */ + +package org.openmuc.openiec61850.internal.mms.asn1; + +import java.io.IOException; +import java.io.EOFException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.io.Serializable; +import org.openmuc.jasn1.ber.*; +import org.openmuc.jasn1.ber.types.*; +import org.openmuc.jasn1.ber.types.string.*; + + +public class FileReadResponse implements Serializable { + + private static final long serialVersionUID = 1L; + + public static final BerTag tag = new BerTag(BerTag.UNIVERSAL_CLASS, BerTag.CONSTRUCTED, 16); + + public byte[] code = null; + private BerOctetString fileData = null; + private BerBoolean moreFollows = null; + + public FileReadResponse() { + } + + public FileReadResponse(byte[] code) { + this.code = code; + } + + public void setFileData(BerOctetString fileData) { + this.fileData = fileData; + } + + public BerOctetString getFileData() { + return fileData; + } + + public void setMoreFollows(BerBoolean moreFollows) { + this.moreFollows = moreFollows; + } + + public BerBoolean getMoreFollows() { + return moreFollows; + } + + public int encode(OutputStream os) throws IOException { + return encode(os, true); + } + + public int encode(OutputStream os, boolean withTag) throws IOException { + + if (code != null) { + for (int i = code.length - 1; i >= 0; i--) { + os.write(code[i]); + } + if (withTag) { + return tag.encode(os) + code.length; + } + return code.length; + } + + int codeLength = 0; + if (moreFollows != null) { + codeLength += moreFollows.encode(os, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 1 + os.write(0x81); + codeLength += 1; + } + + codeLength += fileData.encode(os, false); + // write tag: CONTEXT_CLASS, PRIMITIVE, 0 + os.write(0x80); + codeLength += 1; + + codeLength += BerLength.encodeLength(os, codeLength); + + if (withTag) { + codeLength += tag.encode(os); + } + + return codeLength; + + } + + public int decode(InputStream is) throws IOException { + return decode(is, true); + } + + public int decode(InputStream is, boolean withTag) throws IOException { + int codeLength = 0; + int subCodeLength = 0; + BerTag berTag = new BerTag(); + + if (withTag) { + codeLength += tag.decodeAndCheck(is); + } + + BerLength length = new BerLength(); + codeLength += length.decode(is); + + int totalLength = length.val; + codeLength += totalLength; + + subCodeLength += berTag.decode(is); + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 0)) { + fileData = new BerOctetString(); + subCodeLength += fileData.decode(is, false); + if (subCodeLength == totalLength) { + return codeLength; + } + subCodeLength += berTag.decode(is); + } + else { + throw new IOException("Tag does not match the mandatory sequence element tag."); + } + + if (berTag.equals(BerTag.CONTEXT_CLASS, BerTag.PRIMITIVE, 1)) { + moreFollows = new BerBoolean(); + subCodeLength += moreFollows.decode(is, false); + if (subCodeLength == totalLength) { + return codeLength; + } + } + throw new IOException("Unexpected end of sequence, length tag: " + totalLength + ", actual sequence length: " + subCodeLength); + + + } + + public void encodeAndSave(int encodingSizeGuess) throws IOException { + ReverseByteArrayOutputStream os = new ReverseByteArrayOutputStream(encodingSizeGuess); + encode(os, false); + code = os.getArray(); + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + appendAsString(sb, 0); + return sb.toString(); + } + + public void appendAsString(StringBuilder sb, int indentLevel) { + + sb.append("{"); + sb.append("\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + if (fileData != null) { + sb.append("fileData: ").append(fileData); + } + else { + sb.append("fileData: "); + } + + if (moreFollows != null) { + sb.append(",\n"); + for (int i = 0; i < indentLevel + 1; i++) { + sb.append("\t"); + } + sb.append("moreFollows: ").append(moreFollows); + } + + sb.append("\n"); + for (int i = 0; i < indentLevel; i++) { + sb.append("\t"); + } + sb.append("}"); + } + +} + diff --git a/src/main/java/org/openmuc/openiec61850/ClientAssociation.java b/src/main/java/org/openmuc/openiec61850/ClientAssociation.java index ee6f16c..52b1ad5 100644 --- a/src/main/java/org/openmuc/openiec61850/ClientAssociation.java +++ b/src/main/java/org/openmuc/openiec61850/ClientAssociation.java @@ -21,7 +21,9 @@ import java.io.IOException; import java.net.InetAddress; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import java.text.ParseException; import java.util.ArrayList; +import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.Iterator; @@ -52,8 +54,14 @@ import org.openmuc.openiec61850.internal.mms.asn1.DefineNamedVariableListRequest import org.openmuc.openiec61850.internal.mms.asn1.DeleteNamedVariableListRequest; import org.openmuc.openiec61850.internal.mms.asn1.DeleteNamedVariableListRequest.ListOfVariableListName; import org.openmuc.openiec61850.internal.mms.asn1.DeleteNamedVariableListResponse; +import org.openmuc.openiec61850.internal.mms.asn1.DirectoryEntry; +import org.openmuc.openiec61850.internal.mms.asn1.FileCloseRequest; +import org.openmuc.openiec61850.internal.mms.asn1.FileDeleteRequest; import org.openmuc.openiec61850.internal.mms.asn1.FileDirectoryRequest; +import org.openmuc.openiec61850.internal.mms.asn1.FileDirectoryResponse; import org.openmuc.openiec61850.internal.mms.asn1.FileName; +import org.openmuc.openiec61850.internal.mms.asn1.FileOpenRequest; +import org.openmuc.openiec61850.internal.mms.asn1.FileReadRequest; import org.openmuc.openiec61850.internal.mms.asn1.GetNameListRequest; import org.openmuc.openiec61850.internal.mms.asn1.GetNameListRequest.ObjectScope; import org.openmuc.openiec61850.internal.mms.asn1.GetNameListResponse; @@ -398,6 +406,7 @@ public final class ClientAssociation { } ErrorClass errClass = mmsResponsePdu.getConfirmedErrorPDU().getServiceError().getErrorClass(); + if (errClass != null) { if (errClass.getAccess() != null) { if (errClass.getAccess().value.intValue() == 3) { @@ -409,6 +418,14 @@ public final class ClientAssociation { throw new ServiceError(ServiceError.INSTANCE_NOT_AVAILABLE, "MMS confirmed error: class: \"access\", error code: \"object-non-existent\""); } + + } + else if (errClass.getFile() != null) { + if (errClass.getFile().value.intValue() == 7) { + + throw new ServiceError(ServiceError.FILE_NONE_EXISTENT, + "MMS confirmed error: class: \"file\", error code: \"file-non-existent\""); + } } } @@ -905,27 +922,229 @@ public final class ClientAssociation { decodeGetDataValuesResponse(confirmedServiceResponse, modelNode); } - public void getFileDirectory(String directoryName) throws ServiceError, IOException { + private boolean decodeGetFileDirectoryResponse(ConfirmedServiceResponse confirmedServiceResponse, List files) + throws ServiceError + { + if (confirmedServiceResponse.getFileDirectory() == null) { + throw new ServiceError(ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "Error decoding GetFileDirectoryResponsePdu"); + } + + FileDirectoryResponse fileDirectoryRes = confirmedServiceResponse.getFileDirectory(); + + List entries = fileDirectoryRes.getListOfDirectoryEntry().getDirectoryEntry(); - System.out.println("getFileDirectory"); + for (DirectoryEntry entry : entries) { + List graphicStrings = entry.getFileName().getBerGraphicString(); + + StringBuilder filename = new StringBuilder(); + + for (BerGraphicString bgs : graphicStrings) { + filename.append(bgs.toString()); + } + + long fileSize = entry.getFileAttributes().getSizeOfFile().longValue(); + + Calendar lastModified; + + try { + lastModified = entry.getFileAttributes().getLastModified().asCalendar(); + + } catch (ParseException e) { + throw new ServiceError(ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "Error decoding GetFileDirectoryResponsePdu"); + } + + + FileInformation fileInfo = new FileInformation(filename.toString(), fileSize, lastModified); + + files.add(fileInfo); + } - FileDirectoryRequest fileDirectoryRequest = new FileDirectoryRequest(); + boolean moreFollows = (fileDirectoryRes.getMoreFollows() == null) ? false : fileDirectoryRes.getMoreFollows().value; - BerGraphicString berGraphicString = new BerGraphicString(directoryName.getBytes()); + return moreFollows; + } - FileName fileSpecifcation = new FileName(); - fileSpecifcation.getBerGraphicString().add(berGraphicString); + + /** + * Read the file directory of the server + * + * @param directoryName name of a directory or empty string for the root directory + * + * @return the list of available + * + * @throws ServiceError + * if a ServiceError is returned by the server or parsing of response failed. + * @throws IOException + * if a fatal association error occurs. The association object will be closed and can no longer be used + * after this exception is thrown. + */ + public List getFileDirectory(String directoryName) throws ServiceError, IOException + { + List files = new LinkedList(); - fileDirectoryRequest.setFileSpecification(fileSpecifcation); + boolean moreFollows = true; + + String continueAfter = null; + + while (moreFollows) { + + FileDirectoryRequest fileDirectoryRequest = new FileDirectoryRequest(); + + BerGraphicString berGraphicString = new BerGraphicString(directoryName.getBytes()); + + FileName fileSpecification = new FileName(); + fileSpecification.getBerGraphicString().add(berGraphicString); + + fileDirectoryRequest.setFileSpecification(fileSpecification); + + if (continueAfter != null) { + FileName continueAfterSpecification = new FileName(); + + continueAfterSpecification.getBerGraphicString().add(new BerGraphicString(continueAfter.getBytes())); + + fileDirectoryRequest.setContinueAfter(continueAfterSpecification); + } + + ConfirmedServiceRequest confirmedServiceRequest = new ConfirmedServiceRequest(); + confirmedServiceRequest.setFileDirectory(fileDirectoryRequest); + + ConfirmedServiceResponse confirmedServiceResponse = encodeWriteReadDecode(confirmedServiceRequest); + + moreFollows = decodeGetFileDirectoryResponse(confirmedServiceResponse, files); + + if (moreFollows) + continueAfter = files.get(files.size() - 1).getFilename(); + } + + return files; + } + + /** + * Delete a file from the server + * + * @param filename name of the file to delete + * + * @throws ServiceError + * if a ServiceError is returned by the server + * @throws IOException + * if a fatal association error occurs. The association object will be closed and can no longer be used + * after this exception is thrown. + */ + public void deleteFile(String filename) throws ServiceError, IOException + { + FileDeleteRequest fileDeleteRequest = new FileDeleteRequest(); + + fileDeleteRequest.getBerGraphicString().add(new BerGraphicString(filename.getBytes())); ConfirmedServiceRequest confirmedServiceRequest = new ConfirmedServiceRequest(); - confirmedServiceRequest.setFileDirectory(fileDirectoryRequest); + confirmedServiceRequest.setFileDelete(fileDeleteRequest); - System.out.println("Create file directory request"); + ConfirmedServiceResponse confirmedServiceResponse = encodeWriteReadDecode(confirmedServiceRequest); + + if (confirmedServiceResponse.getFileDelete() == null) { + throw new ServiceError(ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "Error decoding DeleteFileResponsePdu"); + } + } + + private Integer32 openFile(String filename) throws ServiceError, IOException + { + FileOpenRequest fileOpenRequest = new FileOpenRequest(); + + FileName fileSpecification = new FileName(); + fileSpecification.getBerGraphicString().add(new BerGraphicString(filename.getBytes())); + + fileOpenRequest.setFileName(fileSpecification); + fileOpenRequest.setInitialPosition(new Unsigned32(0)); + + ConfirmedServiceRequest confirmedServiceRequest = new ConfirmedServiceRequest(); + confirmedServiceRequest.setFileOpen(fileOpenRequest); + + ConfirmedServiceResponse confirmedServiceResponse = encodeWriteReadDecode(confirmedServiceRequest); + + if (confirmedServiceResponse.getFileOpen() == null) { + throw new ServiceError(ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "Error decoding FileOpenResponsePdu"); + } + + Integer32 frsmId = confirmedServiceResponse.getFileOpen().getFrsmID(); + + return frsmId; + } + + private boolean readNextFileDataBlock(Integer32 frsmId, GetFileListener listener) throws ServiceError, IOException + { + FileReadRequest fileReadRequest = new FileReadRequest(frsmId.longValue()); + + ConfirmedServiceRequest confirmedServiceRequest = new ConfirmedServiceRequest(); + confirmedServiceRequest.setFileRead(fileReadRequest); + + ConfirmedServiceResponse confirmedServiceResponse = encodeWriteReadDecode(confirmedServiceRequest); + + if (confirmedServiceResponse.getFileRead() == null) { + throw new ServiceError(ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "Error decoding FileReadResponsePdu"); + } + + byte[] fileData = confirmedServiceResponse.getFileRead().getFileData().value; + + boolean moreFollows = true; + + if (confirmedServiceResponse.getFileRead().getMoreFollows() != null) + moreFollows = confirmedServiceResponse.getFileRead().getMoreFollows().value; + + if (listener != null) { + boolean continueRead = listener.dataReceived(fileData, moreFollows); + + if (moreFollows == true) + moreFollows = continueRead; + } + + return moreFollows; + } + + private void closeFile(Integer32 frsmId) throws ServiceError, IOException + { + FileCloseRequest fileCloseRequest = new FileCloseRequest(frsmId.longValue()); + + ConfirmedServiceRequest confirmedServiceRequest = new ConfirmedServiceRequest(); + confirmedServiceRequest.setFileClose(fileCloseRequest); ConfirmedServiceResponse confirmedServiceResponse = encodeWriteReadDecode(confirmedServiceRequest); + + if (confirmedServiceResponse.getFileClose() == null) { + throw new ServiceError(ServiceError.FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT, + "Error decoding FileCloseResponsePdu"); + } } + /** + * Read a file from the server + * + * @param filename name of the file to delete + * + * @param listener callback handler to receive fall data + * + * @throws ServiceError + * if a ServiceError is returned by the server + * @throws IOException + * if a fatal association error occurs. The association object will be closed and can no longer be used + * after this exception is thrown. + */ + public void getFile(String filename, GetFileListener listener) throws ServiceError, IOException + { + Integer32 frsmId = openFile(filename); + + boolean moreFollows = true; + + while (moreFollows) { + moreFollows = readNextFileDataBlock(frsmId, listener); + } + + closeFile(frsmId); + } /** * Will update all data inside the model except for control variables (those that have FC=CO). Control variables are diff --git a/src/main/java/org/openmuc/openiec61850/FileInformation.java b/src/main/java/org/openmuc/openiec61850/FileInformation.java new file mode 100644 index 0000000..4c9ff28 --- /dev/null +++ b/src/main/java/org/openmuc/openiec61850/FileInformation.java @@ -0,0 +1,39 @@ +package org.openmuc.openiec61850; + +import java.util.Calendar; + +/** + * @brief Contains file information received by the GetFileDirectory service + */ +public class FileInformation +{ + + private String filename; + + private long fileSize; + + private Calendar lastModified; + + public String getFilename() { + return filename; + } + + public long getFileSize() { + return fileSize; + } + + public Calendar getLastModified() { + return lastModified; + } + + public FileInformation(String filename, long fileSize, + Calendar lastModified) + { + super(); + this.filename = filename; + this.fileSize = fileSize; + this.lastModified = lastModified; + } + + +} diff --git a/src/main/java/org/openmuc/openiec61850/GetFileListener.java b/src/main/java/org/openmuc/openiec61850/GetFileListener.java new file mode 100644 index 0000000..500c23a --- /dev/null +++ b/src/main/java/org/openmuc/openiec61850/GetFileListener.java @@ -0,0 +1,17 @@ +package org.openmuc.openiec61850; + +/** + * 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); +} diff --git a/src/main/java/org/openmuc/openiec61850/ServiceError.java b/src/main/java/org/openmuc/openiec61850/ServiceError.java index 3238b0f..af00e11 100644 --- a/src/main/java/org/openmuc/openiec61850/ServiceError.java +++ b/src/main/java/org/openmuc/openiec61850/ServiceError.java @@ -35,6 +35,7 @@ public final class ServiceError extends Exception { 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; @@ -80,6 +81,8 @@ public final class ServiceError extends Exception { 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: