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


The following commit(s) were added to refs/heads/master by this push:
     new c97330a  PLC4X-29 - [S7] Implement PDU Fragmentation
c97330a is described below

commit c97330a4dfc8df4a2355225fb3fce46a292ef24b
Author: Christofer Dutz <[email protected]>
AuthorDate: Wed Feb 7 16:37:57 2018 +0100

    PLC4X-29 - [S7] Implement PDU Fragmentation
    
    - Added the ability to add options to the connection string (similar to 
options in jdbc)
    - Added some functionality to determine the iso tp TPDUsizes based on the 
provided desired pdu size.
---
 examples/kafka-bridge/pom.xml                      |  1 -
 plc4j/protocols/s7/pom.xml                         |  5 ++
 .../java/isotp/netty/model/types/TpduSize.java     | 37 ++++++++---
 .../java/org/apache/plc4x/java/s7/S7PlcDriver.java |  5 +-
 .../plc4x/java/s7/connection/S7PlcConnection.java  | 73 +++++++++++++++++++---
 .../isotp/netty/model/types/IsotpTypeTests.java    | 49 +++++++++++++++
 .../java/s7/connection/S7PlcConnectionTests.java   |  6 +-
 pom.xml                                            |  5 ++
 8 files changed, 159 insertions(+), 22 deletions(-)

diff --git a/examples/kafka-bridge/pom.xml b/examples/kafka-bridge/pom.xml
index f28a7ec..b922d8b 100644
--- a/examples/kafka-bridge/pom.xml
+++ b/examples/kafka-bridge/pom.xml
@@ -88,7 +88,6 @@
     <dependency>
       <groupId>org.apache.commons</groupId>
       <artifactId>commons-lang3</artifactId>
-      <version>3.7</version>
     </dependency>
 
     <dependency>
diff --git a/plc4j/protocols/s7/pom.xml b/plc4j/protocols/s7/pom.xml
index 1ce4dc4..f03de0f 100644
--- a/plc4j/protocols/s7/pom.xml
+++ b/plc4j/protocols/s7/pom.xml
@@ -59,6 +59,11 @@
     </dependency>
 
     <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+    </dependency>
+
+    <dependency>
       <groupId>ch.qos.logback</groupId>
       <artifactId>logback-classic</artifactId>
     </dependency>
diff --git 
a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/isotp/netty/model/types/TpduSize.java
 
