| | |
| | | /* |
| | | * Copyright 2011-17 Fraunhofer ISE, energy & meteo Systems GmbH and other contributors |
| | | * |
| | | * 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 org.openmuc.openiec61850; |
| | | |
| | | import java.util.Calendar; |
| | | import java.util.Date; |
| | | |
| | | import org.openmuc.jasn1.ber.types.BerNull; |
| | | import org.openmuc.openiec61850.internal.mms.asn1.Data; |
| | | import org.openmuc.openiec61850.internal.mms.asn1.TypeDescription; |
| | | import org.openmuc.openiec61850.internal.mms.asn1.UtcTime; |
| | | |
| | | public final class BdaTimestamp extends BasicDataAttribute { |
| | | |
| | | private 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. |
| | | * |
| | | * NOTE 2 The resolution of a time stamp may be 1/2**1 (= 0,5 s) if only the first bit is used; or may be 1/2**2 (= |
| | | * 0,25 s) if the first two bits are used; or may be approximately 60 ns if all 24 bits are used. The resolution |
| | | * provided by an IED is outside the scope of this standard. |
| | | * |
| | | * @return the fraction of seconds |
| | | */ |
| | | private int getFractionOfSecond() { |
| | | return ((0xff & value[4]) << 16 | (0xff & value[5]) << 8 | (0xff & value[6])); |
| | | } |
| | | |
| | | public void setDate(Date date) { |
| | | if (value == null) { |
| | | value = new byte[8]; |
| | | } |
| | | |
| | | int secondsSinceEpoch = (int) (date.getTime() / 1000L); |
| | | int fractionOfSecond = (int) ((date.getTime() % 1000L) / 1000.0 * (1 << 24)); |
| | | |
| | | // 0x8a = time accuracy of 10 and LeapSecondsKnown = true, ClockFailure |
| | | // = false, ClockNotSynchronized = false |
| | | value = new byte[] { (byte) ((secondsSinceEpoch >> 24) & 0xff), (byte) ((secondsSinceEpoch >> 16) & 0xff), |
| | | (byte) ((secondsSinceEpoch >> 8) & 0xff), (byte) (secondsSinceEpoch & 0xff), |
| | | (byte) ((fractionOfSecond >> 16) & 0xff), (byte) ((fractionOfSecond >> 8) & 0xff), |
| | | (byte) (fractionOfSecond & 0xff), (byte) 0x8a }; |
| | | |
| | | } |
| | | |
| | | public void setDate(Date date, boolean leapSecondsKnown, boolean clockFailure, boolean clockNotSynchronized, |
| | | int timeAccuracy) { |
| | | if (value == null) { |
| | | value = new byte[8]; |
| | | } |
| | | |
| | | int secondsSinceEpoch = (int) (date.getTime() / 1000L); |
| | | int fractionOfSecond = (int) ((date.getTime() % 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 void setValue(byte[] value) { |
| | | if (value == null) { |
| | | this.value = new byte[8]; |
| | | } |
| | | this.value = value; |
| | | } |
| | | |
| | | @Override |
| | | 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 Date getDate() { |
| | | if (value == null || value.length == 0) { |
| | | return null; |
| | | } |
| | | long time = getSecondsSinceEpoch() * 1000L + (long) (((float) getFractionOfSecond()) / (1 << 24) * 1000 + 0.5); |
| | | return new Date(time); |
| | | } |
| | | |
| | | public byte[] getValue() { |
| | | return 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. |
| | | * |
| | | * Java {@link Date} and {@link Calendar} objects do handle leap seconds, so this is usually true. |
| | | * |
| | | * @return TRUE of the attribute LeapSecondsKnown shall indicate that the value for SecondSinceEpoch takes into |
| | | * account all leap seconds occurred |
| | | */ |
| | | public boolean getLeapSecondsKnown() { |
| | | return ((value[7] & 0x80) != 0); |
| | | } |
| | | |
| | | /** |
| | | * The attribute clockFailure shall indicate that the time source of the sending device is unreliable. The value of |
| | | * the TimeStamp shall be ignored. |
| | | * |
| | | * @return true if the time source of the sending device is unreliable |
| | | */ |
| | | public boolean getClockFailure() { |
| | | return ((value[7] & 0x40) != 0); |
| | | } |
| | | |
| | | /** |
| | | * The attribute clockNotSynchronized shall indicate that the time source of the sending device is not synchronized |
| | | * with the external UTC time. |
| | | * |
| | | * @return true if the time source of the sending device is not synchronized |
| | | */ |
| | | public boolean getClockNotSynchronized() { |
| | | return ((value[7] & 0x20) != 0); |
| | | } |
| | | |
| | | /** |
| | | * The attribute TimeAccuracy shall represent the time accuracy class of the time source of the sending device |
| | | * relative to the external UTC time. The timeAccuracy classes shall represent the number of significant bits in the |
| | | * FractionOfSecond |
| | | * |
| | | * If the time is set via Java {@link Date} objects, the accuracy is 1 ms, that is a timeAccuracy value of 10. |
| | | * |
| | | * @return the time accuracy |
| | | */ |
| | | public int getTimeAccuracy() { |
| | | return ((value[7] & 0x1f)); |
| | | } |
| | | |
| | | /** |
| | | * Sets Timestamp the empty byte array (indicating an invalid Timestamp) |
| | | */ |
| | | @Override |
| | | public void setDefault() { |
| | | value = new byte[8]; |
| | | } |
| | | |
| | | /** |
| | | * Sets Timestamp to current time |
| | | */ |
| | | public void setCurrentTime() { |
| | | setDate(new Date()); |
| | | } |
| | | |
| | | @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() + ": " + getDate(); |
| | | } |
| | | |
| | | } |
| | | /*
|
| | | * Copyright 2011-17 Fraunhofer ISE, energy & meteo Systems GmbH and other contributors
|
| | | *
|
| | | * 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 org.openmuc.openiec61850;
|
| | |
|
| | | import java.util.Calendar;
|
| | | import java.util.Date;
|
| | |
|
| | | import org.openmuc.jasn1.ber.types.BerNull;
|
| | | import org.openmuc.openiec61850.internal.mms.asn1.Data;
|
| | | import org.openmuc.openiec61850.internal.mms.asn1.TypeDescription;
|
| | | import org.openmuc.openiec61850.internal.mms.asn1.UtcTime;
|
| | |
|
| | | public final class BdaTimestamp extends BasicDataAttribute {
|
| | |
|
| | | private 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.
|
| | | * |
| | | * NOTE 2 The resolution of a time stamp may be 1/2**1 (= 0,5 s) if only the first bit is used; or may be 1/2**2 (=
|
| | | * 0,25 s) if the first two bits are used; or may be approximately 60 ns if all 24 bits are used. The resolution
|
| | | * provided by an IED is outside the scope of this standard.
|
| | | * |
| | | * @return the fraction of seconds
|
| | | */
|
| | | private int getFractionOfSecond() {
|
| | | return ((0xff & value[4]) << 16 | (0xff & value[5]) << 8 | (0xff & value[6]));
|
| | | }
|
| | |
|
| | | public void setDate(Date date) {
|
| | | if (value == null) {
|
| | | value = new byte[8];
|
| | | }
|
| | |
|
| | | int secondsSinceEpoch = (int) (date.getTime() / 1000L);
|
| | | int fractionOfSecond = (int) ((date.getTime() % 1000L) / 1000.0 * (1 << 24));
|
| | |
|
| | | // 0x8a = time accuracy of 10 and LeapSecondsKnown = true, ClockFailure
|
| | | // = false, ClockNotSynchronized = false
|
| | | value = new byte[] { (byte) ((secondsSinceEpoch >> 24) & 0xff), (byte) ((secondsSinceEpoch >> 16) & 0xff),
|
| | | (byte) ((secondsSinceEpoch >> 8) & 0xff), (byte) (secondsSinceEpoch & 0xff),
|
| | | (byte) ((fractionOfSecond >> 16) & 0xff), (byte) ((fractionOfSecond >> 8) & 0xff),
|
| | | (byte) (fractionOfSecond & 0xff), (byte) 0x8a };
|
| | |
|
| | | }
|
| | |
|
| | | public void setDate(Date date, boolean leapSecondsKnown, boolean clockFailure, boolean clockNotSynchronized,
|
| | | int timeAccuracy) {
|
| | | if (value == null) {
|
| | | value = new byte[8];
|
| | | }
|
| | |
|
| | | int secondsSinceEpoch = (int) (date.getTime() / 1000L);
|
| | | int fractionOfSecond = (int) ((date.getTime() % 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 void setValue(byte[] value) {
|
| | | if (value == null) {
|
| | | this.value = new byte[8];
|
| | | }
|
| | | this.value = value;
|
| | | }
|
| | |
|
| | | @Override
|
| | | 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 Date getDate() {
|
| | | if (value == null || value.length == 0) {
|
| | | return null;
|
| | | }
|
| | | long time = getSecondsSinceEpoch() * 1000L + (long) (((float) getFractionOfSecond()) / (1 << 24) * 1000 + 0.5);
|
| | | return new Date(time);
|
| | | }
|
| | |
|
| | | public byte[] getValue() {
|
| | | return 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.
|
| | | * |
| | | * Java {@link Date} and {@link Calendar} objects do handle leap seconds, so this is usually true.
|
| | | * |
| | | * @return TRUE of the attribute LeapSecondsKnown shall indicate that the value for SecondSinceEpoch takes into
|
| | | * account all leap seconds occurred
|
| | | */
|
| | | public boolean getLeapSecondsKnown() {
|
| | | return ((value[7] & 0x80) != 0);
|
| | | }
|
| | |
|
| | | /**
|
| | | * The attribute clockFailure shall indicate that the time source of the sending device is unreliable. The value of
|
| | | * the TimeStamp shall be ignored.
|
| | | * |
| | | * @return true if the time source of the sending device is unreliable
|
| | | */
|
| | | public boolean getClockFailure() {
|
| | | return ((value[7] & 0x40) != 0);
|
| | | }
|
| | |
|
| | | /**
|
| | | * The attribute clockNotSynchronized shall indicate that the time source of the sending device is not synchronized
|
| | | * with the external UTC time.
|
| | | * |
| | | * @return true if the time source of the sending device is not synchronized
|
| | | */
|
| | | public boolean getClockNotSynchronized() {
|
| | | return ((value[7] & 0x20) != 0);
|
| | | }
|
| | |
|
| | | /**
|
| | | * The attribute TimeAccuracy shall represent the time accuracy class of the time source of the sending device
|
| | | * relative to the external UTC time. The timeAccuracy classes shall represent the number of significant bits in the
|
| | | * FractionOfSecond
|
| | | * |
| | | * If the time is set via Java {@link Date} objects, the accuracy is 1 ms, that is a timeAccuracy value of 10.
|
| | | * |
| | | * @return the time accuracy
|
| | | */
|
| | | public int getTimeAccuracy() {
|
| | | return ((value[7] & 0x1f));
|
| | | }
|
| | |
|
| | | /**
|
| | | * Sets Timestamp the empty byte array (indicating an invalid Timestamp)
|
| | | */
|
| | | @Override
|
| | | public void setDefault() {
|
| | | value = new byte[8];
|
| | | }
|
| | |
|
| | | /**
|
| | | * Sets Timestamp to current time
|
| | | */
|
| | | public void setCurrentTime() {
|
| | | setDate(new Date());
|
| | | }
|
| | |
|
| | | @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() + ": " + getDate();
|
| | | }
|
| | |
|
| | | }
|