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 2018/03/11 10:09:30 UTC

[incubator-plc4x] 01/05: - Renamed the S7 encoders and decoders

This is an automated email from the ASF dual-hosted git repository.

cdutz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-plc4x.git

commit ad387967f4aa8cfbd034a78637ecf120e746b4c5
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Sun Mar 11 11:05:41 2018 +0100

    - Renamed the S7 encoders and decoders
---
 .../plc4x/java/s7/netty/Plc4XS7Protocol.java       |  4 +-
 .../org/apache/plc4x/java/s7/netty/S7Protocol.java | 50 ++++++++++++++++++----
 .../{BigEndianDecoder.java => S7TypeDecoder.java}  | 24 +++++++----
 .../{BigEndianEncoder.java => S7TypeEncoder.java}  |  4 +-
 4 files changed, 61 insertions(+), 21 deletions(-)

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 9fcec13..750ed62 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
@@ -49,8 +49,8 @@ import org.apache.plc4x.java.s7.netty.model.types.*;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import static org.apache.plc4x.java.s7.netty.util.BigEndianDecoder.decodeData;
-import static org.apache.plc4x.java.s7.netty.util.BigEndianEncoder.encodeData;
+import static org.apache.plc4x.java.s7.netty.util.S7TypeDecoder.decodeData;
+import static org.apache.plc4x.java.s7.netty.util.S7TypeEncoder.encodeData;
 
 public class Plc4XS7Protocol extends MessageToMessageCodec<S7Message, PlcRequestContainer> {
 
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 2aa4a75..40398d0 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
@@ -43,16 +43,16 @@ import org.apache.plc4x.java.s7.netty.model.types.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
+import java.util.*;
 
 public class S7Protocol extends MessageToMessageCodec<IsoTPMessage, S7Message> {
 
-    public static final byte S7_PROTOCOL_MAGIC_NUMBER = 0x32;
+    private static final byte S7_PROTOCOL_MAGIC_NUMBER = 0x32;
 
     private static final Logger logger = LoggerFactory.getLogger(S7Protocol.class);
 
+    private Map<Short, List<S7Message>> messageFragments = new HashMap<>();
+
     private short maxAmqCaller;
     private short maxAmqCallee;
     private short pduSize;
@@ -81,13 +81,45 @@ public class S7Protocol extends MessageToMessageCodec<IsoTPMessage, S7Message> {
     protected void encode(ChannelHandlerContext ctx, S7Message in, List<Object> out) {
         logger.debug("S7 Message sent");
 
-        ByteBuf buf = Unpooled.buffer();
+        List<S7Message> messages = splitMessage(in);
+        messageFragments.put(in.getTpduReference(), messages);
+
+        for (S7Message message : messages) {
+            ByteBuf buf = Unpooled.buffer();
+
+            encodeHeader(message, buf);
+            encodeParameters(message, buf);
+            encodePayloads(message, buf);
 
-        encodeHeader(in, buf);
-        encodeParameters(in, buf);
-        encodePayloads(in, buf);
+            out.add(new DataTpdu(true, (byte) 1, Collections.emptyList(), buf));
+        }
+    }
 
-        out.add(new DataTpdu(true, (byte) 1, Collections.emptyList(), buf));
+    /**
+     * While a SetupCommunication message is no problem, when reading multiple
+     * addresses in one request, the size of the PDU could be exceeded, therefore we need
+     * to split up one incoming message. When writing, the S7 PLCs only seem to accept
+     * writing of single elements, so we have to break up writing of multiple values into
+     * multiple single-value write operations.
+     *
+     * @param message incoming message
+     * @return List of outgoing messages
+     */
+    private List<S7Message> splitMessage(S7Message message) {
+        // The following considerations have to be taken into account:
+        // - The size of all parameters and payloads of a message cannot exceed the negotiated PDU size
+        // - When reading data, the size of the returned data cannot exceed the negotiated PDU size
+        //
+        // Examples:
+        // - Size of the request exceeds the maximum
+        //  When having a negotiated max PDU size of 256, the maximum size of individual addresses can be at most 18
+        //  If more are sent, the S7 will respond with a frame error.
+        // - Size of the response exceeds the maximum
+        //  When reading two Strings of each 200 bytes length, the size of the request is ok, however the PLC would
+        //  have to send back 400 bytes of String data, which would exceed the PDU size. In this case the first String
+        //  is correctly returned, but for the second item the PLC will return a code of 0x03 = Access Denied
+
+        return Collections.singletonList(message);
     }
 
     private void encodePayloads(S7Message in, ByteBuf buf) {
diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/BigEndianDecoder.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7TypeDecoder.java
similarity index 76%
rename from plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/BigEndianDecoder.java
rename to plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7TypeDecoder.java
index 6e22bcd..ac67863 100644
--- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/BigEndianDecoder.java
+++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7TypeDecoder.java
@@ -20,12 +20,13 @@ package org.apache.plc4x.java.s7.netty.util;
 
 import org.apache.plc4x.java.api.exceptions.PlcProtocolException;
 
+import java.io.UnsupportedEncodingException;
 import java.util.LinkedList;
 import java.util.List;
 
-public class BigEndianDecoder {
+public class S7TypeDecoder {
 
-    private BigEndianDecoder() {
+    private S7TypeDecoder() {
         // Utility class
     }
 
@@ -58,13 +59,20 @@ public class BigEndianDecoder {
                 result.add(Float.intBitsToFloat(intValue));
                 i += 4;
             } else if (datatype == String.class) {
-                StringBuilder builder = new StringBuilder();
-                while (s7Data[i] != (byte) 0x0 && i < length) {
-                    builder.append((char) s7Data[i]);
-                    i++;
+                // Every string value had a prefix of two bytes for which I have no idea, what the meaning is.
+                // This code assumes the string values doesn't contain UTF-8 values with a code of 0x00 as it
+                // uses this as termination char.
+                try {
+                    int j = 0;
+                    for(; j < s7Data.length; j++) {
+                        if(s7Data[j] == 0) {
+                            break;
+                        }
+                    }
+                    result.add(new String(s7Data, 2, j - 2, "UTF-8"));
+                } catch (UnsupportedEncodingException e) {
+                    throw new PlcProtocolException("Error decoding String value");
                 }
-                i++; // skip terminating character
-                result.add(builder.toString());
             } else {
                 throw new PlcProtocolException("Unsupported datatype " + datatype.getSimpleName());
             }
diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/BigEndianEncoder.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7TypeEncoder.java
similarity index 98%
rename from plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/BigEndianEncoder.java
rename to plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7TypeEncoder.java
index f9d1159..5c50e50 100644
--- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/BigEndianEncoder.java
+++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7TypeEncoder.java
@@ -20,9 +20,9 @@ package org.apache.plc4x.java.s7.netty.util;
 
 import java.util.Calendar;
 
-public class BigEndianEncoder {
+public class S7TypeEncoder {
 
-    private BigEndianEncoder() {
+    private S7TypeEncoder() {
         // Utility class
     }
 

-- 
To stop receiving notification emails like this one, please contact
cdutz@apache.org.