You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by tm...@apache.org on 2019/05/06 19:37:04 UTC
[plc4x] 02/02: added DateAndTime and TimeOfDay to acquirable
Datataypes
This is an automated email from the ASF dual-hosted git repository.
tmitsch pushed a commit to branch scraper_refactoring_and_improvement
in repository https://gitbox.apache.org/repos/asf/plc4x.git
commit 8385dd1e824eba7d768a7d1d7578a655290de6b7
Author: Tim Mitsch <t....@pragmaticindustries.de>
AuthorDate: Mon May 6 21:36:56 2019 +0200
added DateAndTime and TimeOfDay to acquirable Datataypes
---
.../org/apache/plc4x/java/s7/model/S7Field.java | 25 +++----
.../plc4x/java/s7/netty/Plc4XS7Protocol.java | 80 ++++++++++++++++++++++
.../org/apache/plc4x/java/s7/netty/S7Protocol.java | 18 ++++-
.../java/s7/netty/model/types/TransportSize.java | 6 +-
.../strategies/DefaultS7MessageProcessor.java | 4 ++
5 files changed, 117 insertions(+), 16 deletions(-)
diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java
index 7bced35..52cc084 100644
--- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java
+++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java
@@ -141,7 +141,7 @@ public class S7Field implements PlcField {
if(matcher.group(NUM_ELEMENTS) != null) {
numElements = Integer.parseInt(matcher.group(NUM_ELEMENTS));
}
- numElements = calcNumberOfElementsForStringTypes(numElements,dataType);
+ numElements = calcNumberOfElementsForIndividualTypes(numElements,dataType);
if(!transferSizeCode.isEmpty() && !dataType.getSizeCode().equals(transferSizeCode)) {
throw new PlcInvalidFieldException("Transfer size code '" + transferSizeCode +
"' doesn't match specified data type '" + dataType.name() + "'");
@@ -166,7 +166,7 @@ public class S7Field implements PlcField {
if(matcher.group(NUM_ELEMENTS) != null) {
numElements = Integer.parseInt(matcher.group(NUM_ELEMENTS));
}
- numElements = calcNumberOfElementsForStringTypes(numElements,dataType);
+ numElements = calcNumberOfElementsForIndividualTypes(numElements,dataType);
if(!transferSizeCode.isEmpty() && !dataType.getSizeCode().equals(transferSizeCode)) {
throw new PlcInvalidFieldException("Transfer size code '" + transferSizeCode +
"' doesn't match specified data type '" + dataType.name() + "'");
@@ -209,17 +209,18 @@ public class S7Field implements PlcField {
* @param dataType detected Transport-Size that represents the data-type
* @return corrected numElements if nessesary
*/
- private static int calcNumberOfElementsForStringTypes(int numElements,TransportSize dataType){
- //if no String nothing has to be done
- if(!dataType.equals(TransportSize.STRING)){
- return numElements;
- }
- //on valid String-length add two byte because of S7-representation of Strings
- if(numElements>1 && numElements<=254){
- return numElements+2;
+ private static int calcNumberOfElementsForIndividualTypes(int numElements, TransportSize dataType){
+
+ if(dataType.equals(TransportSize.STRING)){
+ //on valid String-length add two byte because of S7-representation of Strings
+ if(numElements>1 && numElements<=254){
+ return numElements+2;
+ }
+ //connection String usage with "STRING" only --> numElements=1 --> enter default value
+ return 256;
}
- //connection String usage with "STRING" only --> numElements=1 --> enter default value
- return 256;
+ return numElements;
+
}
}
diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/Plc4XS7Protocol.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/Plc4XS7Protocol.java
index d64ed82..6e50468 100644
--- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/Plc4XS7Protocol.java
+++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/Plc4XS7Protocol.java
@@ -51,7 +51,11 @@ import java.lang.reflect.Array;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.temporal.ChronoUnit;
import java.util.*;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -524,6 +528,15 @@ public class Plc4XS7Protocol extends PlcMessageToMessageCodec<S7Message, PlcRequ
case WSTRING:
fieldItem = decodeReadResponseVarLengthStringField(true, data);
break;
+ // -----------------------------------------
+ // Characters & Strings
+ // -----------------------------------------
+ case DATE_AND_TIME:
+ fieldItem = decodeReadResponseDateAndTime(field,data);
+ break;
+ case TIME_OF_DAY:
+ fieldItem = decodeReadResponseTimeOfDay(field,data);
+ break;
default:
throw new PlcProtocolException("Unsupported type " + field.getDataType());
}
@@ -640,6 +653,29 @@ public class Plc4XS7Protocol extends PlcMessageToMessageCodec<S7Message, PlcRequ
return decodeReadResponseFixedLengthStringField(actualLength, isUtf16, data);
}
+ BaseDefaultFieldItem decodeReadResponseDateAndTime(S7Field field,ByteBuf data) {
+ LocalDateTime[] localDateTimes = readAllValues(LocalDateTime.class,field, i -> readDateAndTime(data));
+ return new DefaultLocalDateTimeFieldItem(localDateTimes);
+ }
+
+ BaseDefaultFieldItem decodeReadResponseTimeOfDay(S7Field field,ByteBuf data) {
+ LocalTime[] localTimes = readAllValues(LocalTime.class,field, i -> readTimeOfDay(data));
+ return new DefaultLocalTimeFieldItem(localTimes);
+ }
+
+ // Returns a 32 bit unsigned value : from 0 to 4294967295 (2^32-1)
+ public static int getUDIntAt(byte[] buffer, int pos) {
+ int result;
+ result = buffer[pos] & 0x0FF;
+ result <<= 8;
+ result += buffer[pos + 1] & 0x0FF;
+ result <<= 8;
+ result += buffer[pos + 2] & 0x0FF;
+ result <<= 8;
+ result += buffer[pos + 3] & 0x0FF;
+ return result;
+ }
+
private static <T> T[] readAllValues(Class<T> clazz, S7Field field, Function<Integer, T> extract) {
try {
return IntStream.rangeClosed(1, field.getNumElements())
@@ -730,4 +766,48 @@ public class Plc4XS7Protocol extends PlcMessageToMessageCodec<S7Message, PlcRequ
return new BigInteger(bytes);
}
+ LocalDateTime readDateAndTime(ByteBuf data) {
+ //per definition for Date_And_Time only the first 6 bytes are used
+
+ int year=convertByteToBcd(data.readByte());
+ int month=convertByteToBcd(data.readByte());
+ int day=convertByteToBcd(data.readByte());
+ int hour=convertByteToBcd(data.readByte());
+ int minute=convertByteToBcd(data.readByte());
+ int second=convertByteToBcd(data.readByte());
+ //skip the last 2 bytes no information present
+ data.readByte();
+ data.readByte();
+
+ //data-type ranges from 1990 up to 2089
+ if(year>=90){
+ year+=1900;
+ }
+ else{
+ year+=2000;
+ }
+
+ return LocalDateTime.of(year,month,day,hour,minute,second);
+ }
+
+ LocalTime readTimeOfDay(ByteBuf data) {
+ //per definition for Date_And_Time only the first 6 bytes are used
+
+ int millisSinsMidnight = data.readInt();
+
+
+ return LocalTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0).plus(millisSinsMidnight, ChronoUnit.MILLIS);
+
+ }
+
+ /**
+ * converts incoming byte to an integer regarding used BCD format
+ * @param incomingByte
+ * @return converted BCD number
+ */
+ private static int convertByteToBcd(byte incomingByte) {
+ int dec = (incomingByte >> 4) * 10;
+ return dec + (incomingByte & 0x0f);
+ }
+
}
diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/S7Protocol.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/S7Protocol.java
index 02eb677..55a33b7 100644
--- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/S7Protocol.java
+++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/S7Protocol.java
@@ -393,7 +393,8 @@ public class S7Protocol extends ChannelDuplexHandler {
buf.writeByte((byte) 0x0a);
buf.writeByte(s7AnyRequestItem.getAddressingMode().getCode());
buf.writeByte(s7AnyRequestItem.getDataType().getTypeCode());
- buf.writeShort(s7AnyRequestItem.getNumElements());
+
+ buf.writeShort(encodeNumElements(s7AnyRequestItem));
buf.writeShort(s7AnyRequestItem.getDataBlockNumber());
buf.writeByte(s7AnyRequestItem.getMemoryArea().getCode());
// A S7 address is 3 bytes long. Unfortunately the byte-offset is NOT located in
@@ -407,6 +408,21 @@ public class S7Protocol extends ChannelDuplexHandler {
| (s7AnyRequestItem.getBitOffset() & 0x07)));
}
+ /**
+ * this is a workaround for the date and time types, as native requests with the datatypes are
+ * @return
+ */
+ private short encodeNumElements(S7AnyVarParameterItem s7AnyVarParameterItem){
+ switch (s7AnyVarParameterItem.getDataType()){
+ case DATE_AND_TIME:
+ case TIME_OF_DAY:
+ return (short) (s7AnyVarParameterItem.getNumElements()*s7AnyVarParameterItem.getDataType().getSizeInBytes());
+ default:
+ return (short) s7AnyVarParameterItem.getNumElements();
+ }
+
+ }
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Decoding
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/TransportSize.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/TransportSize.java
index 98f35d6..f5e03f1 100644
--- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/TransportSize.java
+++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/TransportSize.java
@@ -84,18 +84,18 @@ public enum TransportSize {
// -----------------------------------------
// IEC date (yyyy-m-d)
// TODO: Find the code
- DATE(0x00, "X", 2, null, null, S7ControllerType.ANY),
+ DATE(0x02, "X", 4, null, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.ANY),
// -----------------------------------------
// Time of day
// -----------------------------------------
// Time (hh:mm:ss.S)
- TIME_OF_DAY(0x0A, "X", 4, null, null, S7ControllerType.ANY),
+ TIME_OF_DAY(0x02, "X", 4, null, DataTransportSize.BYTE_WORD_DWORD,S7ControllerType.ANY),
// -----------------------------------------
// Date and time of day
// -----------------------------------------
- DATE_AND_TIME(0x0F, "X", 8, null, null, S7ControllerType.ANY),
+ DATE_AND_TIME(0x02, "X", 8,null, null, S7ControllerType.S7_1500, S7ControllerType.S7_300, S7ControllerType.S7_400),
// -----------------------------------------
// ASCII Strings
diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/strategies/DefaultS7MessageProcessor.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/strategies/DefaultS7MessageProcessor.java
index a89bd93..97425d8 100644
--- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/strategies/DefaultS7MessageProcessor.java
+++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/strategies/DefaultS7MessageProcessor.java
@@ -405,6 +405,10 @@ public class DefaultS7MessageProcessor implements S7MessageProcessor {
if(requestItem.getNumElements() != responseParameterItem.getNumElements()) {
int itemSizeInBytes = requestItem.getDataType().getSizeInBytes();
int totalSizeInBytes = requestItem.getNumElements() * itemSizeInBytes;
+ if(requestItem.getDataType().equals(TransportSize.DATE_AND_TIME)){
+ totalSizeInBytes = requestItem.getNumElements() * itemSizeInBytes;
+ }
+
if(varParameter.getType() == ParameterType.READ_VAR) {
byte[] data = new byte[totalSizeInBytes];
System.arraycopy(responsePayloadItem.getData(), 0, data, 0, responsePayloadItem.getData().length);