b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/isotp/netty/model/types/TpduSize.java
index 3a8837b..2e662bf 100644
--- 
a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/isotp/netty/model/types/TpduSize.java
+++ 
b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/isotp/netty/model/types/TpduSize.java
@@ -22,26 +22,47 @@ import java.util.HashMap;
 import java.util.Map;
 
 public enum TpduSize {
-    SIZE_8192((byte) 0x0d),
-    SIZE_4096((byte) 0x0c),
-    SIZE_2048((byte) 0x0b),
-    SIZE_1024((byte) 0x0a),
-    SIZE_512((byte) 0x09),
-    SIZE_256((byte) 0x08),
-    SIZE_128((byte) 0x07);
+    SIZE_128((byte) 0x07, 128),
+    SIZE_256((byte) 0x08, 256),
+    SIZE_512((byte) 0x09, 512),
+    SIZE_1024((byte) 0x0a, 1024),
+    SIZE_2048((byte) 0x0b, 2048),
+    SIZE_4096((byte) 0x0c, 4096),
+    SIZE_8192((byte) 0x0d, 8192);
 
     private static Map<Byte, TpduSize> map = null;
     
     private final byte code;
+    private final int value;
 
-    TpduSize(byte code) {
+    TpduSize(byte code, int value) {
         this.code = code;
+        this.value = value;
     }
 
     public byte getCode() {
         return code;
     }
 
+    public int getValue() {
+        return value;
+    }
+
+    public static TpduSize valueForGivenSize(int pduSize) {
+        assert pduSize > 0;
+        for (TpduSize tpduSize : values()) {
+            if(tpduSize.getValue() <= pduSize) {
+                return tpduSize;
+            }
+        }
+        // If the requested pdu size is greater than 8MB,
+        // Simply use that as the given size is simple a
+        // requested size, if the remote responds with a
+        // lower value the application has to live with
+        // this anyway.
+        return SIZE_8192;
+    }
+
     public static TpduSize valueOf(byte code) {
         if (map == null) {
             map = new HashMap<>();
diff --git 
a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/S7PlcDriver.java 
b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/S7PlcDriver.java
index 9156f18..3e279dd 100644
--- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/S7PlcDriver.java
+++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/S7PlcDriver.java
@@ -36,7 +36,7 @@ import java.util.regex.Pattern;
  */
 public class S7PlcDriver implements PlcDriver {
 
-    private static final Pattern S7_URI_PATTERN = 
Pattern.compile("^s7://(?<host>.*)/(?<rack>\\d{1,4})/(?<slot>\\d{1,4})(\\?.*)?");
+    private static final Pattern S7_URI_PATTERN = 
Pattern.compile("^s7://(?<host>.*)/(?<rack>\\d{1,4})/(?<slot>\\d{1,4})(?<params>\\?.*)?");
 
     @Override
     public String getProtocolCode() {
@@ -58,7 +58,8 @@ public class S7PlcDriver implements PlcDriver {
         String host = matcher.group("host");
         int rack = Integer.parseInt(matcher.group("rack"));
         int slot = Integer.parseInt(matcher.group("slot"));
-        return new S7PlcConnection(host, rack, slot);
+        String params = matcher.group("params").substring(1);
+        return new S7PlcConnection(host, rack, slot, params);
     }
 
     @Override
diff --git 
a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java
 
b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java
index 477993f..c0f4793 100644
--- 
a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java
+++ 
b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java
@@ -22,6 +22,7 @@ import io.netty.bootstrap.Bootstrap;
 import io.netty.channel.*;
 import io.netty.channel.nio.NioEventLoopGroup;
 import io.netty.channel.socket.nio.NioSocketChannel;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.plc4x.java.api.connection.AbstractPlcConnection;
 import org.apache.plc4x.java.api.connection.PlcReader;
 import org.apache.plc4x.java.api.connection.PlcWriter;
@@ -67,16 +68,53 @@ public class S7PlcConnection extends AbstractPlcConnection 
implements PlcReader,
     private final String hostName;
     private final int rack;
     private final int slot;
-    private final int pduSize;
+
+    private final int paramPduSize;
+    private final short paramMaxAmqCaller;
+    private final short paramMaxAmqCallee;
 
     private EventLoopGroup workerGroup;
     private Channel channel;
 
-    public S7PlcConnection(String hostName, int rack, int slot) {
+    public S7PlcConnection(String hostName, int rack, int slot, String params) 
{
         this.hostName = hostName;
         this.rack = rack;
         this.slot = slot;
-        this.pduSize = 1024;
+
+        int paramPduSize = 1024;
+        short paramMaxAmqCaller = 8;
+        short paramMaxAmqCallee = 8;
+
+        if(!StringUtils.isEmpty(params)) {
+            for (String param : params.split("&")) {
+                String[] paramElements = param.split("=");
+                String paramName = paramElements[0];
+                if(paramElements.length == 2) {
+                    String paramValue = paramElements[1];
+                    switch (paramName) {
+                        case "pdu-size":
+                            paramPduSize = Integer.parseInt(paramValue);
+                            break;
+                        case "max-amq-caller":
+                            paramMaxAmqCaller = Short.parseShort(paramValue);
+                            break;
+                        case "max-amq-callee":
+                            paramMaxAmqCallee = Short.parseShort(paramValue);
+                            break;
+                        default:
+                            logger.debug("Unknown parameter {}={}", paramName, 
paramValue);
+                    }
+                } else {
+                    logger.debug("Unknown no-value parameter {}", paramName);
+                }
+            }
+        }
+        this.paramPduSize = paramPduSize;
+        this.paramMaxAmqCaller = paramMaxAmqCaller;
+        this.paramMaxAmqCallee = paramMaxAmqCallee;
+
+        logger.info("Configured S7cConnection with: host-name {}, rack {}, 
slot {}, pdu-size {}, max-amq-caller {}, " +
+            "max-amq-callee {}", hostName, rack, slot, paramPduSize, 
paramMaxAmqCaller, paramMaxAmqCallee);
     }
 
     public String getHostName() {
@@ -91,8 +129,16 @@ public class S7PlcConnection extends AbstractPlcConnection 
implements PlcReader,
         return slot;
     }
 
-    public int getPduSize() {
-        return pduSize;
+    public int getParamPduSize() {
+        return paramPduSize;
+    }
+
+    public int getParamMaxAmqCaller() {
+        return paramMaxAmqCaller;
+    }
+
+    public int getParamMaxAmqCallee() {
+        return paramMaxAmqCallee;
     }
 
     @Override
@@ -107,6 +153,15 @@ public class S7PlcConnection extends AbstractPlcConnection 
implements PlcReader,
 
             InetAddress serverInetAddress = InetAddress.getByName(hostName);
 
+            // IsoTP uses pre defined sizes. Find the smallest box,
+            // that would be able to contain the requested pdu size.
+            TpduSize isoTpTpduSize = TpduSize.valueForGivenSize(paramPduSize);
+
+            // If the pdu size was very big, it might have exceeded the
+            // maximum of 8MB defined in the IsoTP protocol, so we have
+            // to generally downgrade the requested size.
+            int pduSize = (isoTpTpduSize.getValue() < paramPduSize) ? 
isoTpTpduSize.getValue() : paramPduSize;
+
             Bootstrap bootstrap = new Bootstrap();
             bootstrap.group(workerGroup);
             bootstrap.channel(NioSocketChannel.class);
@@ -114,7 +169,7 @@ public class S7PlcConnection extends AbstractPlcConnection 
implements PlcReader,
             bootstrap.option(ChannelOption.TCP_NODELAY, true);
             bootstrap.handler(new ChannelInitializer() {
                 @Override
-                protected void initChannel(Channel channel) throws Exception {
+                protected void initChannel(Channel channel) {
                     // Build the protocol stack for communicating with the s7 
protocol.
                     ChannelPipeline pipeline = channel.pipeline();
                     pipeline.addLast(new ChannelInboundHandlerAdapter() {
@@ -129,8 +184,8 @@ public class S7PlcConnection extends AbstractPlcConnection 
implements PlcReader,
                         }
                     });
                     pipeline.addLast(new IsoOnTcpProtocol());
-                    pipeline.addLast(new IsoTPProtocol((byte) rack, (byte) 
slot, TpduSize.SIZE_1024));
-                    pipeline.addLast(new S7Protocol((short) 8, (short) 8, 
(short) 1024));
+                    pipeline.addLast(new IsoTPProtocol((byte) rack, (byte) 
slot, isoTpTpduSize));
+                    pipeline.addLast(new S7Protocol(paramMaxAmqCaller, 
paramMaxAmqCallee, (short) pduSize));
                     pipeline.addLast(new Plc4XS7Protocol());
                 }
             });
@@ -156,7 +211,7 @@ public class S7PlcConnection extends AbstractPlcConnection 
implements PlcReader,
     }
 
     @Override
-    public void close() throws Exception {
+    public void close() {
         if((channel != null) && channel.isOpen()) {
             // Send the PLC a message that the connection is being closed.
             DisconnectRequestTpdu disconnectRequest = new 
DisconnectRequestTpdu(
diff --git 
a/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/isotp/netty/model/types/IsotpTypeTests.java
 
b/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/isotp/netty/model/types/IsotpTypeTests.java
index 47acf5b..f85ee4a 100644
--- 
a/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/isotp/netty/model/types/IsotpTypeTests.java
+++ 
b/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/isotp/netty/model/types/IsotpTypeTests.java
@@ -152,6 +152,7 @@ class IsotpTypeTests {
 
         assertTrue(TpduSize.valueOf((byte)0x07) == TpduSize.SIZE_128, "0x07 
incorrectly mapped");
         assertTrue(tpduSize.getCode() == (byte)0x07, "code is not 0x07");
+        assertEquals(tpduSize.getValue(), 128, "the value is not 128");
     }
 
     @Test
@@ -162,5 +163,53 @@ class IsotpTypeTests {
         assertNull(tpduSize, "expected tpdu size to be null");
     }
 
+    /**
+     * If we are requesting exactly the size of one of the iso tp
+     * pdu sizes, then exactly that box should be returned.
+     */
+    @Test
+    @Tag("fast")
+    void tpduValueForGivenExactFit() {
+        TpduSize tpduSize = TpduSize.valueForGivenSize(256);
+
+        assertEquals(tpduSize, TpduSize.SIZE_256, "expected tpdu size of 256");
+        assertEquals(tpduSize.getValue(), 128, "the value is not 128");
+    }
+
+    /**
+     * In this case we have a given value that is in-between the boundaries of
+     * a pdu box, the method should return the next larger box.
+     */
+    @Test
+    @Tag("fast")
+    void tpduValueForGivenIntermediateSize() {
+        TpduSize tpduSize = TpduSize.valueForGivenSize(123);
+
+        assertEquals(tpduSize, TpduSize.SIZE_256, "expected tpdu size of 256");
+    }
+
+    /**
+     * This test should cause an exception as the tpdu size has to be greater
+     * than 0 in any case.
+     */
+    @Test
+    @Tag("fast")
+    void tpduValueForGivenTooSmallSize() {
+        TpduSize tpduSize = TpduSize.valueForGivenSize(-1);
+
+        assertEquals(tpduSize, TpduSize.SIZE_256, "expected tpdu size of 256");
+    }
+
+    /**
+     * In this test the tpdu size is greater than the maximum defined by the 
iso tp
+     * protocol spec, so it is automatically downgraded to the maximum valid 
value.
+     */
+    @Test
+    @Tag("fast")
+    void tpduValueForGivenTooGreatSize() {
+        TpduSize tpduSize = TpduSize.valueForGivenSize(10000);
+
+        assertEquals(tpduSize, TpduSize.SIZE_8192, "expected tpdu size of 
8192");
+    }
 
 }
\ No newline at end of file
diff --git 
a/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/s7/connection/S7PlcConnectionTests.java
 
b/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/s7/connection/S7PlcConnectionTests.java
index 64d126f..3d8c100 100644
--- 
a/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/s7/connection/S7PlcConnectionTests.java
+++ 
b/plc4j/protocols/s7/src/test/java/org/apache/plc4x/java/s7/connection/S7PlcConnectionTests.java
@@ -36,7 +36,7 @@ class S7PlcConnectionTests {
 
     @BeforeEach
     void setUp() {
-        s7PlcConnection = new S7PlcConnection("localhost", 1, 2);
+        s7PlcConnection = new S7PlcConnection("localhost", 1, 2, "");
     }
 
     @AfterEach
@@ -49,7 +49,9 @@ class S7PlcConnectionTests {
         
assertTrue(s7PlcConnection.getHostName().equalsIgnoreCase("localhost"), 
"Hostname is incorrect");
         assertTrue(s7PlcConnection.getRack() == 1, "Rack is incorrect");
         assertTrue(s7PlcConnection.getSlot() == 2, "Slot is incorrect");
-        assertTrue(s7PlcConnection.getPduSize() == 1024, "Pdu size is 
incorrect"); // Why is this hard coded?
+        assertTrue(s7PlcConnection.getParamPduSize() == 1024, "Pdu size is 
incorrect");
+        assertTrue(s7PlcConnection.getParamMaxAmqCaller() == 8, "Max AMQ 
Caller size is incorrect");
+        assertTrue(s7PlcConnection.getParamMaxAmqCallee() == 8, "Max AMQ 
Callee size is incorrect");
     }
 
     @Test
diff --git a/pom.xml b/pom.xml
index 71c035f..936d3c7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -176,6 +176,11 @@
         <artifactId>slf4j-api</artifactId>
         <version>${slf4j.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.apache.commons</groupId>
+        <artifactId>commons-lang3</artifactId>
+        <version>3.7</version>
+      </dependency>
     </dependencies>
   </dependencyManagement>
 

-- 
To stop receiving notification emails like this one, please contact
[email protected].

Reply via email to