You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2020/10/25 22:37:49 UTC
[plc4x] branch feature/plc4go updated: - Addressed some issues in
the reading of values via S7 protocol
This is an automated email from the ASF dual-hosted git repository.
cdutz pushed a commit to branch feature/plc4go
in repository https://gitbox.apache.org/repos/asf/plc4x.git
The following commit(s) were added to refs/heads/feature/plc4go by this push:
new a1720ad - Addressed some issues in the reading of values via S7 protocol
a1720ad is described below
commit a1720ad594a7927384954e6e1b90318a42de1fee
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Sun Oct 25 23:37:32 2020 +0100
- Addressed some issues in the reading of values via S7 protocol
---
.../plc4x/java/s7/readwrite/field/S7Field.java | 57 ++++++++--------
.../s7/readwrite/protocol/S7ProtocolLogic.java | 2 +-
.../apache/plc4x/java/s7/utils/StaticHelper.java | 12 ++++
.../plc4x/java/s7/readwrite/DatatypesTest.java | 79 ++++++++++++++++++++++
.../plc4x/java/spi/generation/ReadBuffer.java | 2 +-
.../s7/src/main/resources/protocols/s7/s7.mspec | 10 +--
6 files changed, 127 insertions(+), 35 deletions(-)
diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/field/S7Field.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/field/S7Field.java
index cc2a679..80eff10 100644
--- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/field/S7Field.java
+++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/field/S7Field.java
@@ -120,12 +120,13 @@ public class S7Field implements PlcField {
}
public static boolean matches(String fieldString) {
- return ADDRESS_PATTERN.matcher(fieldString).matches() ||
+ return
DATA_BLOCK_STRING_ADDRESS_PATTERN.matcher(fieldString).matches() ||
DATA_BLOCK_STRING_SHORT_PATTERN.matcher(fieldString).matches() ||
DATA_BLOCK_ADDRESS_PATTERN.matcher(fieldString).matches() ||
DATA_BLOCK_SHORT_PATTERN.matcher(fieldString).matches() ||
- PLC_PROXY_ADDRESS_PATTERN.matcher(fieldString).matches();
+ PLC_PROXY_ADDRESS_PATTERN.matcher(fieldString).matches() ||
+ ADDRESS_PATTERN.matcher(fieldString).matches();
}
/**
@@ -166,32 +167,7 @@ public class S7Field implements PlcField {
public static S7Field of(String fieldString) {
Matcher matcher;
- if ((matcher = ADDRESS_PATTERN.matcher(fieldString)).matches()) {
- TransportSize dataType = TransportSize.valueOf(matcher.group(DATA_TYPE));
- MemoryArea memoryArea = getMemoryAreaForShortName(matcher.group(MEMORY_AREA));
- Short transferSizeCode = getSizeCode(matcher.group(TRANSFER_SIZE_CODE));
- int byteOffset = checkByteOffset(Integer.parseInt(matcher.group(BYTE_OFFSET)));
- byte bitOffset = 0;
- if (matcher.group(BIT_OFFSET) != null) {
- bitOffset = Byte.parseByte(matcher.group(BIT_OFFSET));
- } else if (dataType == TransportSize.BOOL) {
- throw new PlcInvalidFieldException("Expected bit offset for BOOL parameters.");
- }
- int numElements = 1;
- if (matcher.group(NUM_ELEMENTS) != null) {
- numElements = Integer.parseInt(matcher.group(NUM_ELEMENTS));
- }
-
- if ((transferSizeCode != null) && (dataType.getSizeCode() != transferSizeCode)) {
- throw new PlcInvalidFieldException("Transfer size code '" + transferSizeCode +
- "' doesn't match specified data type '" + dataType.name() + "'");
- }
- if ((dataType != TransportSize.BOOL) && bitOffset != 0) {
- throw new PlcInvalidFieldException("A bit offset other than 0 is only supported for type BOOL");
- }
-
- return new S7Field(dataType, memoryArea, (short) 0, byteOffset, bitOffset, numElements);
- } else if ((matcher = DATA_BLOCK_STRING_ADDRESS_PATTERN.matcher(fieldString)).matches()) {
+ if ((matcher = DATA_BLOCK_STRING_ADDRESS_PATTERN.matcher(fieldString)).matches()) {
TransportSize dataType = TransportSize.STRING;
int stringLength = Integer.parseInt(matcher.group(STRING_LENGTH));
MemoryArea memoryArea = getMemoryAreaForShortName(matcher.group(MEMORY_AREA));
@@ -309,6 +285,31 @@ public class S7Field implements PlcField {
} catch (ParseException | DecoderException e) {
throw new PlcInvalidFieldException("Unable to parse address: " + fieldString);
}
+ } else if ((matcher = ADDRESS_PATTERN.matcher(fieldString)).matches()) {
+ TransportSize dataType = TransportSize.valueOf(matcher.group(DATA_TYPE));
+ MemoryArea memoryArea = getMemoryAreaForShortName(matcher.group(MEMORY_AREA));
+ Short transferSizeCode = getSizeCode(matcher.group(TRANSFER_SIZE_CODE));
+ int byteOffset = checkByteOffset(Integer.parseInt(matcher.group(BYTE_OFFSET)));
+ byte bitOffset = 0;
+ if (matcher.group(BIT_OFFSET) != null) {
+ bitOffset = Byte.parseByte(matcher.group(BIT_OFFSET));
+ } else if (dataType == TransportSize.BOOL) {
+ throw new PlcInvalidFieldException("Expected bit offset for BOOL parameters.");
+ }
+ int numElements = 1;
+ if (matcher.group(NUM_ELEMENTS) != null) {
+ numElements = Integer.parseInt(matcher.group(NUM_ELEMENTS));
+ }
+
+ if ((transferSizeCode != null) && (dataType.getSizeCode() != transferSizeCode)) {
+ throw new PlcInvalidFieldException("Transfer size code '" + transferSizeCode +
+ "' doesn't match specified data type '" + dataType.name() + "'");
+ }
+ if ((dataType != TransportSize.BOOL) && bitOffset != 0) {
+ throw new PlcInvalidFieldException("A bit offset other than 0 is only supported for type BOOL");
+ }
+
+ return new S7Field(dataType, memoryArea, (short) 0, byteOffset, bitOffset, numElements);
}
throw new PlcInvalidFieldException("Unable to parse address: " + fieldString);
}
diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java
index 133cffc..92135d8 100644
--- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java
+++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java
@@ -606,7 +606,7 @@ public class S7ProtocolLogic extends Plc4xProtocolBase<TPKTPacket> {
}
if(transportSize == TransportSize.STRING) {
transportSize = TransportSize.CHAR;
- int stringLength = ((S7StringField) s7Field).getStringLength();
+ int stringLength = (s7Field instanceof S7StringField) ? ((S7StringField) s7Field).getStringLength() : 254;
numElements = numElements * (stringLength + 2);
}
return new S7AddressAny(transportSize, numElements, s7Field.getBlockNumber(),
diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java
index e76539c..a489955 100644
--- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java
+++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java
@@ -106,6 +106,8 @@ public class StaticHelper {
int minute = io.readByte(8);
int second = io.readByte(8);
int nanosecond = io.readUnsignedInt(24);
+ // Skip day-of-week
+ io.readByte(8);
return LocalDateTime.of(year, month, day, hour, minute, second, nanosecond);
} catch (Exception e) {
@@ -117,6 +119,11 @@ public class StaticHelper {
throw new NotImplementedException("Serializing DATE_AND_TIME not implemented");
}
+ public static String parseS7Char(ReadBuffer io, Object encoding) {
+ // Read the full size of the string.
+ return io.readString(8, (String) encoding);
+ }
+
public static String parseS7String(ReadBuffer io, int stringLength, Object encoding) {
try {
// This is the maximum number of bytes a string can be long.
@@ -132,6 +139,11 @@ public class StaticHelper {
}
}
+ public static void serializeS7Char(WriteBuffer io, PlcValue value, Object encoding) {
+ // TODO: Need to implement the serialization or we can't write strings
+ throw new NotImplementedException("Serializing STRING not implemented");
+ }
+
public static void serializeS7String(WriteBuffer io, PlcValue value, int stringLength, Object encoding) {
// TODO: Need to implement the serialization or we can't write strings
throw new NotImplementedException("Serializing STRING not implemented");
diff --git a/plc4j/drivers/s7/src/test/java/org/apache/plc4x/java/s7/readwrite/DatatypesTest.java b/plc4j/drivers/s7/src/test/java/org/apache/plc4x/java/s7/readwrite/DatatypesTest.java
new file mode 100644
index 0000000..f382b37
--- /dev/null
+++ b/plc4j/drivers/s7/src/test/java/org/apache/plc4x/java/s7/readwrite/DatatypesTest.java
@@ -0,0 +1,79 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+package org.apache.plc4x.java.s7.readwrite;
+
+import org.apache.plc4x.java.PlcDriverManager;
+import org.apache.plc4x.java.api.PlcConnection;
+import org.apache.plc4x.java.api.messages.PlcReadRequest;
+import org.apache.plc4x.java.api.messages.PlcReadResponse;
+
+public class DatatypesTest {
+
+ public static void main(String[] args) throws Exception {
+ try (PlcConnection connection = new PlcDriverManager().getConnection("s7://192.168.23.30")) {
+ final PlcReadRequest.Builder builder = connection.readRequestBuilder();
+ builder.addItem("bool-value-1", "%DB2:0.0:BOOL"); // true
+ builder.addItem("bool-value-2", "%DB2:2.1:BOOL"); // false
+ // It seems S7 PLCs ignores the array notation for BOOL
+ //builder.addItem("bool-array", "%DB2:2.1:BOOL[4]");
+ builder.addItem("byte-value", "%DB2:2:BYTE");
+ builder.addItem("byte-array", "%DB2:2:BYTE[2]");
+ builder.addItem("word-value", "%DB2:2:WORD");
+ builder.addItem("word-array", "%DB2:2:WORD[2]");
+ builder.addItem("dword-value", "%DB2:2:DWORD");
+ builder.addItem("dword-array", "%DB2:2:DWORD[2]");
+ builder.addItem("sint-value", "%DB2:12:SINT"); // 7
+ builder.addItem("sint-array", "%DB2:14:SINT[2]"); // 1, -2
+ builder.addItem("int-value", "%DB2:18:INT"); // 23
+ builder.addItem("int-array", "%DB2:20:INT[2]"); // 123, -142
+ builder.addItem("dint-value", "%DB2:24:DINT"); // 24
+ builder.addItem("dint-array", "%DB2:28:DINT[2]"); // 1234, -2345
+ builder.addItem("usint-value", "%DB2:36:USINT"); // 42
+ builder.addItem("usint-array", "%DB2:38:USINT[2]"); // 3, 4
+ builder.addItem("uint-value", "%DB2:40:UINT"); // 3
+ builder.addItem("uint-array", "%DB2:42:UINT[2]"); // 242, 223
+ builder.addItem("udint-value", "%DB2:46:UDINT"); // 815
+ builder.addItem("udint-array", "%DB2:50:UDINT[2]"); // 12345, 23456
+ builder.addItem("real-value", "%DB2:58:REAL"); // 3.14159
+ builder.addItem("real-array", "%DB2:62:REAL[2]"); // 12.345, 12.345
+ builder.addItem("lreal-value", "%DB2:70:LREAL"); // 3.14159265358979
+ builder.addItem("lreal-array", "%DB2:78:LREAL[2]"); // 1.2345, -1.2345
+ builder.addItem("string-value", "%DB2:94:STRING(10)"); // "Hurz"
+ // When reading a sized STRING string array, this has to be translated into multiple items
+ //builder.addItem("string-array", "%DB2:350:STRING(10)[2]"); // "Wolf", "Lamm"
+ builder.addItem("time-value", "%DB2:862:TIME"); // 1234ms
+ builder.addItem("time-array", "%DB2:866:TIME[2]"); // 123ms, 234ms
+ builder.addItem("date-value", "%DB2:874:DATE"); // D#2020-08-20
+ builder.addItem("date-array", "%DB2:876:DATE[2]"); // D#1990-03-28, D#2020-10-25
+ builder.addItem("time-of-day-value", "%DB2:880:TIME_OF_DAY"); // TOD#12:34:56
+ builder.addItem("time-of-day-array", "%DB2:884:TIME_OF_DAY[2]"); // TOD#16:34:56, TOD#08:15:00
+ builder.addItem("date-and-time-value", "%DB2:892:DATE_AND_TIME"); // DTL#1978-03-28-12:34:56
+ builder.addItem("date-and-time-array", "%DB2:904:DATE_AND_TIME[2]"); // DTL#1978-03-28-12:34:56, DTL#1978-03-28-12:34:56
+ builder.addItem("char-value", "%DB2:928:CHAR"); // "H"
+ builder.addItem("char-array", "%DB2:930:CHAR[4]"); // "H", "u", "r", "z"
+ final PlcReadRequest readRequest = builder.build();
+
+ final PlcReadResponse readResponse = readRequest.execute().get();
+
+ System.out.println(readResponse);
+
+ }
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java
index c856c6c..d890f7b 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java
@@ -61,7 +61,7 @@ public class ReadBuffer {
}
public boolean hasMore(int numBits) {
- return (numBits / 8) < (totalBytes - getPos());
+ return (numBits / 8) <= (totalBytes - getPos());
}
public byte peekByte(int offset) throws ParseException {
diff --git a/protocols/s7/src/main/resources/protocols/s7/s7.mspec b/protocols/s7/src/main/resources/protocols/s7/s7.mspec
index 914c53e..5e1d329 100644
--- a/protocols/s7/src/main/resources/protocols/s7/s7.mspec
+++ b/protocols/s7/src/main/resources/protocols/s7/s7.mspec
@@ -333,11 +333,11 @@
// -----------------------------------------
// Characters & Strings
// -----------------------------------------
- ['41' STRING
- [manual string 'UTF-8' 'value' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.parseS7String", io, stringLength, _type.encoding)' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.serializeS7String", io, _value, '1', _type.encoding)' '1']
+ ['41' CHAR
+ [manual string 'UTF-8' 'value' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.parseS7Char", io, _type.encoding)' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.serializeS7Char", io, _value, _type.encoding)' '1']
]
- ['42' STRING
- [manual string 'UTF-16' 'value' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.parseS7String", io, stringLength, _type.encoding)' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.serializeS7String", io, _value, '1', _type.encoding)' '2']
+ ['42' CHAR
+ [manual string 'UTF-16' 'value' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.parseS7Char", io, _type.encoding)' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.serializeS7Char", io, _value, _type.encoding)' '2']
]
['43' STRING
[manual string 'UTF-8' 'value' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.parseS7String", io, stringLength, _type.encoding)' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.serializeS7String", io, _value, stringLength, _type.encoding)' '_value.length + 2']
@@ -433,7 +433,7 @@
['0x03' CHAR ['B' , '1' , 'null' , 'DataTransportSize.BYTE_WORD_DWORD' , '41' , 'true' , 'true' , 'true' , 'true' , 'true' ]]
['0x13' WCHAR ['X' , '2' , 'null' , 'null' , '42' , 'false' , 'false' , 'true' , 'true' , 'true' ]]
['0x03' STRING ['X' , '1' , 'null' , 'DataTransportSize.BYTE_WORD_DWORD' , '43' , 'true' , 'true' , 'true' , 'true' , 'true' ]]
- ['0x00' WSTRING ['X' , '1' , 'null' , 'null' , '44' , 'false' , 'false' , 'true' , 'true' , 'true' ]]
+ ['0x00' WSTRING ['X' , '2' , 'null' , 'null' , '44' , 'false' , 'false' , 'true' , 'true' , 'true' ]]
// Dates and time values (Please note that we seem to have to reqite queries for these types to reading bytes or we'll get "Data type not supported" errors)
['0x0B' TIME ['X' , '4' , 'null' , 'null' , '51' , 'true' , 'true' , 'true' , 'true' , 'true' ]]