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 2019/10/10 09:22:27 UTC
[plc4x] 03/03: - Initiated a plc simulator module - Started working
on a s7 server module for the simulator
This is an automated email from the ASF dual-hosted git repository.
cdutz pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git
commit f9c8818b701a9d63711ffd8a6c68a32673247a0e
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Thu Oct 10 11:22:11 2019 +0200
- Initiated a plc simulator module
- Started working on a s7 server module for the simulator
---
sandbox/plc-simulator/pom.xml | 129 +++++++++++++
.../org/apache/plc4x/simulator/PlcSimulator.java | 88 +++++++++
.../plc4x/simulator/server/ServerModule.java | 32 ++++
.../apache/plc4x/simulator/server/s7/S7Server.java | 61 ++++++
.../plc4x/simulator/server/s7/S7ServerModule.java | 40 ++++
.../server/s7/protocol/S7Step7Protocol.java | 76 ++++++++
.../server/s7/protocol/S7Step7ServerProtocol.java | 207 +++++++++++++++++++++
.../simulator/simulation/SimulationModule.java | 43 +++++
.../watertank/WaterTankSimulationModule.java | 60 ++++++
.../org.apache.plc4x.simulator.server.ServerModule | 20 ++
...che.plc4x.simulator.simulation.SimulationModule | 20 ++
.../plc-simulator/src/main/resources/logback.xml | 36 ++++
12 files changed, 812 insertions(+)
diff --git a/sandbox/plc-simulator/pom.xml b/sandbox/plc-simulator/pom.xml
new file mode 100644
index 0000000..e853987
--- /dev/null
+++ b/sandbox/plc-simulator/pom.xml
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.plc4x.sandbox</groupId>
+ <artifactId>plc4x-sandbox</artifactId>
+ <version>0.5.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>plc-simulator</artifactId>
+
+ <name>Sandbox: PLC-Simulator</name>
+
+ <build>
+ <plugins>
+ <!-- Generate the code for parsing and serializing S7 packets -->
+ <plugin>
+ <groupId>org.apache.plc4x.plugins</groupId>
+ <artifactId>plc4x-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>test</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>generate-driver</goal>
+ </goals>
+ <configuration>
+ <protocolName>s7</protocolName>
+ <languageName>java</languageName>
+ <outputFlavor>read-write</outputFlavor>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <!-- Build a fat jar containing all dependencies -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <version>3.2.1</version>
+ <executions>
+ <execution>
+ <id>generate-uber-jar</id>
+ <phase>package</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ <configuration>
+ <transformers combine.children="append">
+ <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+ <mainClass>org.apache.plc4x.simulator.PlcSimulator</mainClass>
+ </transformer>
+ </transformers>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4j-utils-driver-base-java</artifactId>
+ <version>0.5.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4j-protocol-driver-base</artifactId>
+ <version>0.5.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>io.netty</groupId>
+ <artifactId>netty-all</artifactId>
+ <version>${netty.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-annotations</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-core</artifactId>
+ <scope>compile</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-build-utils-language-java</artifactId>
+ <version>0.5.0-SNAPSHOT</version>
+ <!-- Scope is 'provided' as this way it's not shipped with the driver -->
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4x-protocols-s7</artifactId>
+ <version>0.5.0-SNAPSHOT</version>
+ <!-- Scope is 'provided' as this way it's not shipped with the driver -->
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/PlcSimulator.java b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/PlcSimulator.java
new file mode 100644
index 0000000..9553c02
--- /dev/null
+++ b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/PlcSimulator.java
@@ -0,0 +1,88 @@
+/*
+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.simulator;
+
+import org.apache.plc4x.simulator.server.ServerModule;
+import org.apache.plc4x.simulator.simulation.SimulationModule;
+
+import java.util.Map;
+import java.util.ServiceLoader;
+import java.util.TreeMap;
+import java.util.concurrent.TimeUnit;
+
+public class PlcSimulator {
+
+ private boolean running;
+ private static Map<String, ServerModule> serverModules;
+ private static Map<String, SimulationModule> simulationModules;
+
+ public PlcSimulator() {
+ this(Thread.currentThread().getContextClassLoader());
+ }
+
+ public PlcSimulator(ClassLoader classLoader) {
+ // Initialize all the server modules.
+ serverModules = new TreeMap<>();
+ ServiceLoader<ServerModule> serverModuleLoader = ServiceLoader.load(ServerModule.class, classLoader);
+ for (ServerModule serverModule : serverModuleLoader) {
+ serverModules.put(serverModule.getName(), serverModule);
+ }
+
+ // Initialize all the simulation modules.
+ simulationModules = new TreeMap<>();
+ ServiceLoader<SimulationModule> simulationModuleLoader = ServiceLoader.load(SimulationModule.class, classLoader);
+ for (SimulationModule simulationModule : simulationModuleLoader) {
+ simulationModules.put(simulationModule.getName(), simulationModule);
+ }
+
+ running = true;
+ }
+
+ public void stop() {
+ running = false;
+ }
+
+ public void run() throws Exception {
+ // Start all server modules.
+ for (ServerModule serverModule : serverModules.values()) {
+ serverModule.start();
+ }
+
+ try {
+ while (running) {
+ // Give all the simulation modules the chance to do something.
+ for (SimulationModule simulationModule : simulationModules.values()) {
+ simulationModule.loop();
+ }
+ // Sleep 100 ms to not run the simulation too eagerly.
+ TimeUnit.MILLISECONDS.sleep(100);
+ }
+ } finally {
+ // Start all server modules.
+ for (ServerModule serverModule : serverModules.values()) {
+ serverModule.stop();
+ }
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ new PlcSimulator().run();
+ }
+
+}
diff --git a/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/ServerModule.java b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/ServerModule.java
new file mode 100644
index 0000000..41aecac
--- /dev/null
+++ b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/ServerModule.java
@@ -0,0 +1,32 @@
+/*
+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.simulator.server;
+
+public interface ServerModule {
+
+ /**
+ * @return the name of the server module
+ */
+ String getName();
+
+ void start();
+
+ void stop();
+
+}
diff --git a/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/S7Server.java b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/S7Server.java
new file mode 100644
index 0000000..16cb8a8
--- /dev/null
+++ b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/S7Server.java
@@ -0,0 +1,61 @@
+/*
+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.simulator.server.s7;
+
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.*;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import org.apache.plc4x.simulator.server.s7.protocol.S7Step7Protocol;
+import org.apache.plc4x.simulator.server.s7.protocol.S7Step7ServerProtocol;
+
+public class S7Server {
+
+ private static final int ISO_ON_TCP_PORT = 102;
+
+ public void run() throws Exception {
+ EventLoopGroup loopGroup = new NioEventLoopGroup();
+ EventLoopGroup workerGroup = new NioEventLoopGroup();
+ try {
+ ServerBootstrap bootstrap = new ServerBootstrap();
+ bootstrap.group(loopGroup, workerGroup)
+ .channel(NioServerSocketChannel.class)
+ .childHandler(new ChannelInitializer<SocketChannel>() {
+ @Override
+ public void initChannel(SocketChannel channel) {
+ ChannelPipeline pipeline = channel.pipeline();
+ pipeline.addLast(new S7Step7Protocol());
+ pipeline.addLast(new S7Step7ServerProtocol());
+ }
+ }).option(ChannelOption.SO_BACKLOG, 128)
+ .childOption(ChannelOption.SO_KEEPALIVE, true);
+
+ ChannelFuture future = bootstrap.bind(ISO_ON_TCP_PORT).sync();
+
+ // Wait till it ends ...
+ // TODO: Remove this ...
+ future.channel().closeFuture().sync();
+ } finally {
+ workerGroup.shutdownGracefully();
+ loopGroup.shutdownGracefully();
+ }
+ }
+
+}
diff --git a/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/S7ServerModule.java b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/S7ServerModule.java
new file mode 100644
index 0000000..e9ca944
--- /dev/null
+++ b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/S7ServerModule.java
@@ -0,0 +1,40 @@
+/*
+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.simulator.server.s7;
+
+import org.apache.plc4x.simulator.server.ServerModule;
+
+public class S7ServerModule implements ServerModule {
+
+ @Override
+ public String getName() {
+ return "S7-STEP7";
+ }
+
+ @Override
+ public void start() {
+
+ }
+
+ @Override
+ public void stop() {
+
+ }
+
+}
diff --git a/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/protocol/S7Step7Protocol.java b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/protocol/S7Step7Protocol.java
new file mode 100644
index 0000000..f79b3bd
--- /dev/null
+++ b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/protocol/S7Step7Protocol.java
@@ -0,0 +1,76 @@
+/*
+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.simulator.server.s7.protocol;
+
+import io.netty.buffer.ByteBuf;
+import org.apache.plc4x.java.base.GeneratedDriverByteToMessageCodec;
+import org.apache.plc4x.java.s7.readwrite.TPKTPacket;
+import org.apache.plc4x.java.s7.readwrite.io.TPKTPacketIO;
+import org.apache.plc4x.java.utils.MessageIO;
+import org.apache.plc4x.java.utils.ParseException;
+import org.apache.plc4x.java.utils.ReadBuffer;
+import org.apache.plc4x.java.utils.WriteBuffer;
+
+public class S7Step7Protocol extends GeneratedDriverByteToMessageCodec<TPKTPacket> {
+
+ public S7Step7Protocol() {
+ super(new MessageIO<TPKTPacket, TPKTPacket>() {
+ @Override
+ public TPKTPacket parse(ReadBuffer io) throws ParseException {
+ try {
+ return TPKTPacketIO.parse(io);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new ParseException("Error parsing message", e);
+ }
+ }
+
+ @Override
+ public void serialize(WriteBuffer io, TPKTPacket value) throws ParseException {
+ try {
+ TPKTPacketIO.serialize(io, value);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new ParseException("Error serializing message", e);
+ }
+ }
+ });
+ }
+
+ @Override
+ protected int getPacketSize(ByteBuf byteBuf) {
+ if(byteBuf.readableBytes() >= 4) {
+ if (byteBuf.getByte(0) != TPKTPacket.PROTOCOLID) {
+ return -1;
+ }
+ // Byte 1 is a reserved byte set to 0x00
+ return byteBuf.getShort(2);
+ }
+ return -1;
+ }
+
+ @Override
+ protected void removeRestOfCorruptPackage(ByteBuf byteBuf) {
+ while (byteBuf.getUnsignedByte(0) != TPKTPacket.PROTOCOLID) {
+ // Just consume the bytes till the next possible start position.
+ byteBuf.readByte();
+ }
+ }
+
+}
diff --git a/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/protocol/S7Step7ServerProtocol.java b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/protocol/S7Step7ServerProtocol.java
new file mode 100644
index 0000000..d5dd6f8
--- /dev/null
+++ b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/protocol/S7Step7ServerProtocol.java
@@ -0,0 +1,207 @@
+/*
+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.simulator.server.s7.protocol;
+
+import io.netty.channel.*;
+import org.apache.plc4x.java.s7.readwrite.*;
+import org.apache.plc4x.java.s7.readwrite.types.COTPProtocolClass;
+import org.apache.plc4x.java.s7.readwrite.types.COTPTpduSize;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class S7Step7ServerProtocol extends ChannelInboundHandlerAdapter {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(S7Step7ServerProtocol.class);
+
+ private State state = State.INITIAL;
+
+ // COTP parameters
+ private static final int localReference = 42;
+ private int remoteReference = -1;
+ private COTPProtocolClass protocolClass;
+ private static final int localTsapId = 1;
+ private int remoteTsapId = -1;
+ private static final COTPTpduSize maxTpduSize = COTPTpduSize.SIZE_256;
+ private COTPTpduSize tpduSize;
+ // S7 parameters
+ // Set this to 1 as we don't want to handle stuff in parallel
+ private static final int maxAmqCaller = 1;
+ private int amqCaller;
+ // Set this to 1 as we don't want to handle stuff in parallel
+ private static final int maxAmqCallee = 1;
+ private int amqCallee;
+ private static final int maxPduLength = 240;
+ private int pduLength;
+
+ @Override
+ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+ if(msg instanceof TPKTPacket) {
+ TPKTPacket packet = (TPKTPacket) msg;
+ switch (state) {
+ case INITIAL: {
+ final COTPPacket cotpPacket = packet.getPayload();
+ if (!(cotpPacket instanceof COTPPacketConnectionRequest)) {
+ LOGGER.error("Expecting COTP Connection-Request");
+ return;
+ }
+
+ COTPTpduSize proposedTpduSize = null;
+ COTPPacketConnectionRequest cotpConnectionRequest = (COTPPacketConnectionRequest) cotpPacket;
+ for (COTPParameter parameter : cotpConnectionRequest.getParameters()) {
+ if (parameter instanceof COTPParameterCalledTsap) {
+ COTPParameterCalledTsap calledTsapParameter = (COTPParameterCalledTsap) parameter;
+ } else if (parameter instanceof COTPParameterCallingTsap) {
+ COTPParameterCallingTsap callingTsapParameter = (COTPParameterCallingTsap) parameter;
+ remoteTsapId = callingTsapParameter.getTsapId();
+ } else if (parameter instanceof COTPParameterTpduSize) {
+ COTPParameterTpduSize tpduSizeParameter = (COTPParameterTpduSize) parameter;
+ proposedTpduSize = tpduSizeParameter.getTpduSize();
+ } else {
+ LOGGER.error(
+ "Unexpected COTP Connection-Request Parameter " + parameter.getClass().getName());
+ return;
+ }
+ }
+
+ remoteReference = cotpConnectionRequest.getSourceReference();
+ protocolClass = cotpConnectionRequest.getProtocolClass();
+ tpduSize = (proposedTpduSize.getSizeInBytes() > maxTpduSize.getSizeInBytes()) ? maxTpduSize : proposedTpduSize;
+
+ // Prepare a response and send it back to the remote.
+ COTPParameter[] parameters = new COTPParameter[3];
+ parameters[0] = new COTPParameterCalledTsap(remoteTsapId);
+ parameters[1] = new COTPParameterCallingTsap(localTsapId);
+ parameters[2] = new COTPParameterTpduSize(tpduSize);
+ COTPPacketConnectionResponse response = new COTPPacketConnectionResponse(
+ parameters, null, remoteReference, localReference, protocolClass);
+ ctx.writeAndFlush(new TPKTPacket(response));
+
+ state = State.COTP_CONNECTED;
+ break;
+ }
+ case COTP_CONNECTED: {
+ final COTPPacket cotpPacket = packet.getPayload();
+ if (!(cotpPacket instanceof COTPPacketData)) {
+ LOGGER.error("Expecting COTP Data packet");
+ return;
+ }
+
+ COTPPacketData packetData = (COTPPacketData) cotpPacket;
+ final short cotpTpduRef = packetData.getTpduRef();
+ final S7Message payload = packetData.getPayload();
+ if(!(payload instanceof S7MessageRequest)) {
+ LOGGER.error("Expecting S7 Message Request");
+ return;
+ }
+ S7MessageRequest s7MessageRequest = (S7MessageRequest) payload;
+ final int s7TpduReference = s7MessageRequest.getTpduReference();
+ final S7Parameter s7Parameter = s7MessageRequest.getParameter();
+ if(!(s7Parameter instanceof S7ParameterSetupCommunication)) {
+ LOGGER.error("Expecting S7 Message Request containing a S7 Setup Communication Parameter");
+ return;
+ }
+ S7ParameterSetupCommunication s7ParameterSetupCommunication =
+ (S7ParameterSetupCommunication) s7Parameter;
+
+ amqCaller = Math.min(s7ParameterSetupCommunication.getMaxAmqCaller(), maxAmqCaller);
+ amqCallee = Math.min(s7ParameterSetupCommunication.getMaxAmqCallee(), maxAmqCallee);
+ pduLength = Math.min(s7ParameterSetupCommunication.getPduLength(), maxPduLength);
+
+ S7ParameterSetupCommunication s7ParameterSetupCommunicationResponse =
+ new S7ParameterSetupCommunication(amqCaller, amqCallee, pduLength);
+ S7MessageResponse s7MessageResponse = new S7MessageResponse(
+ s7TpduReference, s7ParameterSetupCommunicationResponse, new S7PayloadSetupCommunication(),
+ (short) 0, (short) 0);
+ ctx.writeAndFlush(new TPKTPacket(new COTPPacketData(null, s7MessageResponse, true, cotpTpduRef)));
+
+ state = State.S7_CONNECTED;
+ break;
+ }
+ case S7_CONNECTED: {
+ final COTPPacket cotpPacket = packet.getPayload();
+ if (!(cotpPacket instanceof COTPPacketData)) {
+ LOGGER.error("Expecting COTP Data packet");
+ return;
+ }
+
+ COTPPacketData packetData = (COTPPacketData) cotpPacket;
+ final short cotpTpduRef = packetData.getTpduRef();
+ final S7Message payload = packetData.getPayload();
+ if(payload instanceof S7MessageUserData) {
+ S7MessageUserData s7MessageUserData = (S7MessageUserData) payload;
+ final int s7TpduReference = s7MessageUserData.getTpduReference();
+ final S7Parameter s7Parameter = s7MessageUserData.getParameter();
+ if(s7Parameter instanceof S7ParameterUserData) {
+ S7ParameterUserData userData = (S7ParameterUserData) s7Parameter;
+ for (S7ParameterUserDataItem item : userData.getItems()) {
+ if(item instanceof S7ParameterUserDataItemCPUFunctions) {
+ S7ParameterUserDataItemCPUFunctions function = (S7ParameterUserDataItemCPUFunctions) item;
+ /*s7MessageUserData.getParameter()
+ final S7ParameterUserDataItemCpuFunctionsItem cpuFunction = function.getCpuFunction();
+ if(cpuFunction instanceof S7ParameterUserDataItemCpuFunctionReadSzlRequest) {
+ S7ParameterUserDataItemCpuFunctionReadSzlRequest readSzlRequest =
+ (S7ParameterUserDataItemCpuFunctionReadSzlRequest) cpuFunction;
+ final SzlId szlId = readSzlRequest.getSzlId();
+ // This is a request to list the type of device
+ if((szlId.getTypeClass() == SzlModuleTypeClass.CPU) &&
+ (szlId.getSublistList() == SzlSublist.MODULE_IDENTIFICATION)) {
+
+ SzlDataTreeItem[] items = new SzlDataTreeItem[1];
+ items[0] = new SzlDataTreeItem((short) 0x0001, new byte[20],
+ 0x2020, 0x0001, 0x2020);
+ S7ParameterUserDataItemCpuFunctionReadSzlResponse readSzlResponse =
+ new S7ParameterUserDataItemCpuFunctionReadSzlResponse(
+ readSzlRequest.getCpuFunctionType(), readSzlRequest.getCpuFunctionGroup(),
+ readSzlRequest.getCpuSubfunction(), (short) 1, (short) 0, (short) 0,
+ (short) 0, (short) 0xFF, (short) 0x09, readSzlRequest.getSzlId(),
+ readSzlRequest.getSzlIndex(), items);
+ S7ParameterUserDataItem[] responseItems = new S7ParameterUserDataItem[1];
+ responseItems[0] = new S7ParameterUserDataItemCPUFunctions((short) 0x12, readSzlResponse);
+ S7ParameterUserData responseUserData = new S7ParameterUserData(responseItems);
+ S7Message s7ResponseMessage = new S7MessageResponse(s7TpduReference, responseUserData, new S7PayloadUserData());
+ ctx.writeAndFlush(new TPKTPacket(new COTPPacketData(null, responseUserData, true, cotpTpduRef)));
+ } else {
+ LOGGER.error("Not able to respond to the given request Read SZL with SZL type class " +
+ szlId.getTypeClass().name() + " and SZL sublise " + szlId.getSublistList().name());
+ }
+ }*/
+ }
+ }
+ } else {
+ LOGGER.error("Unsupported type of S7MessageUserData parameter " +
+ s7Parameter.getClass().getName());
+ return;
+ }
+ } else {
+ LOGGER.error("Unsupported type of message " + payload.getClass().getName());
+ return;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ private enum State {
+ INITIAL,
+ COTP_CONNECTED,
+ S7_CONNECTED
+ }
+
+}
diff --git a/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/simulation/SimulationModule.java b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/simulation/SimulationModule.java
new file mode 100644
index 0000000..f08b082
--- /dev/null
+++ b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/simulation/SimulationModule.java
@@ -0,0 +1,43 @@
+/*
+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.simulator.simulation;
+
+import java.util.Map;
+
+public interface SimulationModule {
+
+ /**
+ * @return the name of the simulation module
+ */
+ String getName();
+
+ /**
+ * Gives access to the internal simulations context.
+ * This is an immutable map of named properties that should contain only simple data-types.
+ * @return reference to the simulations context
+ */
+ Map<String, Object> getContext();
+
+ /**
+ * Method for doing the actual processing inside the simulation.
+ * In this method the simulation can do calculations and update it's context variables.
+ */
+ void loop();
+
+}
diff --git a/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/simulation/watertank/WaterTankSimulationModule.java b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/simulation/watertank/WaterTankSimulationModule.java
new file mode 100644
index 0000000..996076d
--- /dev/null
+++ b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/simulation/watertank/WaterTankSimulationModule.java
@@ -0,0 +1,60 @@
+/*
+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.simulator.simulation.watertank;
+
+import org.apache.plc4x.simulator.simulation.SimulationModule;
+
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.TimeUnit;
+
+public class WaterTankSimulationModule implements SimulationModule {
+
+ private static final String PROP_WATER_LEVEL = "waterLevel";
+
+ private final Map<String, Object> context;
+
+ public WaterTankSimulationModule() {
+ context = new TreeMap<>();
+ context.put(PROP_WATER_LEVEL, 0);
+ }
+
+ @Override
+ public String getName() {
+ return "Water Tank";
+ }
+
+ @Override
+ public Map<String, Object> getContext() {
+ return context;
+ }
+
+ @Override
+ public void loop() {
+ // TODO: Do something sensible ;-)
+ try {
+ // Just increase the level by 1 (Whatever this means ...
+ context.put(PROP_WATER_LEVEL, ((Integer) context.get(context)) + 1);
+ TimeUnit.MILLISECONDS.sleep(100);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/sandbox/plc-simulator/src/main/resources/META-INF/services/org.apache.plc4x.simulator.server.ServerModule b/sandbox/plc-simulator/src/main/resources/META-INF/services/org.apache.plc4x.simulator.server.ServerModule
new file mode 100644
index 0000000..9392a75
--- /dev/null
+++ b/sandbox/plc-simulator/src/main/resources/META-INF/services/org.apache.plc4x.simulator.server.ServerModule
@@ -0,0 +1,20 @@
+#
+# 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.
+#
+
+org.apache.plc4x.simulator.server.s7.S7ServerModule
\ No newline at end of file
diff --git a/sandbox/plc-simulator/src/main/resources/META-INF/services/org.apache.plc4x.simulator.simulation.SimulationModule b/sandbox/plc-simulator/src/main/resources/META-INF/services/org.apache.plc4x.simulator.simulation.SimulationModule
new file mode 100644
index 0000000..bb5db94
--- /dev/null
+++ b/sandbox/plc-simulator/src/main/resources/META-INF/services/org.apache.plc4x.simulator.simulation.SimulationModule
@@ -0,0 +1,20 @@
+#
+# 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.
+#
+
+org.apache.plc4x.simulator.simulation.watertank.WaterTankSimulationModule
\ No newline at end of file
diff --git a/sandbox/plc-simulator/src/main/resources/logback.xml b/sandbox/plc-simulator/src/main/resources/logback.xml
new file mode 100644
index 0000000..27d40c0
--- /dev/null
+++ b/sandbox/plc-simulator/src/main/resources/logback.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<configuration xmlns="http://ch.qos.logback/xml/ns/logback"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://ch.qos.logback/xml/ns/logback https://raw.githubusercontent.com/enricopulatzo/logback-XSD/master/src/main/xsd/logback.xsd">
+
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <!-- encoders are assigned the type
+ ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
+ <encoder>
+ <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+ </encoder>
+ </appender>
+
+ <root level="info">
+ <appender-ref ref="STDOUT" />
+ </root>
+
+</configuration>
\ No newline at end of file