This is an automated email from the ASF dual-hosted git repository. sruehl pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-plc4x.git
The following commit(s) were added to refs/heads/master by this push: new 4750820 [General/MODBUS/ADS] Fixed date/time support 4750820 is described below commit 4750820b85638df4f2104159ed02fc4f6f1c3a97 Author: Sebastian Rühl <sru...@apache.org> AuthorDate: Thu Sep 27 16:38:10 2018 +0200 [General/MODBUS/ADS] Fixed date/time support --- .../apache/plc4x/java/ads/model/AdsDataType.java | 9 ++-- .../plc4x/java/ads/model/AdsPlcFieldHandler.java | 58 ++++++++++++++++++-- .../ads/protocol/util/LittleEndianDecoder.java | 8 ++- .../ads/protocol/util/LittleEndianEncoder.java | 62 +++++++++++++++++----- .../java/ads/protocol/Plc4x2AdsProtocolTest.java | 45 +++++++++++----- .../java/base/messages/DefaultPlcWriteRequest.java | 2 +- .../base/protocol/Plc4XSupportedDataTypes.java | 32 +++++++---- .../java/modbus/netty/Plc4XModbusProtocolTest.java | 1 - 8 files changed, 168 insertions(+), 49 deletions(-) diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/AdsDataType.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/AdsDataType.java index b9859f5..e6cf4c2 100644 --- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/AdsDataType.java +++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/AdsDataType.java @@ -19,6 +19,9 @@ package org.apache.plc4x.java.ads.model; import java.time.Duration; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.temporal.ChronoUnit; /** * Documentation can be found here: @@ -191,15 +194,15 @@ public enum AdsDataType { * <p> * TOD#00:00 TOD#1193:02:47.295 32 Bit *///TODO: strange maximum - TIME_OF_DAY(0, Duration.ofHours(23).plusMinutes(59).plusSeconds(59).plusMillis(999).toMillis(), 32), + TIME_OF_DAY(0, ChronoUnit.MILLIS.between(LocalTime.of(0, 0), LocalTime.of(23, 59, 59)), 32), /** * DATE * Date. The most significant digit is one second. The data type is handled internally like DWORD. * <p> * Type Lower bound Upper bound Memory use * DATE D#1970-01-01 D#2106-02-06 32 Bit - *///TODO: calculate max - DATE(0, -1, 32), + */ + DATE(0, ChronoUnit.SECONDS.between(LocalDateTime.of(1970, 1, 1, 0, 0), LocalDateTime.of(2106, 2, 6, 0, 0)), 32), /** * DATE_AND_TIME * DT diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/AdsPlcFieldHandler.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/AdsPlcFieldHandler.java index df751cb..bb9be24 100644 --- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/AdsPlcFieldHandler.java +++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/model/AdsPlcFieldHandler.java @@ -27,10 +27,14 @@ import org.apache.plc4x.java.base.messages.items.*; import java.math.BigDecimal; import java.math.BigInteger; import java.nio.charset.Charset; +import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.Arrays; import java.util.BitSet; import java.util.LinkedList; import java.util.List; +import java.util.stream.Collectors; // TODO: implement me acording to ads. currently copy pasta from S7 // Use endian decoders. @@ -551,7 +555,7 @@ public class AdsPlcFieldHandler extends DefaultPlcFieldHandler { case STRUCT: case ALIAS: case SUB_RANGE_DATA_TYPE: - return internalEncodeTemporal(field, values); + return internalTimeTemporal(field, values); case UNKNOWN: default: throw new PlcRuntimeException("Invalid encoder for type " + adsField.getAdsDataType().name()); @@ -602,7 +606,7 @@ public class AdsPlcFieldHandler extends DefaultPlcFieldHandler { case STRUCT: case ALIAS: case SUB_RANGE_DATA_TYPE: - return internalEncodeTemporal(field, values); + return internalDateTemporal(field, values); case UNKNOWN: default: throw new PlcRuntimeException("Invalid encoder for type " + adsField.getAdsDataType().name()); @@ -653,7 +657,7 @@ public class AdsPlcFieldHandler extends DefaultPlcFieldHandler { case STRUCT: case ALIAS: case SUB_RANGE_DATA_TYPE: - return internalEncodeTemporal(field, values); + return internalDateTimeTemporal(field, values); case UNKNOWN: default: throw new PlcRuntimeException("Invalid encoder for type " + adsField.getAdsDataType().name()); @@ -930,16 +934,60 @@ public class AdsPlcFieldHandler extends DefaultPlcFieldHandler { return new DefaultStringFieldItem(stringValues.toArray(new String[0])); } - private FieldItem internalEncodeTemporal(PlcField field, Object[] values) { + private FieldItem internalTimeTemporal(PlcField field, Object[] values) { AdsField adsField = (AdsField) field; switch (adsField.getAdsDataType()) { case TIME: case DATE: case DATE_AND_TIME: - return new DefaultLocalDateTimeFieldItem((LocalDateTime[]) values); + break; + default: + throw new IllegalArgumentException( + "Cannot assign temporal values to " + adsField.getAdsDataType().name() + " fields."); + } + // TODO: support other types + List<LocalTime> localTimeValues = Arrays.stream(values) + .filter(LocalTime.class::isInstance) + .map(LocalTime.class::cast) + .collect(Collectors.toList()); + return new DefaultLocalTimeFieldItem(localTimeValues.toArray(new LocalTime[0])); + } + + private FieldItem internalDateTemporal(PlcField field, Object[] values) { + AdsField adsField = (AdsField) field; + switch (adsField.getAdsDataType()) { + case TIME: + case DATE: + case DATE_AND_TIME: + break; + default: + throw new IllegalArgumentException( + "Cannot assign temporal values to " + adsField.getAdsDataType().name() + " fields."); + } + // TODO: support other types + List<LocalDate> localDateValues = Arrays.stream(values) + .filter(LocalDate.class::isInstance) + .map(LocalDate.class::cast) + .collect(Collectors.toList()); + return new DefaultLocalDateFieldItem(localDateValues.toArray(new LocalDate[0])); + } + + private FieldItem internalDateTimeTemporal(PlcField field, Object[] values) { + AdsField adsField = (AdsField) field; + switch (adsField.getAdsDataType()) { + case TIME: + case DATE: + case DATE_AND_TIME: + break; default: throw new IllegalArgumentException( "Cannot assign temporal values to " + adsField.getAdsDataType().name() + " fields."); } + // TODO: support other types + List<LocalDateTime> localDateTimeValues = Arrays.stream(values) + .filter(LocalDateTime.class::isInstance) + .map(LocalDateTime.class::cast) + .collect(Collectors.toList()); + return new DefaultLocalDateTimeFieldItem(localDateTimeValues.toArray(new LocalDateTime[0])); } } diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianDecoder.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianDecoder.java index 8d37edb..e09b508 100644 --- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianDecoder.java +++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianDecoder.java @@ -317,7 +317,9 @@ public class LittleEndianDecoder { LinkedList<LocalDate> values = new LinkedList<>(); while (wrappedBuffer.isReadable()) { long aByte = wrappedBuffer.readUnsignedIntLE(); - values.offer(LocalDate.ofEpochDay(aByte)); + // TODO: where to get the zone offset from + LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(aByte, 0, ZoneOffset.UTC); + values.offer(localDateTime.toLocalDate()); } return new DefaultLocalDateFieldItem(values.toArray(new LocalDate[0])); } @@ -325,7 +327,9 @@ public class LittleEndianDecoder { LinkedList<LocalDateTime> values = new LinkedList<>(); while (wrappedBuffer.isReadable()) { long aByte = wrappedBuffer.readUnsignedIntLE(); - values.offer(LocalDateTime.ofEpochSecond(aByte, 0, ZoneOffset.UTC)); + // TODO: where to get the zone offset from + LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(aByte, 0, ZoneOffset.UTC); + values.offer(localDateTime); } return new DefaultLocalDateTimeFieldItem(values.toArray(new LocalDateTime[0])); } diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianEncoder.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianEncoder.java index a039766..44b1247 100644 --- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianEncoder.java +++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianEncoder.java @@ -19,7 +19,6 @@ package org.apache.plc4x.java.ads.protocol.util; import org.apache.commons.lang3.ArrayUtils; -import org.apache.plc4x.java.ads.api.commands.types.TimeStamp; import org.apache.plc4x.java.ads.model.AdsDataType; import org.apache.plc4x.java.api.exceptions.PlcProtocolException; import org.apache.plc4x.java.api.exceptions.PlcRuntimeException; @@ -29,9 +28,9 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.math.BigInteger; import java.nio.charset.Charset; +import java.time.*; +import java.time.temporal.ChronoUnit; import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; import java.util.stream.Stream; // TODO: we might user ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN).putInt(port).asArray() etc @@ -59,8 +58,12 @@ public class LittleEndianEncoder { result = encodeLong(adsDataType, Arrays.stream(values).map(Long.class::cast)); } else if (valueType == BigInteger.class) { result = encodeBigInteger(adsDataType, Arrays.stream(values).map(BigInteger.class::cast)); - } else if (valueType == Calendar.class || Calendar.class.isAssignableFrom(valueType)) { - result = encodeCalendar(adsDataType, Arrays.stream(values).map(Calendar.class::cast)); + } else if (valueType == LocalTime.class) { + result = encodeLocalTime(adsDataType, Arrays.stream(values).map(LocalTime.class::cast)); + } else if (valueType == LocalDate.class) { + result = encodeLocalDate(adsDataType, Arrays.stream(values).map(LocalDate.class::cast)); + } else if (valueType == LocalDateTime.class) { + result = encodeLocalDateTime(adsDataType, Arrays.stream(values).map(LocalDateTime.class::cast)); } else if (valueType == Float.class) { result = encodeFloat(adsDataType, Arrays.stream(values).map(Float.class::cast)); } else if (valueType == Double.class) { @@ -184,14 +187,47 @@ public class LittleEndianEncoder { }); } - private static Stream<byte[]> encodeCalendar(AdsDataType adsDataType, Stream<Calendar> calendarStream) { - return calendarStream - .map(Calendar.class::cast) - .map(Calendar::getTime) - .map(Date::getTime) - .map(BigInteger::valueOf) - .map(TimeStamp::javaToWinTime) - .map(BigInteger::longValue) + private static Stream<byte[]> encodeLocalTime(AdsDataType adsDataType, Stream<LocalTime> localTimeStream) { + return localTimeStream + .map(localTime -> ChronoUnit.MILLIS.between(LocalTime.of(0, 0), localTime)) + .peek(value -> checkBound(adsDataType, value)) + .map(time -> new byte[]{ + (byte) (time & 0x00000000_000000ffL), + (byte) ((time & 0x00000000_0000ff00L) >> 8), + (byte) ((time & 0x00000000_00ff0000L) >> 16), + (byte) ((time & 0x00000000_ff000000L) >> 24), + + (byte) ((time & 0x000000ff_00000000L) >> 32), + (byte) ((time & 0x0000ff00_00000000L) >> 40), + (byte) ((time & 0x00ff0000_00000000L) >> 48), + (byte) ((time & 0xff000000_00000000L) >> 56), + }); + } + + private static Stream<byte[]> encodeLocalDate(AdsDataType adsDataType, Stream<LocalDate> localDateStream) { + return localDateStream + // TODO: fixme: which offset should we use? + .map(localDate -> localDate.atTime(0, 0).toInstant(ZoneOffset.UTC)) + .map(Instant::getEpochSecond) + .peek(value -> checkBound(adsDataType, value)) + .map(time -> new byte[]{ + (byte) (time & 0x00000000_000000ffL), + (byte) ((time & 0x00000000_0000ff00L) >> 8), + (byte) ((time & 0x00000000_00ff0000L) >> 16), + (byte) ((time & 0x00000000_ff000000L) >> 24), + + (byte) ((time & 0x000000ff_00000000L) >> 32), + (byte) ((time & 0x0000ff00_00000000L) >> 40), + (byte) ((time & 0x00ff0000_00000000L) >> 48), + (byte) ((time & 0xff000000_00000000L) >> 56), + }); + } + + private static Stream<byte[]> encodeLocalDateTime(AdsDataType adsDataType, Stream<LocalDateTime> localDateTimeStream) { + return localDateTimeStream + // TODO: fixme: which offset should we use? + .map(localDateTime -> localDateTime.toInstant(ZoneOffset.UTC)) + .map(Instant::getEpochSecond) .peek(value -> checkBound(adsDataType, value)) .map(time -> new byte[]{ (byte) (time & 0x00000000_000000ffL), diff --git a/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/protocol/Plc4x2AdsProtocolTest.java b/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/protocol/Plc4x2AdsProtocolTest.java index a97be10..95c6628 100644 --- a/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/protocol/Plc4x2AdsProtocolTest.java +++ b/plc4j/protocols/ads/src/test/java/org/apache/plc4x/java/ads/protocol/Plc4x2AdsProtocolTest.java @@ -46,7 +46,11 @@ import org.slf4j.LoggerFactory; import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import java.math.BigDecimal; import java.math.BigInteger; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; @@ -99,7 +103,7 @@ public class Plc4x2AdsProtocolTest { Invoke invokeId = Invoke.of(2); return streamOfLittleEndianDataTypePairs() // TODO: calender doesnt work anymore so we might need to adjust the generator above. - .filter(o -> o.getDataTypeClass() != GregorianCalendar.class) + .filter(o -> o.getDataTypeClass() != LocalDateTime.class) .filter(o -> o.getDataTypeClass() != Byte[].class) .filter(o -> o.getDataTypeClass() != byte[].class) .map(Plc4x2AdsProtocolTest::mapToAdsDataType) @@ -121,21 +125,24 @@ public class Plc4x2AdsProtocolTest { )) .flatMap(stream -> stream) // TODO: request doesn't know its type anymore... fixme - .map(pair -> new Object[]{Object.class.getSimpleName(), pair.left, pair.left.getResponseFuture(), pair.left.getRequest().getClass().getSimpleName(), pair.right, pair.right.getClass().getSimpleName()}).collect(Collectors.toList()); + .map(pair -> new Object[]{"???", pair.left, pair.left.getResponseFuture(), pair.left.getRequest().getClass().getSimpleName(), pair.right, pair.right.getClass().getSimpleName()}).collect(Collectors.toList()); } private static AdsDataTypePair mapToAdsDataType(Plc4XSupportedDataTypes.DataTypePair dataTypePair) { - // TODO: check usefull type mapping Map<Class<?>, AdsDataType> dataTypeMap = new HashMap<>(); dataTypeMap.put(Boolean.class, AdsDataType.BOOL); dataTypeMap.put(Byte.class, AdsDataType.BYTE); dataTypeMap.put(Short.class, AdsDataType.INT); - dataTypeMap.put(Float.class, AdsDataType.REAL); dataTypeMap.put(Integer.class, AdsDataType.INT32); - dataTypeMap.put(Double.class, AdsDataType.LREAL); + dataTypeMap.put(Long.class, AdsDataType.INT64); dataTypeMap.put(BigInteger.class, AdsDataType.INT64); - dataTypeMap.put(Calendar.class, AdsDataType.DATE_AND_TIME); + dataTypeMap.put(Float.class, AdsDataType.REAL); + dataTypeMap.put(Double.class, AdsDataType.LREAL); + dataTypeMap.put(BigDecimal.class, AdsDataType.LREAL); dataTypeMap.put(String.class, AdsDataType.STRING); + dataTypeMap.put(LocalTime.class, AdsDataType.TIME); + dataTypeMap.put(LocalDate.class, AdsDataType.DATE); + dataTypeMap.put(LocalDateTime.class, AdsDataType.DATE_AND_TIME); dataTypeMap.put(byte[].class, AdsDataType.BYTE); dataTypeMap.put(Byte[].class, AdsDataType.BYTE); return new AdsDataTypePair(dataTypePair, dataTypeMap.getOrDefault(dataTypePair.getDataTypeClass(), AdsDataType.BYTE)); @@ -149,10 +156,6 @@ public class Plc4x2AdsProtocolTest { super(dataTypePair.getDataTypePair()); this.adsDataType = adsDataType; } - - private AdsDataType getAdsDataType() { - return adsDataType; - } } @Before @@ -182,16 +185,30 @@ public class Plc4x2AdsProtocolTest { assertThat(value, equalTo(new byte[]{0x1})); } else if (payloadClazzName.equals(Short.class.getSimpleName())) { assertThat(value, equalTo(new byte[]{0x1, 0x0})); - } else if (payloadClazzName.equals(GregorianCalendar.class.getSimpleName())) { - assertThat(value, equalTo(new byte[]{0x0, (byte) 0x80, 0x3E, 0x15, (byte) 0xAB, 0X47, (byte) 0xFC, 0x28})); + } else if (payloadClazzName.equals(Integer.class.getSimpleName())) { + assertThat(value, equalTo(new byte[]{0x1, 0x0, 0x0, 0x0})); + } else if (payloadClazzName.equals(Long.class.getSimpleName())) { + assertThat(value, equalTo(new byte[]{0x1, 0x0, 0x0, 0x0})); + } else if (payloadClazzName.equals(BigInteger.class.getSimpleName())) { + assertThat(value, equalTo(new byte[]{0x1, 0x0, 0x0, 0x0})); } else if (payloadClazzName.equals(Float.class.getSimpleName())) { assertThat(value, equalTo(new byte[]{0x0, 0x0, (byte) 0x80, 0x3F})); } else if (payloadClazzName.equals(Double.class.getSimpleName())) { assertThat(value, equalTo(new byte[]{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, (byte) 0xF0, 0x3F})); - } else if (payloadClazzName.equals(Integer.class.getSimpleName())) { - assertThat(value, equalTo(new byte[]{0x1, 0x0, 0x0, 0x0})); + } else if (payloadClazzName.equals(BigDecimal.class.getSimpleName())) { + assertThat(value, equalTo(new byte[]{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, (byte) 0xF0, 0x3F})); } else if (payloadClazzName.equals(String.class.getSimpleName())) { assertThat(value, equalTo(new byte[]{0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x00})); + } else if (payloadClazzName.equals(LocalTime.class.getSimpleName())) { + assertThat(value, equalTo(new byte[]{0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x00})); + } else if (payloadClazzName.equals(LocalDate.class.getSimpleName())) { + assertThat(value, equalTo(new byte[]{0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x00})); + } else if (payloadClazzName.equals(LocalDateTime.class.getSimpleName())) { + assertThat(value, equalTo(new byte[]{0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x00})); + } else if (payloadClazzName.equals(byte[].class.getSimpleName())) { + assertThat(value, equalTo(new byte[]{0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x00})); + } else if (payloadClazzName.equals(Byte[].class.getSimpleName())) { + assertThat(value, equalTo(new byte[]{0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x00})); } } } diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcWriteRequest.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcWriteRequest.java index d7e4086..c78ff08 100644 --- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcWriteRequest.java +++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcWriteRequest.java @@ -121,8 +121,8 @@ public class DefaultPlcWriteRequest implements InternalPlcWriteRequest, Internal handlerMap.put(BigInteger.class, fieldHandler::encodeBigInteger); handlerMap.put(Long.class, fieldHandler::encodeLong); handlerMap.put(Float.class, fieldHandler::encodeFloat); - handlerMap.put(BigDecimal.class, fieldHandler::encodeBigDecimal); handlerMap.put(Double.class, fieldHandler::encodeDouble); + handlerMap.put(BigDecimal.class, fieldHandler::encodeBigDecimal); handlerMap.put(String.class, fieldHandler::encodeString); handlerMap.put(LocalTime.class, fieldHandler::encodeTime); handlerMap.put(LocalDate.class, fieldHandler::encodeDate); diff --git a/plc4j/protocols/driver-bases/test/src/main/java/org/apache/plc4x/java/base/protocol/Plc4XSupportedDataTypes.java b/plc4j/protocols/driver-bases/test/src/main/java/org/apache/plc4x/java/base/protocol/Plc4XSupportedDataTypes.java index 2797f83..ffe5234 100644 --- a/plc4j/protocols/driver-bases/test/src/main/java/org/apache/plc4x/java/base/protocol/Plc4XSupportedDataTypes.java +++ b/plc4j/protocols/driver-bases/test/src/main/java/org/apache/plc4x/java/base/protocol/Plc4XSupportedDataTypes.java @@ -24,8 +24,15 @@ import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; import java.io.Serializable; +import java.math.BigDecimal; import java.math.BigInteger; -import java.util.*; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; import java.util.function.Function; import java.util.stream.Stream; @@ -38,19 +45,20 @@ public class Plc4XSupportedDataTypes { private final static Map<Class, DataTypePair<?>> bigEndianMap; static { - Calendar calenderInstance = Calendar.getInstance(); - calenderInstance.setTime(new Date(283686951976960L)); littleEndianMap = new HashMap<>(); littleEndianMap.put(Boolean.class, DataTypePair.of(Boolean.TRUE, new byte[]{0x01})); littleEndianMap.put(Byte.class, DataTypePair.of(Byte.valueOf("1"), new byte[]{0x1})); littleEndianMap.put(Short.class, DataTypePair.of(Short.valueOf("1"), new byte[]{0x1, 0x0})); - littleEndianMap.put(Float.class, DataTypePair.of(Float.valueOf("1"), new byte[]{0x0, 0x0, (byte) 0x80, 0x3F})); littleEndianMap.put(Integer.class, DataTypePair.of(Integer.valueOf("1"), new byte[]{0x1, 0x0, 0x0, 0x0})); - littleEndianMap.put(Double.class, DataTypePair.of(Double.valueOf("1"), new byte[]{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, (byte) 0xF0, 0x3F})); + littleEndianMap.put(Long.class, DataTypePair.of(BigInteger.valueOf(1), new byte[]{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0})); littleEndianMap.put(BigInteger.class, DataTypePair.of(BigInteger.valueOf(1), new byte[]{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0})); - littleEndianMap.put(Calendar.class, DataTypePair.of(calenderInstance, new byte[]{0x0, (byte) 0x80, 0x3E, 0x15, (byte) 0xAB, 0x47, (byte) 0xFC, 0x28})); - littleEndianMap.put(GregorianCalendar.class, littleEndianMap.get(Calendar.class)); + littleEndianMap.put(Float.class, DataTypePair.of(Float.valueOf("1"), new byte[]{0x0, 0x0, (byte) 0x80, 0x3F})); + littleEndianMap.put(Double.class, DataTypePair.of(Double.valueOf("1"), new byte[]{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, (byte) 0xF0, 0x3F})); + littleEndianMap.put(BigDecimal.class, DataTypePair.of(Double.valueOf("1"), new byte[]{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, (byte) 0xF0, 0x3F})); littleEndianMap.put(String.class, DataTypePair.of(String.valueOf("Hello World!"), new byte[]{0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x00})); + littleEndianMap.put(LocalTime.class, DataTypePair.of(LocalTime.ofSecondOfDay(1), new byte[]{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0})); + littleEndianMap.put(LocalDate.class, DataTypePair.of(LocalDate.of(1970, 1, 1), new byte[]{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0})); + littleEndianMap.put(LocalDateTime.class, DataTypePair.of(LocalDateTime.of(LocalDate.of(1970, 1, 1), LocalTime.ofSecondOfDay(1)), new byte[]{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0})); littleEndianMap.put(byte[].class, DataTypePair.of(new byte[]{0x1, 0x2, 0x3, 0x4}, new byte[]{0x1, 0x2, 0x3, 0x4})); littleEndianMap.put(Byte[].class, DataTypePair.of(new Byte[]{0x1, 0x2, 0x3, 0x4}, new byte[]{0x1, 0x2, 0x3, 0x4})); bigEndianMap = new HashMap<>(); @@ -77,12 +85,16 @@ public class Plc4XSupportedDataTypes { Boolean.class, Byte.class, Short.class, - Float.class, Integer.class, - Double.class, + Long.class, BigInteger.class, - Calendar.class, + Float.class, + Double.class, + BigDecimal.class, String.class, + LocalTime.class, + LocalDate.class, + LocalDateTime.class, byte[].class, Byte[].class ); diff --git a/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocolTest.java b/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocolTest.java index 7e9099e..b67f97a 100644 --- a/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocolTest.java +++ b/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocolTest.java @@ -65,7 +65,6 @@ public class Plc4XModbusProtocolTest { public ExpectedException expectedException = ExpectedException.none(); // TODO: implement these types private List<String> notYetSupportedDataType = Stream.of( - GregorianCalendar.class, String.class ).map(Class::getSimpleName).collect(Collectors.toList());