This is an automated email from the ASF dual-hosted git repository. jfeinauer pushed a commit to branch feature/plc-simulator in repository https://gitbox.apache.org/repos/asf/plc4x.git
commit 8c3c13ed44a3d929ab4d3140863f00ae0e110b1a Author: Christofer Dutz <christofer.d...@c-ware.de> AuthorDate: Thu Oct 17 09:57:08 2019 +0200 - Made data be transported in "byte" instead of "short" arrays. - Changed the PLCSimulator to only run with one selected simulation (Due to the problem of how to map I/O to the different simulations) --- .../org/apache/plc4x/simulator/PlcSimulator.java | 48 ++++++++++++---------- .../plc4x/simulator/server/ServerModule.java | 4 +- .../plc4x/simulator/server/s7/S7ServerModule.java | 12 ++---- .../server/s7/protocol/S7Step7ServerAdapter.java | 46 +++++++++++++++++---- .../watertank/WaterTankSimulationModule.java | 2 +- 5 files changed, 71 insertions(+), 41 deletions(-) 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 index 26aab3a..d9bdab5 100644 --- 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 @@ -35,25 +35,32 @@ public class PlcSimulator { private boolean running; private final Map<String, ServerModule> serverModules; - private final Map<String, SimulationModule> simulationModules; + private final SimulationModule simulationModule; - private PlcSimulator() { - this(Thread.currentThread().getContextClassLoader()); + private PlcSimulator(String simulationName) { + this(simulationName, Thread.currentThread().getContextClassLoader()); } - private PlcSimulator(ClassLoader classLoader) { - Map<String, Context> contexts = new TreeMap<>(); - + private PlcSimulator(String simulationName, ClassLoader classLoader) { + Context context = null; // Initialize all the simulation modules. LOGGER.info("Initializing Simulation Modules:"); - simulationModules = new TreeMap<>(); + SimulationModule foundSimulationModule = null; ServiceLoader<SimulationModule> simulationModuleLoader = ServiceLoader.load(SimulationModule.class, classLoader); - for (SimulationModule simulationModule : simulationModuleLoader) { - LOGGER.info(String.format("Initializing simulation module: %s ...", simulationModule.getName())); - simulationModules.put(simulationModule.getName(), simulationModule); - contexts.put(simulationModule.getName(), simulationModule.getContext()); - LOGGER.info("Initialized"); + for (SimulationModule curSimulationModule : simulationModuleLoader) { + if(curSimulationModule.getName().equals(simulationName)) { + LOGGER.info(String.format("Initializing simulation module: %s ...", simulationName)); + foundSimulationModule = curSimulationModule; + context = curSimulationModule.getContext(); + LOGGER.info("Initialized"); + } + } + // If we couldn't find the simulation module provided, report an error and exit. + if(foundSimulationModule == null) { + LOGGER.info(String.format("Couldn't find simulation module %s", simulationName)); + System.exit(1); } + simulationModule = foundSimulationModule; LOGGER.info("Finished Initializing Simulation Modules\n"); // Initialize all the server modules. @@ -64,7 +71,7 @@ public class PlcSimulator { LOGGER.info(String.format("Initializing server module: %s ...", serverModule.getName())); serverModules.put(serverModule.getName(), serverModule); // Inject the contexts. - serverModule.setContexts(contexts); + serverModule.setContext(context); LOGGER.info("Initialized"); } LOGGER.info("Finished Initializing Server Modules\n"); @@ -89,14 +96,11 @@ public class PlcSimulator { try { LOGGER.info("Starting simulations ..."); while (running) { - // Give all the simulation modules the chance to do something. - for (SimulationModule simulationModule : simulationModules.values()) { - try { - simulationModule.loop(); - } catch(Exception e) { - LOGGER.error("Caught error while executing loop() method of " + simulationModule.getName() + - " simulation.", e); - } + try { + simulationModule.loop(); + } catch(Exception e) { + LOGGER.error("Caught error while executing loop() method of " + simulationModule.getName() + + " simulation.", e); } // Sleep 100 ms to not run the simulation too eagerly. TimeUnit.MILLISECONDS.sleep(100); @@ -113,7 +117,7 @@ public class PlcSimulator { } public static void main(String[] args) throws Exception { - final PlcSimulator simulator = new PlcSimulator(); + final PlcSimulator simulator = new PlcSimulator("Water Tank"); // Make sure we stop everything correctly. Runtime.getRuntime().addShutdownHook(new Thread(simulator::stop)); // Start the simulator. 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 index 97bf1c0..61a1ac9 100644 --- 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 @@ -21,8 +21,6 @@ package org.apache.plc4x.simulator.server; import org.apache.plc4x.simulator.exceptions.SimulatorExcepiton; import org.apache.plc4x.simulator.model.Context; -import java.util.Map; - public interface ServerModule { /** @@ -30,7 +28,7 @@ public interface ServerModule { */ String getName(); - void setContexts(Map<String, Context> contexts); + void setContext(Context contexts); void start() throws SimulatorExcepiton; 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 index 483acc6..5a63fc9 100644 --- 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 @@ -32,17 +32,13 @@ import org.apache.plc4x.simulator.model.Context; import org.apache.plc4x.simulator.server.ServerModule; import org.apache.plc4x.simulator.server.s7.protocol.S7Step7ServerAdapter; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - public class S7ServerModule implements ServerModule { private static final int ISO_ON_TCP_PORT = 102; private EventLoopGroup loopGroup; private EventLoopGroup workerGroup; - private List<Context> contexts; + private Context context; @Override public String getName() { @@ -50,8 +46,8 @@ public class S7ServerModule implements ServerModule { } @Override - public void setContexts(Map<String, Context> contexts) { - this.contexts = new ArrayList<>(contexts.values()); + public void setContext(Context context) { + this.context = context; } @Override @@ -72,7 +68,7 @@ public class S7ServerModule implements ServerModule { public void initChannel(SocketChannel channel) { ChannelPipeline pipeline = channel.pipeline(); pipeline.addLast(new S7Step7Protocol()); - pipeline.addLast(new S7Step7ServerAdapter(contexts)); + pipeline.addLast(new S7Step7ServerAdapter(context)); } }).option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); diff --git a/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/protocol/S7Step7ServerAdapter.java b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/protocol/S7Step7ServerAdapter.java index 6a7e95b..9f7a34d 100644 --- a/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/protocol/S7Step7ServerAdapter.java +++ b/sandbox/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/protocol/S7Step7ServerAdapter.java @@ -25,14 +25,15 @@ import org.apache.plc4x.simulator.model.Context; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Arrays; +import java.util.BitSet; import java.util.List; -import java.util.Map; public class S7Step7ServerAdapter extends ChannelInboundHandlerAdapter { private static final Logger LOGGER = LoggerFactory.getLogger(S7Step7ServerAdapter.class); - private List<Context> contexts; + private Context context; private State state; @@ -54,8 +55,8 @@ public class S7Step7ServerAdapter extends ChannelInboundHandlerAdapter { private static final int maxPduLength = 240; private int pduLength; - public S7Step7ServerAdapter(List<Context> contexts) { - this.contexts = contexts; + public S7Step7ServerAdapter(Context context) { + this.context = context; state = State.INITIAL; } @@ -184,6 +185,7 @@ public class S7Step7ServerAdapter extends ChannelInboundHandlerAdapter { function.getCpuSubfunction(), (short) 1, (short) 0, (short) 0, 0); + // This is the product number of a S7-1200 SzlDataTreeItem[] items = new SzlDataTreeItem[1]; items[0] = new SzlDataTreeItem((short) 0x0001, "6ES7 212-1BD30-0XB0 ".getBytes(), 0x2020, 0x0001, 0x2020); @@ -210,7 +212,7 @@ public class S7Step7ServerAdapter extends ChannelInboundHandlerAdapter { ctx.writeAndFlush(new TPKTPacket(new COTPPacketData(null, s7ResponseMessage, 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()); + szlId.getTypeClass().name() + " and SZL sublist " + szlId.getSublistList().name()); } } @@ -228,17 +230,39 @@ public class S7Step7ServerAdapter extends ChannelInboundHandlerAdapter { S7ParameterReadVarRequest readVarRequestParameter = (S7ParameterReadVarRequest) request.getParameter(); final S7VarRequestParameterItem[] items = readVarRequestParameter.getItems(); - for (S7VarRequestParameterItem item : items) { + S7VarPayloadDataItem[] payloadItems = new S7VarPayloadDataItem[items.length]; + for (int i = 0; i < items.length; i++) { + S7VarRequestParameterItem item = items[i]; if(item instanceof S7VarRequestParameterItemAddress) { S7VarRequestParameterItemAddress address = (S7VarRequestParameterItemAddress) item; final S7Address address1 = address.getAddress(); if(address1 instanceof S7AddressAny) { S7AddressAny addressAny = (S7AddressAny) address1; - + switch (addressAny.getArea()) { + case DATA_BLOCKS: { + + break; + } + case INPUTS: + case OUTPUTS: { + int ioNumber = (addressAny.getByteAddress() * 8) + addressAny.getBitAddress(); + int numElements = (addressAny.getTransportSize() == ParameterSize.BOOL) ? + addressAny.getNumberOfElements() : addressAny.getTransportSize().getSizeInBytes() * 8; + final BitSet bitSet = toBitSet(context.getDigitalInputs(), ioNumber, numElements); + final byte[] data = Arrays.copyOf(bitSet.toByteArray(), (numElements + 7) / 8); + payloadItems[i] = new S7VarPayloadDataItem((short) 0xFF, PayloadSize.BYTE_WORD_DWORD, data.length, data); + break; + } + } } } } + S7ParameterReadVarResponse readVarResponseParameter = new S7ParameterReadVarResponse((short) items.length); + S7PayloadReadVarResponse readVarResponsePayload = new S7PayloadReadVarResponse(payloadItems); + S7MessageResponse response = new S7MessageResponse(request.getTpduReference(), + readVarResponseParameter, readVarResponsePayload, (short) 0x00, (short) 0x00); + ctx.writeAndFlush(new TPKTPacket(new COTPPacketData(null, response, true, cotpTpduRef))); } else if(request.getParameter() instanceof S7ParameterWriteVarRequest) { S7ParameterWriteVarRequest writeVarRequestParameter = @@ -266,4 +290,12 @@ public class S7Step7ServerAdapter extends ChannelInboundHandlerAdapter { S7_CONNECTED } + private BitSet toBitSet(List<Boolean> booleans, int startIndex, int numElements) { + BitSet bitSet = new BitSet(booleans.size()); + for(int i = 0; i < Math.min(booleans.size() - startIndex, numElements); i++) { + bitSet.set(i, booleans.get(i + startIndex)); + } + return bitSet; + } + } 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 index dafd394..7000fb3 100644 --- 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 @@ -54,7 +54,7 @@ public class WaterTankSimulationModule implements SimulationModule { // The input valve .addDigitalInput(false) // The output valve - .addDigitalInput(false) + .addDigitalInput(true) // The emergency valve .addDigitalOutput(false) // The water level