Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
gurux.dlms.internal.GXCommon Maven / Gradle / Ivy
Go to download
gurux.dlms.java package is used to communicate with DLMS devices.
//
// --------------------------------------------------------------------------
// Gurux Ltd
//
//
//
// Filename: $HeadURL$
//
// Version: $Revision$,
// $Date$
// $Author$
//
// Copyright (c) Gurux Ltd
//
//---------------------------------------------------------------------------
//
// DESCRIPTION
//
// This file is a part of Gurux Device Framework.
//
// Gurux Device Framework is Open Source software; you can redistribute it
// and/or modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2 of the License.
// Gurux Device Framework is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// More information of Gurux products: https://www.gurux.org
//
// This code is licensed under the GNU General Public License v2.
// Full text may be retrieved at http://www.gnu.org/licenses/gpl-2.0.txt
//---------------------------------------------------------------------------
package gurux.dlms.internal;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.TimeZone;
import gurux.dlms.GXArray;
import gurux.dlms.GXBitString;
import gurux.dlms.GXByteBuffer;
import gurux.dlms.GXCryptoKeyParameter;
import gurux.dlms.GXDLMSClient;
import gurux.dlms.GXDLMSConverter;
import gurux.dlms.GXDLMSSettings;
import gurux.dlms.GXDate;
import gurux.dlms.GXDateTime;
import gurux.dlms.GXEnum;
import gurux.dlms.GXStructure;
import gurux.dlms.GXTime;
import gurux.dlms.GXUInt16;
import gurux.dlms.GXUInt32;
import gurux.dlms.GXUInt64;
import gurux.dlms.GXUInt8;
import gurux.dlms.enums.ClockStatus;
import gurux.dlms.enums.Command;
import gurux.dlms.enums.ConnectionState;
import gurux.dlms.enums.CryptoKeyType;
import gurux.dlms.enums.DataType;
import gurux.dlms.enums.DateTimeExtraInfo;
import gurux.dlms.enums.DateTimeSkips;
import gurux.dlms.enums.Security;
import gurux.dlms.enums.Standard;
import gurux.dlms.enums.TranslatorOutputType;
import gurux.dlms.objects.enums.CertificateType;
import gurux.dlms.objects.enums.SecuritySuite;
/*
* This class is for internal use only and is subject to changes or removal
* in future versions of the API. Don't use it.
*/
public final class GXCommon {
private static String zeroes = "00000000000000000000000000000000";
private static char[] hexArray = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
private static final char[] BASE_64_ARRAY = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/', '=' };
/*
* Constructor.
*/
private GXCommon() {
}
@SuppressWarnings("squid:S2386")
public static final byte[] LLC_SEND_BYTES = { (byte) 0xE6, (byte) 0xE6, 0x00 };
@SuppressWarnings("squid:S2386")
public static final byte[] LLC_REPLY_BYTES = { (byte) 0xE6, (byte) 0xE7, 0x00 };
/*
* Convert string to byte array.
* @param value String value.
* @return String as bytes.
*/
public static byte[] getBytes(final String value) {
if (value == null) {
return new byte[0];
}
return value.getBytes(StandardCharsets.US_ASCII);
}
/*
* Convert char hex value to byte value.
* @param c Character to convert hex.
* @return Byte value of hex char value.
*/
private static byte getValue(final byte c) {
byte value = -1;
// If number
if (c > 0x2F && c < 0x3A) {
value = (byte) (c - '0');
} else if (c > 0x40 && c < 'G') {
// If upper case.
value = (byte) (c - 'A' + 10);
} else if (c > 0x60 && c < 'g') {
// If lower case.
value = (byte) (c - 'a' + 10);
}
return value;
}
private static boolean isHex(final byte c) {
return getValue(c) != -1;
}
/**
* Convert string to byte array.
*
* @param value
* Hex string.
* @return byte array.
*/
@SuppressWarnings("squid:S3034")
public static byte[] hexToBytes(final String value) {
if (value == null || value.length() == 0) {
return new byte[0];
}
int len = value.length() / 2;
if (value.length() % 2 != 0) {
++len;
}
byte[] buffer = new byte[len];
int lastValue = -1;
int index = 0;
for (byte ch : value.getBytes()) {
if (isHex(ch)) {
if (lastValue == -1) {
lastValue = getValue(ch);
} else if (lastValue != -1) {
buffer[index] = (byte) (lastValue << 4 | getValue(ch));
lastValue = -1;
++index;
}
} else if (lastValue != -1 && ch == ' ') {
buffer[index] = getValue(ch);
lastValue = -1;
++index;
} else {
lastValue = -1;
}
}
if (lastValue != -1) {
buffer[index] = (byte) lastValue;
++index;
}
// If there are no spaces in the hex string.
if (buffer.length == index) {
return buffer;
}
byte[] tmp = new byte[index];
System.arraycopy(buffer, 0, tmp, 0, index);
return tmp;
}
/*
* Convert byte array to hex string.
*/
public static String toHex(final byte[] bytes) {
return toHex(bytes, true);
}
/*
* Convert byte array to hex string.
*/
public static String toHex(final byte[] bytes, final boolean addSpace) {
if (bytes == null) {
return "";
}
return toHex(bytes, addSpace, 0, bytes.length);
}
/*
* Convert byte array to hex string.
*/
public static String toHex(final byte[] bytes, final boolean addSpace, final int index, final int count) {
if (bytes == null || bytes.length == 0 || count == 0) {
return "";
}
char[] str;
if (addSpace) {
str = new char[count * 3];
} else {
str = new char[count * 2];
}
int tmp;
int len = 0;
for (int pos = 0; pos != count; ++pos) {
tmp = bytes[index + pos] & 0xFF;
str[len] = hexArray[tmp >>> 4];
++len;
str[len] = hexArray[tmp & 0x0F];
++len;
if (addSpace) {
str[len] = ' ';
++len;
}
}
if (addSpace) {
--len;
}
return new String(str, 0, len);
}
/**
* Is string hex string.
*
* @param value
* String value.
* @return Return true, if string is hex string.
*/
public static boolean isHexString(final String value) {
if (value == null || value.length() == 0) {
return false;
}
char ch;
for (int pos = 0; pos != value.length(); ++pos) {
ch = value.charAt(pos);
if (ch != ' ' && !((ch > 0x40 && ch < 'G') || (ch > 0x60 && ch < 'g') || (ch > '/' && ch < ':'))) {
return false;
}
}
return true;
}
/**
* Convert byte array to Base64 string.
*
* @param value
* Byte array to convert.
* @return Base64 string.
*/
public static String toBase64(final byte[] value) {
StringBuilder str = new StringBuilder((value.length * 4) / 3);
int b;
for (int pos = 0; pos < value.length; pos += 3) {
b = (value[pos] & 0xFC) >> 2;
str.append(BASE_64_ARRAY[b]);
b = (value[pos] & 0x03) << 4;
if (pos + 1 < value.length) {
b |= (value[pos + 1] & 0xF0) >> 4;
str.append(BASE_64_ARRAY[b]);
b = (value[pos + 1] & 0x0F) << 2;
if (pos + 2 < value.length) {
b |= (value[pos + 2] & 0xC0) >> 6;
str.append(BASE_64_ARRAY[b]);
b = value[pos + 2] & 0x3F;
str.append(BASE_64_ARRAY[b]);
} else {
str.append(BASE_64_ARRAY[b]);
str.append('=');
}
} else {
str.append(BASE_64_ARRAY[b]);
str.append("==");
}
}
return str.toString();
}
/**
* Get index of given char.
*
* @param ch
* @return
*/
private static int getIndex(final char ch) {
if (ch == '+') {
return 62;
}
if (ch == '/') {
return 63;
}
if (ch == '=') {
return 64;
}
if (ch < ':') {
return (52 + (ch - '0'));
}
if (ch < '[') {
return (ch - 'A');
}
if (ch < '{') {
return (26 + (ch - 'a'));
}
throw new IllegalArgumentException("fromBase64");
}
/**
* Convert Base64 string to byte array.
*
* @param input
* Base64 string.
* @return Converted byte array.
*/
public static byte[] fromBase64(final String input) {
String tmp = input.replace("\r\n", "").replace("\n", "");
if (tmp.length() % 4 != 0) {
throw new IllegalArgumentException("Invalid base64 input");
}
int len = (tmp.length() * 3) / 4;
int pos = tmp.indexOf('=');
if (pos > 0) {
len -= tmp.length() - pos;
}
byte[] decoded = new byte[len];
char[] inChars = new char[4];
int j = 0;
int[] b = new int[4];
for (pos = 0; pos != tmp.length(); pos += 4) {
tmp.getChars(pos, pos + 4, inChars, 0);
b[0] = getIndex(inChars[0]);
b[1] = getIndex(inChars[1]);
b[2] = getIndex(inChars[2]);
b[3] = getIndex(inChars[3]);
decoded[j++] = (byte) ((b[0] << 2) | (b[1] >> 4));
if (b[2] < 64) {
decoded[j++] = (byte) ((b[1] << 4) | (b[2] >> 2));
if (b[3] < 64) {
decoded[j++] = (byte) ((b[2] << 6) | b[3]);
}
}
}
return decoded;
}
public static int intValue(final Object value) {
if (value instanceof Byte) {
return ((Byte) value).intValue() & 0xFF;
}
if (value instanceof Short) {
return ((Short) value).intValue() & 0xFFFF;
}
return ((Number) value).intValue();
}
/**
* Insert item count to the begin of the buffer.
*
* @param count
* Count.
* @param buff
* Buffer.
* @param index
* byte index.
*/
public static void insertObjectCount(int count, GXByteBuffer buff, int index) {
if (count < 0x80) {
buff.move(index, index + 1, buff.size());
buff.size(buff.size() - index);
buff.setUInt8(index, (byte) count);
} else if (count < 0x100) {
buff.move(index, index + 2, buff.size());
buff.size(buff.size() - index);
buff.setUInt8(index, 0x81);
buff.setUInt8(index + 1, (byte) count);
} else if (count < 0x10000) {
buff.move(index, index + 4, buff.size());
buff.size(buff.size() - index);
buff.setUInt8(index, 0x82);
buff.setUInt16(index + 1, count);
} else {
buff.move(index, index + 5, buff.size());
buff.size(buff.size() - index);
buff.setUInt8(index, 0x84);
buff.setUInt32(index + 1, count);
}
}
/*
* Get object count. If first byte is 0x80 or higger it will tell bytes
* count.
* @param data received data.
* @return Object count.
*/
public static int getObjectCount(final GXByteBuffer data) {
int cnt = data.getUInt8();
if (cnt > 0x80) {
if (cnt == 0x81) {
return data.getUInt8();
} else if (cnt == 0x82) {
return data.getUInt16();
} else if (cnt == 0x83) {
return data.getUInt24();
} else if (cnt == 0x84) {
return (int) data.getUInt32();
} else {
throw new IllegalArgumentException("Invalid count.");
}
}
return cnt;
}
/**
* Return how many bytes object count takes.
*
* @param count
* Value
* @return Value size in bytes.
*/
public static int getObjectCountSizeInBytes(final int count) {
if (count < 0x80) {
return 1;
} else if (count < 0x100) {
return 2;
} else if (count < 0x10000) {
return 3;
} else {
return 5;
}
}
/**
* Add string to byte buffer.
*
* @param value
* String to add.
* @param bb
* Byte buffer where string is added.
*/
public static void addString(final String value, final GXByteBuffer bb) {
bb.setUInt8((byte) DataType.OCTET_STRING.getValue());
if (value == null) {
setObjectCount(0, bb);
} else {
setObjectCount(value.length(), bb);
bb.set(value.getBytes());
}
}
/*
* Set item count.
* @param count
* @param buff
*/
public static byte setObjectCount(final int count, final GXByteBuffer buff) {
if (count < 0x80) {
buff.setUInt8(count);
return 1;
} else if (count < 0x100) {
buff.setUInt8(0x81);
buff.setUInt8(count);
return 2;
} else if (count < 0x10000) {
buff.setUInt8(0x82);
buff.setUInt16(count);
return 3;
} else {
buff.setUInt8(0x84);
buff.setUInt32(count);
return 5;
}
}
/*
* Compares, whether two given arrays are similar.
* @param arr1 First array to compare.
* @param index Starting index of table, for first array.
* @param arr2 Second array to compare.
* @return True, if arrays are similar. False, if the arrays differ.
*/
public static boolean compare(final byte[] arr1, final byte[] arr2) {
if (arr1.length != arr2.length) {
return false;
}
int pos;
for (pos = 0; pos != arr2.length; ++pos) {
if (arr1[pos] != arr2[pos]) {
return false;
}
}
return true;
}
/*
* Reserved for internal use.
*/
@SuppressWarnings("squid:S3034")
public static void toBitString(final StringBuilder sb, final byte value, final int count) {
int count2 = count;
if (count2 > 0) {
if (count2 > 8) {
count2 = 8;
}
for (int pos = 7; pos != 8 - count2 - 1; --pos) {
if ((value & (1 << pos)) != 0) {
sb.append('1');
} else {
sb.append('0');
}
}
}
}
/**
* Get data from DLMS frame.
*
* @param settings
* DLMS settings.
* @param data
* received data.
* @param info
* Data info.
* @return Received data.
*/
public static Object getData(final GXDLMSSettings settings, final GXByteBuffer data, final GXDataInfo info) {
Object value = null;
int startIndex = data.position();
if (data.position() == data.size()) {
info.setComplete(false);
return null;
}
info.setComplete(true);
boolean knownType = info.getType() != DataType.NONE;
// Get data type if it is unknown.
if (!knownType) {
info.setType(DataType.forValue(data.getUInt8()));
}
if (info.getType() == DataType.NONE) {
if (info.getXml() != null) {
info.getXml().appendLine("<" + info.getXml().getDataType(info.getType()) + " />");
}
return value;
}
if (data.position() == data.size()) {
info.setComplete(false);
return null;
}
switch (info.getType()) {
case ARRAY:
case STRUCTURE:
value = getArray(settings, data, info, startIndex);
break;
case BOOLEAN:
value = getBoolean(data, info);
break;
case BITSTRING:
value = getBitString(data, info);
break;
case INT32:
value = getInt32(data, info);
break;
case UINT32:
value = getUInt32(settings, data, info);
break;
case STRING:
value = getString(data, info, knownType);
break;
case STRING_UTF8:
value = getUtfString(data, info, knownType);
break;
case OCTET_STRING:
value = getOctetString(settings, data, info, knownType);
break;
case BCD:
value = getBcd(data, info);
break;
case INT8:
value = getInt8(data, info);
break;
case INT16:
value = getInt16(data, info);
break;
case UINT8:
value = getUInt8(settings, data, info);
break;
case UINT16:
value = getUInt16(settings, data, info);
break;
case COMPACT_ARRAY:
value = getCompactArray(settings, data, info);
break;
case INT64:
value = getInt64(data, info);
break;
case UINT64:
value = getUInt64(settings, data, info);
break;
case ENUM:
value = getEnum(data, info);
break;
case FLOAT32:
value = getFloat(data, info);
break;
case FLOAT64:
value = getDouble(data, info);
break;
case DATETIME:
value = getDateTime(settings, data, info);
break;
case DATE:
value = getDate(data, info);
break;
case TIME:
value = getTime(data, info);
break;
default:
throw new IllegalArgumentException("Invalid data type.");
}
return value;
}
/*
* Convert value to hex string.
* @param value value to convert.
* @param desimals Amount of decimals.
* @return
*/
public static String integerToHex(final Object value, final int desimals) {
long tmp;
if (value instanceof Byte) {
tmp = ((Byte) value).byteValue() & 0xFF;
} else if (value instanceof Short) {
tmp = ((Short) value).shortValue() & 0xFFFF;
} else if (value instanceof Long) {
tmp = ((Long) value).longValue() & 0xFFFFFFFF;
} else if (value instanceof GXUInt8) {
tmp = ((GXUInt8) value).byteValue() & 0xFF;
} else if (value instanceof GXUInt16) {
tmp = ((GXUInt16) value).shortValue() & 0xFFFF;
} else if (value instanceof GXUInt32) {
tmp = ((GXUInt32) value).longValue() & 0xFFFFFFFF;
} else {
tmp = ((Number) value).longValue();
}
String str = Long.toString(tmp, 16).toUpperCase();
if (desimals == 0 || str.length() >= desimals || str.length() == zeroes.length()) {
return str;
}
return zeroes.substring(0, desimals - str.length()) + str;
}
/*
* Convert value to hex string.
* @param value value to convert.
* @param desimals Amount of decimals.
* @return
*/
public static String integerString(final Object value, final int desimals) {
String str = Long.toString(((Number) value).longValue());
if (desimals == 0 || str.length() == zeroes.length()) {
return str;
}
return zeroes.substring(0, desimals - str.length()) + str;
}
/**
* Get array from DLMS data.
*
* @param buff
* Received DLMS data.
* @param info
* Data info.
* @param index
* starting index.
* @return Object array.
*/
private static Object getArray(final GXDLMSSettings settings, final GXByteBuffer buff, final GXDataInfo info,
final int index) {
if (info.getCount() == 0) {
info.setCount(GXCommon.getObjectCount(buff));
}
if (info.getXml() != null) {
info.getXml().appendStartTag(info.getXml().getDataType(info.getType()), "Qty",
info.getXml().integerToHex(info.getCount(), 2));
}
int size = buff.size() - buff.position();
if (info.getCount() != 0 && size < 1) {
info.setComplete(false);
return null;
}
int startIndex = index;
java.util.ArrayList arr;
if (info.getType() == DataType.ARRAY) {
arr = new GXArray();
} else {
arr = new GXStructure();
}
// Position where last row was found. Cache uses this info.
int pos = info.getIndex();
for (; pos != info.getCount(); ++pos) {
GXDataInfo info2 = new GXDataInfo();
info2.setXml(info.getXml());
Object tmp = getData(settings, buff, info2);
if (!info2.isComplete()) {
buff.position(startIndex);
info.setComplete(false);
break;
} else {
if (info2.getCount() == info2.getIndex()) {
startIndex = buff.position();
arr.add(tmp);
}
}
}
if (info.getXml() != null) {
info.getXml().appendEndTag(info.getXml().getDataType(info.getType()));
}
info.setIndex(pos);
return arr;
}
/**
* Get time from DLMS data.
*
* @param buff
* Received DLMS data.
* @param info
* Data info.
* @return Parsed time.
*/
private static Object getTime(final GXByteBuffer buff, final GXDataInfo info) {
Object value = null;
if (buff.size() - buff.position() < 4) {
// If there is not enough data available.
info.setComplete(false);
return null;
}
String str = null;
if (info.getXml() != null) {
str = GXCommon.toHex(buff.getData(), false, buff.position(), 4);
}
try {
// Get time.
int hour = buff.getUInt8();
int minute = buff.getUInt8();
int second = buff.getUInt8();
int ms = buff.getUInt8();
if (ms != 0xFF) {
ms *= 10;
} else {
ms = -1;
}
GXTime dt = new GXTime(hour, minute, second, ms);
value = dt;
} catch (Exception ex) {
if (info.getXml() == null) {
throw ex;
}
}
if (info.getXml() != null) {
if (value != null) {
info.getXml().appendComment(String.valueOf(value));
}
info.getXml().appendLine(info.getXml().getDataType(info.getType()), null, str);
}
return value;
}
/**
* Get date from DLMS data.
*
* @param buff
* Received DLMS data.
* @param info
* Data info.
* @return Parsed date.
*/
private static Object getDate(final GXByteBuffer buff, final GXDataInfo info) {
Object value = null;
if (buff.size() - buff.position() < 5) {
// If there is not enough data available.
info.setComplete(false);
return null;
}
String str = null;
if (info.getXml() != null) {
str = GXCommon.toHex(buff.getData(), false, buff.position(), 5);
}
try {
// Get year.
int year = buff.getUInt16();
// Get month
int month = buff.getUInt8();
java.util.Set extra = new HashSet();
java.util.Set skip = new HashSet();
if (month == 0 || month == 0xFF) {
month = 1;
skip.add(DateTimeSkips.MONTH);
} else if (month == 0xFE) {
// Daylight savings begin.
month = 1;
extra.add(DateTimeExtraInfo.DST_BEGIN);
} else if (month == 0xFD) {
// Daylight savings end.
month = 1;
extra.add(DateTimeExtraInfo.DST_END);
}
// Get day
int day = buff.getUInt8();
if (day == 0xFD) {
// 2nd last day of month.
day = 1;
extra.add(DateTimeExtraInfo.LAST_DAY2);
} else if (day == 0xFE) {
// Last day of month
day = 1;
extra.add(DateTimeExtraInfo.LAST_DAY);
} else if (day < 1 || day == 0xFF) {
day = 1;
skip.add(DateTimeSkips.DAY);
}
GXDate dt = new GXDate(year, month, day);
value = dt;
dt.setExtra(extra);
dt.getSkip().addAll(skip);
// Skip week day
if (buff.getUInt8() == 0xFF) {
dt.getSkip().add(DateTimeSkips.DAY_OF_WEEK);
}
} catch (Exception ex) {
if (info.getXml() == null) {
throw ex;
}
}
if (info.getXml() != null) {
if (value != null) {
info.getXml().appendComment(String.valueOf(value));
}
info.getXml().appendLine(info.getXml().getDataType(info.getType()), null, str);
}
return value;
}
/**
* Get the number of days in that month.
*
* @param year
* Year.
* @param month
* Month.
* @return Number of days in month.
*/
public static int daysInMonth(final int year, final int month) {
Calendar cal = Calendar.getInstance();
cal.set(year, month, 1);
return cal.getActualMaximum(Calendar.DAY_OF_MONTH);
}
/**
* Get date and time from DLMS data.
*
* @param buff
* Received DLMS data.
* @param info
* Data info.
* @return Parsed date and time.
*/
private static Object getDateTime(final GXDLMSSettings settings, final GXByteBuffer buff, final GXDataInfo info) {
Object value = null;
java.util.Set skip = new HashSet();
// If there is not enough data available.
if (buff.size() - buff.position() < 12) {
info.setComplete(false);
return null;
}
String str = null;
if (info.getXml() != null) {
str = GXCommon.toHex(buff.getData(), false, buff.position(), 12);
}
GXDateTime dt = new GXDateTime();
try {
// Get year.
int year = buff.getUInt16();
// Get month
int month = buff.getUInt8();
if (month == 0 || month == 0xFF) {
month = 1;
skip.add(DateTimeSkips.MONTH);
} else if (month == 0xFE) {
// Daylight savings begin.
month = 1;
dt.getExtra().add(DateTimeExtraInfo.DST_BEGIN);
} else if (month == 0xFD) {
// Daylight savings end.
month = 1;
dt.getExtra().add(DateTimeExtraInfo.DST_END);
}
// Get day
int day = buff.getUInt8();
if (day == 0xFD) {
// 2nd last day of month.
day = 1;
dt.getExtra().add(DateTimeExtraInfo.LAST_DAY2);
} else if (day == 0xFE) {
// Last day of month
day = 1;
dt.getExtra().add(DateTimeExtraInfo.LAST_DAY);
} else if (day < 1 || day == 0xFF) {
day = 1;
skip.add(DateTimeSkips.DAY);
}
// Skip week day
int dayOfWeek = buff.getUInt8();
if (dayOfWeek == 0xFF) {
skip.add(DateTimeSkips.DAY_OF_WEEK);
} else {
dt.setDayOfWeek(dayOfWeek);
}
// Get time.
int hour = buff.getUInt8();
int minute = buff.getUInt8();
int second = buff.getUInt8();
int ms = buff.getUInt8() & 0xFF;
if (ms != 0xFF) {
ms *= 10;
} else {
ms = -1;
}
int deviation = buff.getInt16();
if (deviation == -32768) {
skip.add(DateTimeSkips.DEVIATION);
}
int status = buff.getUInt8();
dt.setStatus(ClockStatus.forValue(status));
if (year < 1 || year == 0xFFFF) {
skip.add(DateTimeSkips.YEAR);
java.util.Calendar tm = java.util.Calendar.getInstance();
year = tm.get(Calendar.YEAR);
}
if (month != 0xFE && month != 0xFD) {
if (month < 1 || month > 12) {
skip.add(DateTimeSkips.MONTH);
month = 0;
} else {
month -= 1;
}
}
if (day != 0xFE && day != 0xFD) {
if (day == -1 || day == 0 || day > 31) {
skip.add(DateTimeSkips.DAY);
day = 1;
}
}
if (hour < 0 || hour > 24) {
skip.add(DateTimeSkips.HOUR);
hour = 0;
}
if (minute < 0 || minute > 60) {
skip.add(DateTimeSkips.MINUTE);
minute = 0;
}
if (second < 0 || second > 60) {
skip.add(DateTimeSkips.SECOND);
second = 0;
}
// If ms is Zero it's skipped.
if (ms < 0 || ms > 1000) {
skip.add(DateTimeSkips.MILLISECOND);
ms = 0;
}
if (settings != null && settings.getUseUtc2NormalTime() && deviation != -32768) {
deviation = -deviation;
}
java.util.Calendar tm;
boolean ignoreDeviation = deviation == -32768;
if (!ignoreDeviation && settings != null
&& settings.getDateTimeSkipsOnRead().contains(DateTimeSkips.DEVIATION)) {
ignoreDeviation = true;
}
if (ignoreDeviation) {
tm = Calendar.getInstance();
} else {
TimeZone tz =
GXDateTime.getTimeZone(-deviation, dt.getStatus().contains(ClockStatus.DAYLIGHT_SAVE_ACTIVE));
tm = Calendar.getInstance(tz);
}
tm.set(year, month, day, hour, minute, second);
if (skip.contains(DateTimeSkips.MILLISECOND)) {
tm.set(Calendar.MILLISECOND, 0);
} else {
tm.set(Calendar.MILLISECOND, ms);
}
dt.setMeterCalendar(tm);
dt.getSkip().addAll(skip);
value = dt;
} catch (Exception ex) {
if (info.getXml() == null) {
throw ex;
}
}
if (info.getXml() != null) {
if (!dt.getSkip().contains(DateTimeSkips.YEAR) && value != null) {
info.getXml().appendComment(String.valueOf(value));
}
info.getXml().appendLine(info.getXml().getDataType(info.getType()), null, str);
}
return value;
}
/**
* Get double value from DLMS data.
*
* @param buff
* Received DLMS data.
* @param info
* Data info.
* @return Parsed double value.
*/
private static Object getDouble(final GXByteBuffer buff, final GXDataInfo info) {
Object value;
// If there is not enough data available.
if (buff.size() - buff.position() < 8) {
info.setComplete(false);
return null;
}
value = buff.getDouble();
if (info.getXml() != null) {
if (info.getXml().isComments()) {
info.getXml().appendComment(String.format("%.2f", value));
}
GXByteBuffer tmp = new GXByteBuffer();
setData(null, tmp, DataType.FLOAT64, value);
info.getXml().appendLine(info.getXml().getDataType(info.getType()), null,
GXCommon.toHex(tmp.getData(), false, 1, tmp.size() - 1));
}
return value;
}
/**
* Get float value from DLMS data.
*
* @param buff
* Received DLMS data.
* @param info
* Data info.
* @return Parsed float value.
*/
private static Object getFloat(final GXByteBuffer buff, final GXDataInfo info) {
Object value;
// If there is not enough data available.
if (buff.size() - buff.position() < 4) {
info.setComplete(false);
return null;
}
value = buff.getFloat();
if (info.getXml() != null) {
if (info.getXml().isComments()) {
info.getXml().appendComment(String.format("%.2f", value));
}
GXByteBuffer tmp = new GXByteBuffer();
setData(null, tmp, DataType.FLOAT32, value);
info.getXml().appendLine(info.getXml().getDataType(info.getType()), null,
GXCommon.toHex(tmp.getData(), false, 1, tmp.size() - 1));
}
return value;
}
/**
* Get enumeration value from DLMS data.
*
* @param buff
* Received DLMS data.
* @param info
* Data info.
* @return parsed enumeration value.
*/
private static Object getEnum(final GXByteBuffer buff, final GXDataInfo info) {
Object value;
// If there is not enough data available.
if (buff.size() - buff.position() < 1) {
info.setComplete(false);
return null;
}
value = buff.getUInt8();
if (info.getXml() != null) {
info.getXml().appendLine(info.getXml().getDataType(info.getType()), null,
info.getXml().integerToHex(value, 2));
}
return new GXEnum((short) value);
}
/**
* Get UInt64 value from DLMS data.
*
* @param buff
* Received DLMS data.
* @param info
* Data info.
* @return parsed UInt64 value.
*/
private static Object getUInt64(final GXDLMSSettings settings, final GXByteBuffer buff, final GXDataInfo info) {
// If there is not enough data available.
if (buff.size() - buff.position() < 8) {
info.setComplete(false);
return null;
}
BigInteger value = buff.getUInt64();
if (info.getXml() != null) {
info.getXml().appendLine(info.getXml().getDataType(info.getType()), null,
info.getXml().integerToHex(value, 16));
}
// Return old value.
if (settings == null || settings.getVersion() == 3) {
return value;
}
return new GXUInt64(value);
}
/**
* Get Int64 value from DLMS data.
*
* @param buff
* Received DLMS data.
* @param info
* Data info.
* @return parsed Int64 value.
*/
private static Object getInt64(final GXByteBuffer buff, final GXDataInfo info) {
Object value;
// If there is not enough data available.
if (buff.size() - buff.position() < 8) {
info.setComplete(false);
return null;
}
value = buff.getInt64();
if (info.getXml() != null) {
info.getXml().appendLine(info.getXml().getDataType(info.getType()), null,
info.getXml().integerToHex(value, 16));
}
return value;
}
/**
* Get UInt16 value from DLMS data.
*
* @param buff
* Received DLMS data.
* @param info
* Data info.
* @return parsed UInt16 value.
*/
private static Object getUInt16(final GXDLMSSettings settings, final GXByteBuffer buff, final GXDataInfo info) {
Object value;
// If there is not enough data available.
if (buff.size() - buff.position() < 2) {
info.setComplete(false);
return null;
}
value = buff.getUInt16();
if (info.getXml() != null) {
info.getXml().appendLine(info.getXml().getDataType(info.getType()), null,
info.getXml().integerToHex(value, 4));
}
// Return old value.
if (settings == null || settings.getVersion() == 3) {
return value;
}
return new GXUInt16((int) value);
}
@SuppressWarnings("squid:S1172")
private static void getCompactArrayItem(final GXDLMSSettings settings, GXByteBuffer buff, List> dt,
List list, int len) {
List tmp2 = new ArrayList();
for (Object it : dt) {
if (it instanceof DataType) {
getCompactArrayItem(settings, buff, (DataType) it, tmp2, 1);
} else {
getCompactArrayItem(settings, buff, (List>) it, tmp2, 1);
}
}
list.add(tmp2.toArray());
}
private static void getCompactArrayItem(final GXDLMSSettings settings, final GXByteBuffer buff, final DataType dt,
final List list, final int len) {
GXDataInfo tmp = new GXDataInfo();
tmp.setType(dt);
int start = buff.position();
if (dt == DataType.STRING) {
while (buff.position() - start < len) {
tmp.clear();
tmp.setType(dt);
list.add(getString(buff, tmp, false));
if (!tmp.isComplete()) {
break;
}
}
} else if (dt == DataType.OCTET_STRING) {
while (buff.position() - start < len) {
tmp.clear();
tmp.setType(dt);
list.add(getOctetString(settings, buff, tmp, false));
if (!tmp.isComplete()) {
break;
}
}
} else {
while (buff.position() - start < len) {
tmp.clear();
tmp.setType(dt);
list.add(getData(settings, buff, tmp));
if (!tmp.isComplete()) {
break;
}
}
}
}
//
static final int CONTENTS_DESCRIPTION = 0xFF68;
static final int ARRAY_CONTENTS = 0xFF69;
static final int DATA_TYPE_OFFSET = 0xFF0000;
private static void getDataTypes(GXByteBuffer buff, List cols, int len) {
DataType dt;
for (int pos = 0; pos != len; ++pos) {
dt = DataType.forValue(buff.getUInt8());
if (dt == DataType.ARRAY) {
int cnt = buff.getUInt16();
List tmp = new ArrayList();
List tmp2 = new ArrayList();
getDataTypes(buff, tmp, 1);
for (int i = 0; i != cnt; ++i) {
tmp2.addAll(tmp);
}
cols.add(tmp2);
} else if (dt == DataType.STRUCTURE) {
List tmp = new ArrayList();
getDataTypes(buff, tmp, buff.getUInt8());
cols.add(tmp.toArray(new Object[tmp.size()]));
} else {
cols.add(dt);
}
}
}
private static void appendDataTypeAsXml(List> cols, GXDataInfo info) {
for (Object it : cols) {
if (it instanceof DataType) {
info.getXml().appendEmptyTag(info.getXml().getDataType((DataType) it));
} else if (it instanceof GXStructure) {
info.getXml().appendStartTag(DATA_TYPE_OFFSET + DataType.STRUCTURE.getValue(), null, null);
appendDataTypeAsXml((List>) it, info);
info.getXml().appendEndTag(DATA_TYPE_OFFSET + DataType.STRUCTURE.getValue());
} else if (it instanceof GXArray) {
info.getXml().appendStartTag(DATA_TYPE_OFFSET + DataType.ARRAY.getValue(), null, null);
appendDataTypeAsXml(((List>) it), info);
info.getXml().appendEndTag(DATA_TYPE_OFFSET + DataType.ARRAY.getValue());
}
}
}
/**
* Get compact array value from DLMS data.
*
* @param buff
* Received DLMS data.
* @param info
* Data info.
* @return parsed UInt16 value.
*/
private static Object getCompactArray(final GXDLMSSettings settings, final GXByteBuffer buff,
final GXDataInfo info) {
// If there is not enough data available.
if (buff.size() - buff.position() < 2) {
info.setComplete(false);
return null;
}
DataType dt = DataType.forValue(buff.getUInt8());
if (dt == DataType.ARRAY) {
throw new IllegalArgumentException("Invalid compact array data.");
}
int len = GXCommon.getObjectCount(buff);
List list = new ArrayList();
if (dt == DataType.STRUCTURE) {
// Get data types.
GXStructure cols = new GXStructure();
getDataTypes(buff, cols, len);
len = GXCommon.getObjectCount(buff);
if (info.getXml() != null) {
info.getXml().appendStartTag(info.getXml().getDataType(DataType.COMPACT_ARRAY), null, null);
info.getXml().appendStartTag(CONTENTS_DESCRIPTION);
appendDataTypeAsXml(cols, info);
info.getXml().appendEndTag(CONTENTS_DESCRIPTION);
if (info.getXml().getOutputType() == TranslatorOutputType.STANDARD_XML) {
info.getXml().appendStartTag(ARRAY_CONTENTS, true);
info.getXml().append(buff.remainingHexString(true));
info.getXml().appendEndTag(ARRAY_CONTENTS, true);
info.getXml().appendEndTag(info.getXml().getDataType(DataType.COMPACT_ARRAY));
} else {
info.getXml().appendStartTag(ARRAY_CONTENTS);
}
}
int start = buff.position();
while (buff.position() - start < len) {
List row = new ArrayList();
for (int pos = 0; pos != cols.size(); ++pos) {
if (cols.get(pos) instanceof GXStructure) {
getCompactArrayItem(settings, buff, (List>) cols.get(pos), row, 1);
} else if (cols.get(pos) instanceof GXArray) {
List tmp2 = new ArrayList();
getCompactArrayItem(settings, buff, ((List>) cols.get(pos)), tmp2, 1);
row.add((List>) tmp2.get(0));
} else {
getCompactArrayItem(settings, buff, (DataType) cols.get(pos), row, 1);
}
if (buff.position() == buff.size()) {
break;
}
}
// If all columns are read.
if (row.size() >= cols.size()) {
list.add(row);
} else {
break;
}
}
if (info.getXml() != null && info.getXml().getOutputType() == TranslatorOutputType.SIMPLE_XML) {
StringBuilder sb = new StringBuilder();
for (Object row : list) {
for (Object it : (List>) row) {
if (it instanceof byte[]) {
sb.append(GXCommon.toHex((byte[]) it));
} else if (it instanceof List>) {
for (Object it2 : (List>) it) {
if (it2 instanceof byte[]) {
sb.append(GXCommon.toHex((byte[]) it2));
} else {
sb.append(String.valueOf(it2));
}
sb.append(";");
}
if (!((List>) it).isEmpty()) {
sb.setLength(sb.length() - 1);
}
} else {
sb.append(String.valueOf(it));
}
sb.append(";");
}
if (sb.length() != 0) {
sb.setLength(sb.length() - 1);
}
info.getXml().appendLine(sb.toString());
sb.setLength(0);
}
}
if (info.getXml() != null && info.getXml().getOutputType() == TranslatorOutputType.SIMPLE_XML) {
info.getXml().appendEndTag(ARRAY_CONTENTS);
info.getXml().appendEndTag(info.getXml().getDataType(DataType.COMPACT_ARRAY));
}
return list;
} else {
if (info.getXml() != null) {
info.getXml().appendStartTag(info.getXml().getDataType(DataType.COMPACT_ARRAY), null, null);
info.getXml().appendStartTag(CONTENTS_DESCRIPTION);
info.getXml().appendEmptyTag(info.getXml().getDataType(dt));
info.getXml().appendEndTag(CONTENTS_DESCRIPTION);
info.getXml().appendStartTag(ARRAY_CONTENTS, true);
if (info.getXml().getOutputType() == TranslatorOutputType.STANDARD_XML) {
info.getXml().append(buff.remainingHexString(false));
info.getXml().appendEndTag(ARRAY_CONTENTS, true);
info.getXml().appendEndTag(info.getXml().getDataType(DataType.COMPACT_ARRAY));
}
}
getCompactArrayItem(settings, buff, dt, list, len);
if (info.getXml() != null && info.getXml().getOutputType() == TranslatorOutputType.SIMPLE_XML) {
for (Object it : list) {
if (it instanceof byte[]) {
info.getXml().append(GXCommon.toHex((byte[]) it));
} else {
info.getXml().append(String.valueOf(it));
}
info.getXml().append(";");
}
if (!list.isEmpty()) {
info.getXml().setXmlLength(info.getXml().getXmlLength() - 1);
}
info.getXml().appendEndTag(ARRAY_CONTENTS, true);
info.getXml().appendEndTag(info.getXml().getDataType(DataType.COMPACT_ARRAY));
}
}
return list;
}
/**
* Get UInt8 value from DLMS data.
*
* @param buff
* Received DLMS data.
* @param info
* Data info.
* @return parsed UInt8 value.
*/
private static Object getUInt8(final GXDLMSSettings settings, final GXByteBuffer buff, final GXDataInfo info) {
int value;
// If there is not enough data available.
if (buff.size() - buff.position() < 1) {
info.setComplete(false);
return null;
}
value = buff.getUInt8() & 0xFF;
if (info.getXml() != null) {
info.getXml().appendLine(info.getXml().getDataType(info.getType()), null,
info.getXml().integerToHex(value, 2));
}
// Return old value.
if (settings == null || settings.getVersion() == 3) {
return value;
}
return new GXUInt8((short) value);
}
/**
* Get Int16 value from DLMS data.
*
* @param buff
* Received DLMS data.
* @param info
* Data info.
* @return parsed Int16 value.
*/
private static Object getInt16(final GXByteBuffer buff, final GXDataInfo info) {
Object value;
// If there is not enough data available.
if (buff.size() - buff.position() < 2) {
info.setComplete(false);
return null;
}
value = buff.getInt16();
if (info.getXml() != null) {
info.getXml().appendLine(info.getXml().getDataType(info.getType()), null,
info.getXml().integerToHex(value, 4));
}
return value;
}
/**
* Get Int8 value from DLMS data.
*
* @param buff
* Received DLMS data.
* @param info
* Data info.
* @return parsed Int8 value.
*/
private static Object getInt8(final GXByteBuffer buff, final GXDataInfo info) {
Object value;
// If there is not enough data available.
if (buff.size() - buff.position() < 1) {
info.setComplete(false);
return null;
}
value = buff.getInt8();
if (info.getXml() != null) {
info.getXml().appendLine(info.getXml().getDataType(info.getType()), null,
info.getXml().integerToHex(value, 2));
}
return value;
}
/**
* Get BCD value from DLMS data.
*
* @param buff
* Received DLMS data.
* @param info
* Data info.
* @return parsed BCD value.
*/
private static Object getBcd(final GXByteBuffer buff, final GXDataInfo info) {
// If there is not enough data available.
if (buff.size() - buff.position() < 1) {
info.setComplete(false);
return null;
}
short value = buff.getUInt8();
if (info.getXml() != null) {
info.getXml().appendLine(info.getXml().getDataType(info.getType()), null,
info.getXml().integerToHex(value, 2));
}
return value;
}
/**
* Get UTF string value from DLMS data.
*
* @param buff
* Received DLMS data.
* @param info
* Data info.
* @return parsed UTF string value.
*/
private static Object getUtfString(final GXByteBuffer buff, final GXDataInfo info, final boolean knownType) {
Object value;
int len;
if (knownType) {
len = buff.size();
} else {
len = GXCommon.getObjectCount(buff);
// If there is not enough data available.
if (buff.size() - buff.position() < len) {
info.setComplete(false);
return null;
}
}
if (len > 0) {
value = buff.getString(buff.position(), len, "UTF-8");
buff.position(buff.position() + len);
} else {
value = "";
}
if (info.getXml() != null) {
if (info.getXml().getShowStringAsHex()) {
info.getXml().appendLine(info.getXml().getDataType(info.getType()), null,
GXCommon.toHex(buff.getData(), false, buff.position() - len, len));
} else {
info.getXml().appendLine(info.getXml().getDataType(info.getType()), null, value.toString());
}
}
return value;
}
/**
* Get octet string value from DLMS data.
*
* @param buff
* Received DLMS data.
* @param info
* Data info.
* @return parsed octet string value.
*/
private static Object getOctetString(final GXDLMSSettings settings, final GXByteBuffer buff, final GXDataInfo info,
final boolean knownType) {
Object value;
int len;
if (knownType) {
len = buff.size();
} else {
len = GXCommon.getObjectCount(buff);
// If there is not enough data available.
if (buff.size() - buff.position() < len) {
info.setComplete(false);
return null;
}
}
byte[] tmp = new byte[len];
buff.get(tmp);
value = tmp;
if (info.getXml() != null) {
if (info.getXml().isComments() && tmp.length != 0) {
// This might be logical name.
if (tmp.length == 6 && tmp[5] == -1) {
info.getXml().appendComment(toLogicalName(tmp));
} else {
boolean isString = true;
// Try to move octet string to DateTime, Date or time.
if (tmp.length == 12 || tmp.length == 5 || tmp.length == 4) {
try {
DataType type;
if (tmp.length == 12) {
type = DataType.DATETIME;
} else if (tmp.length == 5) {
type = DataType.DATE;
} else {
type = DataType.TIME;
}
boolean useUtc;
if (settings != null) {
useUtc = settings.getUseUtc2NormalTime();
} else {
useUtc = false;
}
GXDateTime dt = (GXDateTime) GXDLMSClient.changeType(tmp, type, useUtc);
int year = dt.getMeterCalendar().get(Calendar.YEAR);
if (year > 1970 && year < 2100) {
info.getXml().appendComment(dt.toString());
isString = false;
}
} catch (Exception e) {
isString = true;
}
}
if (isString) {
for (byte it : tmp) {
if (it < 32 || it > 126) {
isString = false;
break;
}
}
if (isString) {
info.getXml().appendComment(new String(tmp));
}
}
}
}
info.getXml().appendLine(info.getXml().getDataType(info.getType()), null, GXCommon.toHex(tmp, false));
}
return value;
}
/**
* Get string value from DLMS data.
*
* @param buff
* Received DLMS data.
* @param info
* Data info.
* @return parsed string value.
*/
private static String getString(final GXByteBuffer buff, final GXDataInfo info, final boolean knownType) {
String value;
int len;
if (knownType) {
len = buff.size();
} else {
len = GXCommon.getObjectCount(buff);
// If there is not enough data available.
if (buff.size() - buff.position() < len) {
info.setComplete(false);
return null;
}
}
if (len > 0) {
value = buff.getString(len);
} else {
value = "";
}
if (info.getXml() != null) {
if (info.getXml().getShowStringAsHex()) {
info.getXml().appendLine(info.getXml().getDataType(info.getType()), null,
GXCommon.toHex(buff.getData(), false, buff.position() - len, len));
} else {
info.getXml().appendLine(info.getXml().getDataType(info.getType()), null, value);
}
}
return value;
}
/**
* Get UInt32 value from DLMS data.
*
* @param buff
* Received DLMS data.
* @param info
* Data info.
* @return parsed UInt32 value.
*/
private static Object getUInt32(final GXDLMSSettings settings, final GXByteBuffer buff, final GXDataInfo info) {
// If there is not enough data available.
if (buff.size() - buff.position() < 4) {
info.setComplete(false);
return null;
}
long value = buff.getUInt32();
if (info.getXml() != null) {
info.getXml().appendLine(info.getXml().getDataType(info.getType()), null,
info.getXml().integerToHex(value, 8));
}
// Return old value.
if (settings == null || settings.getVersion() == 3) {
return value;
}
return new GXUInt32(value);
}
/**
* Get Int32 value from DLMS data.
*
* @param buff
* Received DLMS data.
* @param info
* Data info.
* @return parsed Int32 value.
*/
private static Object getInt32(final GXByteBuffer buff, final GXDataInfo info) {
// If there is not enough data available.
if (buff.size() - buff.position() < 4) {
info.setComplete(false);
return null;
}
Integer value = buff.getInt32();
if (info.getXml() != null) {
info.getXml().appendLine(info.getXml().getDataType(info.getType()), null,
info.getXml().integerToHex(value, 8));
}
return value;
}
/**
* Get bit string value from DLMS data.
*
* @param buff
* Received DLMS data.
* @param info
* Data info.
* @return parsed bit string value.
*/
private static GXBitString getBitString(final GXByteBuffer buff, final GXDataInfo info) {
int cnt = getObjectCount(buff);
double t = cnt;
t /= 8;
if (cnt % 8 != 0) {
++t;
}
int byteCnt = (int) Math.floor(t);
// If there is not enough data available.
if (buff.size() - buff.position() < byteCnt) {
info.setComplete(false);
return null;
}
StringBuilder sb = new StringBuilder();
while (cnt > 0) {
toBitString(sb, buff.getInt8(), cnt);
cnt -= 8;
}
if (info.getXml() != null) {
info.getXml().appendLine(info.getXml().getDataType(info.getType()), null, sb.toString());
}
return new GXBitString(sb.toString());
}
/**
* Get boolean value from DLMS data.
*
* @param buff
* Received DLMS data.
* @param info
* Data info.
* @return parsed boolean value.
*/
private static Object getBoolean(final GXByteBuffer buff, final GXDataInfo info) {
// If there is not enough data available.
if (buff.size() - buff.position() < 1) {
info.setComplete(false);
return null;
}
boolean value = buff.getUInt8() != 0;
if (info.getXml() != null) {
info.getXml().appendLine(info.getXml().getDataType(info.getType()), null, String.valueOf(value));
}
return value;
}
/**
* Get HDLC address from byte array.
*
* @param buff
* byte array.
* @return HDLC address.
*/
public static int getHDLCAddress(final GXByteBuffer buff) {
int size = 0;
for (int pos = buff.position(); pos != buff.size(); ++pos) {
++size;
if ((buff.getUInt8(pos) & 0x1) == 1) {
break;
}
}
if (size == 1) {
return (byte) ((buff.getUInt8() & 0xFE) >>> 1);
} else if (size == 2) {
size = buff.getUInt16();
size = ((size & 0xFE) >>> 1) | ((size & 0xFE00) >>> 2);
return size;
} else if (size == 4) {
long tmp = buff.getUInt32();
tmp = ((tmp & 0xFE) >> 1) | ((tmp & 0xFE00) >> 2) | ((tmp & 0xFE0000) >> 3) | ((tmp & 0xFE000000) >> 4);
return (int) tmp;
}
throw new IllegalArgumentException("Wrong size.");
}
/*
* Convert object to DLMS bytes.
* @param settings DLMS settings.
* @param buff Byte buffer where data is write.
* @param dataType Data type.
* @param value Added Value.
*/
public static void setData(final GXDLMSSettings settings, final GXByteBuffer buff, final DataType dataType,
final Object value) {
// If value is enum get integer value.
if (value instanceof Enum) {
throw new IllegalArgumentException("Value can't be enum. Give integer value.");
}
if ((dataType == DataType.ARRAY || dataType == DataType.STRUCTURE) && value instanceof byte[]) {
// If byte array is added do not add type.
buff.set((byte[]) value);
return;
} else {
buff.setUInt8(dataType.getValue());
}
switch (dataType) {
case NONE:
break;
case BOOLEAN:
if (Boolean.parseBoolean(value.toString())) {
buff.setUInt8(1);
} else {
buff.setUInt8(0);
}
break;
case INT8:
case UINT8:
case ENUM:
buff.setUInt8(((Number) value).byteValue());
break;
case INT16:
case UINT16:
buff.setUInt16(((Number) value).shortValue());
break;
case INT32:
case UINT32:
buff.setUInt32(((Number) value).intValue());
break;
case INT64:
case UINT64:
buff.setUInt64(((Number) value).longValue());
break;
case FLOAT32:
buff.setFloat(((Number) value).floatValue());
break;
case FLOAT64:
buff.setDouble(((Number) value).doubleValue());
break;
case BITSTRING:
setBitString(buff, value, true);
break;
case STRING:
setString(buff, value);
break;
case STRING_UTF8:
setUtfString(buff, value);
break;
case OCTET_STRING:
if (value instanceof GXDate) {
// Add size
buff.setUInt8(5);
setDate(settings, buff, value);
} else if (value instanceof GXTime) {
// Add size
buff.setUInt8(4);
setTime(settings, buff, value);
} else if (value instanceof GXDateTime || value instanceof java.util.Date
|| value instanceof java.util.Calendar) {
// Date an calendar are always written as date time.
buff.setUInt8(12);
setDateTime(settings, buff, value);
} else {
setOctetString(buff, value);
}
break;
case ARRAY:
case STRUCTURE:
setArray(settings, buff, value);
break;
case BCD:
setBcd(buff, value);
break;
case COMPACT_ARRAY:
// Compact array is not work with java because we don't know data
// types of each element. Java is not support unsigned values.
throw new IllegalArgumentException("Invalid data type.");
case DATETIME:
setDateTime(settings, buff, value);
break;
case DATE:
setDate(settings, buff, value);
break;
case TIME:
setTime(settings, buff, value);
break;
default:
throw new IllegalArgumentException("Invalid data type.");
}
}
/**
* Convert time to DLMS bytes.
*
* @param settings
* DLMS settings.
* @param buff
* Byte buffer where data is write.
* @param value
* Added value.
*/
private static void setTime(final GXDLMSSettings settings, final GXByteBuffer buff, final Object value) {
java.util.Set skip = new HashSet();
java.util.Calendar tm = java.util.Calendar.getInstance();
if (value instanceof GXDateTime) {
GXDateTime tmp = (GXDateTime) value;
tm.setTime(tmp.getMeterCalendar().getTime());
skip = tmp.getSkip();
} else if (value instanceof java.util.Date) {
tm.setTime((java.util.Date) value);
} else if (value instanceof java.util.Calendar) {
tm.setTime(((java.util.Calendar) value).getTime());
} else if (value instanceof String) {
DateFormat f = new SimpleDateFormat();
try {
tm.setTime(f.parse(value.toString()));
} catch (ParseException e) {
throw new IllegalArgumentException("Invalid date time value.\r\n" + e.getMessage());
}
} else {
throw new IllegalArgumentException("Invalid date format.");
}
// Add additional date time skips.
if (settings != null && !settings.getDateTimeSkips().isEmpty()) {
skip.addAll(settings.getDateTimeSkips());
}
// Add time.
if (skip.contains(DateTimeSkips.HOUR)) {
buff.setUInt8(0xFF);
} else {
buff.setUInt8(tm.get(java.util.Calendar.HOUR_OF_DAY));
}
if (skip.contains(DateTimeSkips.MINUTE)) {
buff.setUInt8(0xFF);
} else {
buff.setUInt8(tm.get(java.util.Calendar.MINUTE));
}
if (skip.contains(DateTimeSkips.SECOND)) {
buff.setUInt8(0xFF);
} else {
buff.setUInt8(tm.get(java.util.Calendar.SECOND));
}
if (skip.contains(DateTimeSkips.MILLISECOND)) {
// Hundredths of second is not used.
buff.setUInt8(0xFF);
} else {
buff.setUInt8(tm.get(java.util.Calendar.MILLISECOND) / 10);
}
}
/**
* Convert date to DLMS bytes.
*
* @param settings
* DLMS settings.
* @param buff
* Byte buffer where data is write.
* @param value
* Added value.
*/
private static void setDate(final GXDLMSSettings settings, final GXByteBuffer buff, final Object value) {
GXDateTime dt;
if (value instanceof GXDateTime) {
dt = (GXDateTime) value;
} else if (value instanceof java.util.Date) {
dt = new GXDateTime((java.util.Date) value);
} else if (value instanceof java.util.Calendar) {
dt = new GXDateTime(((java.util.Calendar) value).getTime());
} else if (value instanceof String) {
DateFormat f = new SimpleDateFormat();
try {
dt = new GXDateTime(f.parse(String.valueOf(value)));
} catch (ParseException e) {
throw new IllegalArgumentException(e.getMessage());
}
} else {
throw new IllegalArgumentException("Invalid date format.");
}
java.util.Calendar tm = java.util.Calendar.getInstance();
tm.setTime(dt.getMeterCalendar().getTime());
// Add additional date time skips.
if (settings != null && !settings.getDateTimeSkips().isEmpty()) {
dt.getSkip().addAll(settings.getDateTimeSkips());
}
// Add year.
if (dt.getSkip().contains(DateTimeSkips.YEAR)) {
buff.setUInt16(0xFFFF);
} else {
buff.setUInt16(tm.get(java.util.Calendar.YEAR));
}
// Add month
if (dt.getExtra().contains(DateTimeExtraInfo.DST_BEGIN)) {
buff.setUInt8(0xFE);
} else if (dt.getExtra().contains(DateTimeExtraInfo.DST_END)) {
buff.setUInt8(0xFD);
} else if (dt.getSkip().contains(DateTimeSkips.MONTH)) {
buff.setUInt8(0xFF);
} else {
buff.setUInt8((tm.get(java.util.Calendar.MONTH) + 1));
}
// Add day
if (dt.getExtra().contains(DateTimeExtraInfo.LAST_DAY)) {
buff.setUInt8(0xFE);
} else if (dt.getExtra().contains(DateTimeExtraInfo.LAST_DAY2)) {
buff.setUInt8(0xFD);
} else if (dt.getSkip().contains(DateTimeSkips.DAY)) {
buff.setUInt8(0xFF);
} else {
buff.setUInt8(tm.get(java.util.Calendar.DATE));
}
if (dt.getSkip().contains(DateTimeSkips.DAY_OF_WEEK)) {
// Week day is not specified.
buff.setUInt8(0xFF);
} else {
int val = tm.get(java.util.Calendar.DAY_OF_WEEK);
if (val == java.util.Calendar.SUNDAY) {
val = 8;
}
buff.setUInt8(val - 1);
}
}
public static GXDateTime getDateTime(final Object value) {
GXDateTime dt;
if (value instanceof GXDateTime) {
dt = (GXDateTime) value;
} else if (value instanceof java.util.Date) {
dt = new GXDateTime((java.util.Date) value);
dt.getSkip().add(DateTimeSkips.MILLISECOND);
} else if (value instanceof java.util.Calendar) {
dt = new GXDateTime((java.util.Calendar) value);
dt.getSkip().add(DateTimeSkips.MILLISECOND);
} else if (value instanceof String) {
DateFormat f = new SimpleDateFormat();
try {
dt = new GXDateTime(f.parse(value.toString()));
dt.getSkip().add(DateTimeSkips.MILLISECOND);
} catch (ParseException e) {
throw new IllegalArgumentException("Invalid date time value." + e.getMessage());
}
} else {
throw new IllegalArgumentException("Invalid date format.");
}
return dt;
}
/**
* Convert date time to DLMS bytes.
*
* @param buff
* Byte buffer where data is write.
* @param value
* Added value.
*/
private static void setDateTime(final GXDLMSSettings settings, final GXByteBuffer buff, final Object value) {
GXDateTime dt = getDateTime(value);
java.util.Calendar tm = dt.getMeterCalendar();
// Add additional date time skips.
if (settings != null && !settings.getDateTimeSkips().isEmpty()) {
dt.getSkip().addAll(settings.getDateTimeSkips());
}
// Add year.
if (dt.getSkip().contains(DateTimeSkips.YEAR)) {
buff.setUInt16(0xFFFF);
} else {
buff.setUInt16(tm.get(java.util.Calendar.YEAR));
}
// Add month
if (dt.getExtra().contains(DateTimeExtraInfo.DST_BEGIN)) {
buff.setUInt8(0xFE);
} else if (dt.getExtra().contains(DateTimeExtraInfo.DST_END)) {
buff.setUInt8(0xFD);
} else if (dt.getSkip().contains(DateTimeSkips.MONTH)) {
buff.setUInt8(0xFF);
} else {
buff.setUInt8((tm.get(java.util.Calendar.MONTH) + 1));
}
// Add day
if (dt.getExtra().contains(DateTimeExtraInfo.LAST_DAY)) {
buff.setUInt8(0xFE);
} else if (dt.getExtra().contains(DateTimeExtraInfo.LAST_DAY2)) {
buff.setUInt8(0xFD);
} else if (dt.getSkip().contains(DateTimeSkips.DAY)) {
buff.setUInt8(0xFF);
} else {
buff.setUInt8(tm.get(java.util.Calendar.DATE));
}
// Day of week.
if (dt.getSkip().contains(DateTimeSkips.DAY_OF_WEEK)) {
buff.setUInt8(0xFF);
} else {
if (dt.getDayOfWeek() == 0) {
int val = tm.get(java.util.Calendar.DAY_OF_WEEK);
if (val == java.util.Calendar.SUNDAY) {
val = 8;
}
buff.setUInt8(val - 1);
} else {
buff.setUInt8(dt.getDayOfWeek());
}
}
// Add time.
if (dt.getSkip().contains(DateTimeSkips.HOUR)) {
buff.setUInt8(0xFF);
} else {
buff.setUInt8(tm.get(java.util.Calendar.HOUR_OF_DAY));
}
if (dt.getSkip().contains(DateTimeSkips.MINUTE)) {
buff.setUInt8(0xFF);
} else {
buff.setUInt8(tm.get(java.util.Calendar.MINUTE));
}
if (dt.getSkip().contains(DateTimeSkips.SECOND)) {
buff.setUInt8(0xFF);
} else {
buff.setUInt8(tm.get(java.util.Calendar.SECOND));
}
if (dt.getSkip().contains(DateTimeSkips.MILLISECOND)) {
// Hundredth of seconds is not used.
buff.setUInt8(0xFF);
} else {
int ms = tm.get(java.util.Calendar.MILLISECOND);
if (ms != 0) {
ms /= 10;
}
buff.setUInt8(ms);
}
// devitation not used.
if (dt.getSkip().contains(DateTimeSkips.DEVIATION)) {
buff.setUInt16(0x8000);
} else {
int deviation =
(dt.getMeterCalendar().get(Calendar.ZONE_OFFSET) + dt.getMeterCalendar().get(Calendar.DST_OFFSET))
/ 60000;
if (settings != null && settings.getUseUtc2NormalTime()) {
buff.setUInt16(deviation);
} else {
buff.setUInt16(-deviation);
}
}
// Add clock_status
if (!dt.getSkip().contains(DateTimeSkips.STATUS)) {
if ((dt.getMeterCalendar().getTimeZone().inDaylightTime(dt.getMeterCalendar().getTime())
|| dt.getStatus().contains(ClockStatus.DAYLIGHT_SAVE_ACTIVE))) {
buff.setUInt8(ClockStatus.toInteger(dt.getStatus()) | ClockStatus.DAYLIGHT_SAVE_ACTIVE.getValue());
} else {
buff.setUInt8(ClockStatus.toInteger(dt.getStatus()));
}
} else {
// Status is not used.
buff.setUInt8(0xFF);
}
}
/**
* Convert BCD to DLMS bytes.
*
* @param buff
* Byte buffer where data is write.
* @param value
* Added value.
*/
private static void setBcd(final GXByteBuffer buff, final Object value) {
// Standard supports only size of byte.
buff.setUInt8(((Number) value).byteValue());
}
/**
* Convert Array to DLMS bytes.
*
* @param buff
* Byte buffer where data is write.
* @param value
* Added value.
*/
private static void setArray(final GXDLMSSettings settings, final GXByteBuffer buff, final Object value) {
if (value != null) {
List> arr;
if (value instanceof List>) {
arr = ((List>) value);
} else {
List tmp = new ArrayList();
tmp.addAll(Arrays.asList((Object[]) value));
arr = tmp;
}
int len = arr.size();
setObjectCount(len, buff);
for (Object it : arr) {
setData(settings, buff, GXDLMSConverter.getDLMSDataType(it), it);
}
} else {
setObjectCount(0, buff);
}
}
/**
* Split string to array.
*
* @param str
* String to split.
* @param separators
* Separators.
* @return Split values.
*/
public static List split(final String str, final char[] separators) {
int lastPos = 0;
List arr = new ArrayList();
for (int pos = 0; pos != str.length(); ++pos) {
char ch = str.charAt(pos);
for (char sep : separators) {
if (ch == sep) {
if (lastPos != pos) {
arr.add(str.substring(lastPos, pos));
}
lastPos = pos + 1;
break;
}
}
}
if (lastPos != str.length()) {
arr.add(str.substring(lastPos, str.length()));
}
return arr;
}
/**
* Split string to array.
*
* @param str
* String to split.
* @param separator
* Separator.
* @return Split values.
*/
public static List split(final String str, final char separator) {
List arr = new ArrayList();
int pos = 0, lastPos = 0;
while ((pos = str.indexOf(separator, lastPos)) != -1) {
arr.add(str.substring(lastPos, pos));
lastPos = pos + 1;
}
if (str.length() > lastPos) {
arr.add(str.substring(lastPos));
} else {
arr.add("");
}
return arr;
}
/**
* Split string to array.
*
* @param str
* String to split.
* @param separator
* Separator.
* @return Split values.
*/
public static List split(final String str, final String separator) {
List arr = new ArrayList();
int pos = 0, lastPos = 0;
while ((pos = str.indexOf(separator, lastPos)) != -1) {
arr.add(str.substring(lastPos, pos));
lastPos = pos + separator.length();
}
if (str.length() > lastPos) {
arr.add(str.substring(lastPos));
} else {
arr.add("");
}
return arr;
}
/**
* Convert Octet string to DLMS bytes.
*
* @param buff
* Byte buffer where data is write.
* @param value
* Added value.
*/
private static void setOctetString(final GXByteBuffer buff, final Object value) {
if (value instanceof String) {
byte[] tmp = GXCommon.hexToBytes((String) value);
setObjectCount(tmp.length, buff);
buff.set(tmp);
} else if (value instanceof byte[]) {
setObjectCount(((byte[]) value).length, buff);
buff.set((byte[]) value);
} else if (value == null) {
setObjectCount(0, buff);
} else {
throw new IllegalArgumentException("Invalid data type.");
}
}
/**
* Convert UTF string to DLMS bytes.
*
* @param buff
* Byte buffer where data is write.
* @param value
* Added value.
*/
private static void setUtfString(final GXByteBuffer buff, final Object value) {
if (value != null) {
byte[] tmp = String.valueOf(value).getBytes(StandardCharsets.UTF_8);
setObjectCount(tmp.length, buff);
buff.set(tmp);
} else {
buff.setUInt8(0);
}
}
/**
* Convert ASCII string to DLMS bytes.
*
* @param buff
* Byte buffer where data is write.
* @param value
* Added value.
*/
private static void setString(final GXByteBuffer buff, final Object value) {
if (value != null) {
String str = String.valueOf(value);
setObjectCount(str.length(), buff);
buff.set(GXCommon.getBytes(str));
} else {
buff.setUInt8(0);
}
}
/**
* Convert Bit string to DLMS bytes.
*
* @param buff
* Byte buffer where data is write.
* @param val1
* Added value.
* @param addCount
* Is bit count added.
*/
public static void setBitString(final GXByteBuffer buff, final Object val1, final boolean addCount) {
Object value = val1;
if (value instanceof GXBitString) {
value = ((GXBitString) value).getValue();
}
if (value instanceof String) {
byte val = 0;
String str = (String) value;
if (addCount) {
setObjectCount(str.length(), buff);
}
int index = 7;
for (int pos = 0; pos != str.length(); ++pos) {
char it = str.charAt(pos);
if (it == '1') {
val |= (byte) (1 << index);
} else if (it != '0') {
throw new IllegalArgumentException("Not a bit string.");
}
--index;
if (index == -1) {
index = 7;
buff.setUInt8(val);
val = 0;
}
}
if (index != 7) {
buff.setUInt8(val);
}
} else if (value instanceof byte[]) {
byte[] arr = (byte[]) value;
setObjectCount(8 * arr.length, buff);
buff.set(arr);
} else if (value instanceof Byte) {
setObjectCount(8, buff);
buff.setUInt8(((Byte) value).byteValue());
} else if (value == null) {
buff.setUInt8(0);
} else {
throw new IllegalArgumentException("BitString must give as string.");
}
}
/**
* Get data type in bytes.
*
* @param type
* Data type.
* @return Size of data type in bytes.
*/
public static int getDataTypeSize(final DataType type) {
int size = -1;
switch (type) {
case BCD:
size = 1;
break;
case BOOLEAN:
size = 1;
break;
case DATE:
size = 5;
break;
case DATETIME:
size = 12;
break;
case ENUM:
size = 1;
break;
case FLOAT32:
size = 4;
break;
case FLOAT64:
size = 8;
break;
case INT16:
size = 2;
break;
case INT32:
size = 4;
break;
case INT64:
size = 8;
break;
case INT8:
size = 1;
break;
case NONE:
size = 0;
break;
case TIME:
size = 4;
break;
case UINT16:
size = 2;
break;
case UINT32:
size = 4;
break;
case UINT64:
size = 8;
break;
case UINT8:
size = 1;
break;
default:
break;
}
return size;
}
/**
* Convert logical name byte array to string.
*
* @param value
* Logical name as a byte array.
* @return Logical name as a string.
*/
public static String toLogicalName(final Object value) {
if (value instanceof byte[]) {
byte[] buff = (byte[]) value;
if (buff.length == 0) {
buff = new byte[6];
}
if (buff.length == 6) {
return (buff[0] & 0xFF) + "." + (buff[1] & 0xFF) + "." + (buff[2] & 0xFF) + "." + (buff[3] & 0xFF) + "."
+ (buff[4] & 0xFF) + "." + (buff[5] & 0xFF);
}
throw new IllegalArgumentException("Invalid Logical name.");
}
return (String) value;
}
/**
* Convert logical name to byte array.
*
* @param value
* Logical name.
* @return Logical name as byte array.
*/
public static byte[] logicalNameToBytes(final String value) {
if (value == null || value.length() == 0) {
return new byte[6];
}
List items = GXCommon.split(value, '.');
// If data is string.
if (items.size() != 6) {
throw new IllegalArgumentException("Invalid Logical name.");
}
byte[] buff = new byte[6];
byte pos = 0;
for (String it : items) {
int v = Integer.parseInt(it);
if (v < 0 || v > 255) {
throw new IllegalArgumentException("Invalid Logical name.");
}
buff[pos] = (byte) v;
++pos;
}
return buff;
}
/**
* Convert integer list to array.
*
* @param list
* Integer list to convert.
* @return Integer array.
*/
public static int[] toIntArray(final List list) {
int[] ret = new int[list.size()];
int pos = 0;
for (Integer it : list) {
ret[pos] = it.intValue();
++pos;
}
return ret;
}
/**
* Convert short list to array.
*
* @param list
* Integer list to convert.
* @return Integer array.
*/
public static short[] toShortArray(final List list) {
short[] ret = new short[list.size()];
int pos = 0;
for (Short it : list) {
ret[pos] = it.shortValue();
++pos;
}
return ret;
}
public static Date getGeneralizedTime(final String dateString) {
int year, month, day, hour, minute, second = 0;
Calendar calendar;
year = Integer.parseInt(dateString.substring(0, 4));
month = Integer.parseInt(dateString.substring(4, 6)) - 1;
day = Integer.parseInt(dateString.substring(6, 8));
hour = Integer.parseInt(dateString.substring(8, 10));
minute = Integer.parseInt(dateString.substring(10, 12));
// If UTC time.
if (dateString.endsWith("Z")) {
if (dateString.length() > 13) {
second = Integer.parseInt(dateString.substring(12, 14));
}
calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
calendar.set(year, month, day, hour, minute, second);
long v = calendar.getTimeInMillis();
calendar = Calendar.getInstance();
calendar.setTimeInMillis(v);
calendar.set(Calendar.MILLISECOND, 0);
return calendar.getTime();
} else {
if (dateString.length() > 17) {
second = Integer.parseInt(dateString.substring(12, 14));
}
calendar = Calendar.getInstance(
TimeZone.getTimeZone("GMT" + dateString.substring(dateString.length() - 4, dateString.length())));
}
calendar.set(year, month, day, hour, minute, second);
calendar.set(Calendar.MILLISECOND, 0);
return calendar.getTime();
}
public static String generalizedTime(final GXDateTime date) {
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
calendar.setTimeInMillis(date.getMeterCalendar().getTimeInMillis());
StringBuilder sb = new StringBuilder();
sb.append(GXCommon.integerString(calendar.get(Calendar.YEAR), 4));
sb.append(GXCommon.integerString(1 + calendar.get(Calendar.MONTH), 2));
sb.append(GXCommon.integerString(calendar.get(Calendar.DAY_OF_MONTH), 2));
sb.append(GXCommon.integerString(calendar.get(Calendar.HOUR_OF_DAY), 2));
sb.append(GXCommon.integerString(calendar.get(Calendar.MINUTE), 2));
sb.append(GXCommon.integerString(calendar.get(Calendar.SECOND), 2));
// UTC time.
sb.append("Z");
return sb.toString();
}
/**
* Check is string ASCII string.
*
* @param value
* ASCII string.
* @return Is ASCII string
*/
public static boolean isAscii(final String value) {
return StandardCharsets.US_ASCII.newEncoder().canEncode(value);
}
// Reserved for internal use.
public static short swapBits(short value) {
short ret = 0;
for (int pos = 0; pos != 8; ++pos) {
ret = (short) ((ret << 1) | (value & 0x01));
value = (short) (value >> 1);
}
return ret;
}
/**
* Encrypt Flag name to two bytes.
*
* @param flagName
* 3 letter Flag name.
* @return Encrypted Flag name.
*/
@SuppressWarnings("unused")
public static int encryptManufacturer(final String flagName) {
if (flagName.length() != 3) {
throw new IllegalArgumentException("Invalid Flag name.");
}
int value = ((flagName.charAt(0) - 0x40) & 0x1f);
value <<= 5;
value += ((flagName.charAt(0) - 0x40) & 0x1f);
value <<= 5;
value += ((flagName.charAt(0) - 0x40) & 0x1f);
return value;
}
/**
* Decrypt two bytes to Flag name.
*
* @param value
* Encrypted Flag value.
* @return Flag name.
*/
public static String decryptManufacturer(final int value) {
int tmp = (value >> 8 | value << 8);
char c = (char) ((tmp & 0x1f) + 0x40);
tmp = (tmp >> 5);
char c1 = (char) ((tmp & 0x1f) + 0x40);
tmp = (tmp >> 5);
char c2 = (char) ((tmp & 0x1f) + 0x40);
return new String(new char[] { c2, c1, c });
}
static String idisSystemTitleToString(final byte[] st, final boolean addComments) {
StringBuilder sb = new StringBuilder();
String newline = System.getProperty("line.separator");
sb.append("IDIS system title:");
sb.append(newline);
sb.append("Manufacturer Code: ");
sb.append(new String(new char[] { (char) st[0], (char) st[1], (char) st[2] }));
sb.append(newline);
sb.append(" Function type: ");
int ft = st[4] >> 4;
boolean add = false;
if ((ft & 0x1) != 0) {
sb.append("Disconnector");
add = true;
}
if ((ft & 0x2) != 0) {
if (add) {
sb.append(", ");
}
add = true;
sb.append("Load Management");
}
if ((ft & 0x4) != 0) {
if (add) {
sb.append(", ");
}
sb.append("Multi Utility");
}
// Serial number;
int sn = (st[4] & 0xF) << 24;
sn |= (st[5] << 16);
sn |= (st[6] << 8);
sn |= (st[7]);
sb.append(newline);
sb.append("Serial number: ");
sb.append(String.valueOf(sn));
sb.append(newline);
return sb.toString();
}
static String dlmsSystemTitleToString(final byte[] st, final boolean addComments) {
String newline = System.getProperty("line.separator");
StringBuilder sb = new StringBuilder();
sb.append(newline);
sb.append("DLMS system title:");
sb.append(newline);
sb.append("Manufacturer Code: ");
sb.append(new String(new char[] { (char) st[0], (char) st[1], (char) st[2] }));
sb.append(newline);
sb.append("Serial number: ");
sb.append(new String(new char[] { (char) st[3], (char) st[4], (char) st[5], (char) st[6], (char) st[7] }));
sb.append(newline);
return sb.toString();
}
static String uniSystemTitleToString(final byte[] st, final boolean addComments) {
String newline = System.getProperty("line.separator");
StringBuilder sb = new StringBuilder();
if (addComments) {
sb.append(newline);
sb.append("UNI/TS system title:");
sb.append(newline);
sb.append("Manufacturer: ");
int m = (st[0] << 8 | st[1]);
sb.append(decryptManufacturer(m));
sb.append(newline);
sb.append("Serial number: ");
sb.append(toHex(new byte[] { st[7], st[6], st[5], st[4], st[3], st[2] }, false));
sb.append(newline);
} else {
int m = (st[0] << 8 | st[1]);
sb.append(decryptManufacturer(m));
sb.append(toHex(new byte[] { st[7], st[6], st[5], st[4], st[3], st[2] }, false));
}
return sb.toString();
}
private static boolean IsT1(final byte value) {
return value > 98 && value < 104;
}
private static boolean IsT2(final byte value) {
return (value & 0xf0) != 0;
}
/**
* Convert system title to string.
*
* @param standard
* Used standard.
* @param st
* System title.
* @param addComments
* Are comments added.
* @return System title in string format.
*/
public static String systemTitleToString(final Standard standard, final byte[] st, final boolean addComments) {
if (st == null || st.length != 8) {
return "";
}
if (standard == Standard.ITALY || !Character.isLetter(st[0]) || !Character.isLetter(st[1])
|| !Character.isLetter(st[2])) {
return uniSystemTitleToString(st, addComments);
}
if (standard == Standard.IDIS || (IsT1(st[3]) && IsT2(st[4]))) {
return idisSystemTitleToString(st, addComments);
}
return dlmsSystemTitleToString(st, addComments);
}
public static boolean isCiphered(final short cmd) {
switch (cmd) {
case Command.GLO_READ_REQUEST:
case Command.GLO_WRITE_REQUEST:
case Command.GLO_GET_REQUEST:
case Command.GLO_SET_REQUEST:
case Command.GLO_READ_RESPONSE:
case Command.GLO_WRITE_RESPONSE:
case Command.GLO_GET_RESPONSE:
case Command.GLO_SET_RESPONSE:
case Command.GLO_METHOD_REQUEST:
case Command.GLO_METHOD_RESPONSE:
case Command.DED_GET_REQUEST:
case Command.DED_SET_REQUEST:
case Command.DED_READ_RESPONSE:
case Command.DED_GET_RESPONSE:
case Command.DED_SET_RESPONSE:
case Command.DED_METHOD_REQUEST:
case Command.DED_METHOD_RESPONSE:
case Command.GENERAL_GLO_CIPHERING:
case Command.GENERAL_DED_CIPHERING:
case Command.AARE:
case Command.AARQ:
case Command.GLO_CONFIRMED_SERVICE_ERROR:
case Command.DED_CONFIRMED_SERVICE_ERROR:
case Command.GENERAL_CIPHERING:
case Command.RELEASE_REQUEST:
case Command.GENERAL_SIGNING:
return true;
default:
return false;
}
}
/**
* Encrypt or decrypt the data using external Hardware Security Module.
*
* @param certificateType
* Certificate type.
* @param Data
* Data.
* @param encrypt
* Is data encrypted or decrypted.
* @param keyType
* Key type.
* @return
*/
public static byte[] crypt(final GXDLMSSettings settings, final CertificateType certificateType, final byte[] Data,
final boolean encrypt, final CryptoKeyType keyType, final int command, final Security security,
final SecuritySuite securitySuite, final long invocationCounter) {
if (settings.getCryptoNotifier() != null) {
GXCryptoKeyParameter args = new GXCryptoKeyParameter();
args.setEncrypt(encrypt);
args.setKeyType(keyType);
args.setCommand(command);
args.setSystemTitle(settings.getCipher().getSystemTitle());
args.setRecipientSystemTitle(settings.getSourceSystemTitle());
args.setCertificateType(certificateType);
args.setInvocationCounter(invocationCounter);
args.setSecurity(security);
args.setSecuritySuite(securitySuite);
args.setSecurityPolicy(settings.getCipher().getSecurityPolicy());
if (encrypt) {
args.setPlainText(Data);
} else {
args.setEncrypted(Data);
}
args.setAuthenticationKey(settings.getCipher().getAuthenticationKey());
if (settings.getCipher().getDedicatedKey() != null && settings.getCipher().getDedicatedKey().length == 16
&& (settings.getConnected() & ConnectionState.DLMS) != 0) {
args.setBlockCipherKey(settings.getCipher().getDedicatedKey());
} else {
args.setBlockCipherKey(settings.getCipher().getBlockCipherKey());
}
settings.getCryptoNotifier().onCrypto(settings.getCryptoNotifier(), args);
if (encrypt) {
return args.getEncrypted();
} else {
return args.getPlainText();
}
}
return null;
}
}