From f7179a52ad855399eb0435639f3432864c891d06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Wed, 11 Dec 2019 15:50:12 -0400 Subject: [PATCH 01/17] S7Protocol dst-tsap <-> src-tsap --- .../java/s7/connection/S7PlcConnection.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java index 0de64839f4a..60947066f60 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java @@ -20,6 +20,12 @@ Licensed to the Apache Software Foundation (ASF) under one import io.netty.buffer.Unpooled; import io.netty.channel.*; +import java.net.InetAddress; +import java.util.Collections; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import org.apache.commons.configuration2.Configuration; import org.apache.commons.configuration2.SystemConfiguration; import org.apache.commons.lang3.StringUtils; @@ -32,7 +38,6 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.api.model.PlcField; import org.apache.plc4x.java.base.connection.ChannelFactory; import org.apache.plc4x.java.base.connection.NettyPlcConnection; -import org.apache.plc4x.java.tcp.connection.TcpSocketChannelFactory; import org.apache.plc4x.java.base.events.ConnectEvent; import org.apache.plc4x.java.base.events.ConnectedEvent; import org.apache.plc4x.java.base.messages.*; @@ -50,16 +55,10 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.netty.util.S7PlcFieldHandler; import org.apache.plc4x.java.s7.types.S7ControllerType; import org.apache.plc4x.java.s7.utils.S7TsapIdEncoder; +import org.apache.plc4x.java.tcp.connection.TcpSocketChannelFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.net.InetAddress; -import java.util.Collections; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - /** * Class implementing the Connection handling for Siemens S7. * The adressing of Values in S7 works as follows: @@ -170,9 +169,11 @@ public boolean canWrite() { @Override protected ChannelHandler getChannelHandler(CompletableFuture sessionSetupCompleteFuture) { - short calledTsapId = S7TsapIdEncoder.encodeS7TsapId(DeviceGroup.OS, 0, 0); - short callingTsapId = S7TsapIdEncoder.encodeS7TsapId(DeviceGroup.PG_OR_PC, rack, slot); - + //short calledTsapId = S7TsapIdEncoder.encodeS7TsapId(DeviceGroup.OS, 0, 0); + //short callingTsapId = S7TsapIdEncoder.encodeS7TsapId(DeviceGroup.PG_OR_PC, rack, slot); + short calledTsapId = S7TsapIdEncoder.encodeS7TsapId(DeviceGroup.PG_OR_PC, rack, slot); + short callingTsapId = S7TsapIdEncoder.encodeS7TsapId(DeviceGroup.OS, 0, 0); + return new ChannelInitializer() { @Override protected void initChannel(Channel channel) { From ac6857476a7942247aea348e2616aaa0b9656e3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Fri, 13 Dec 2019 23:38:05 -0400 Subject: [PATCH 02/17] Initial work to incorporate the handling of Alarms in the S7 protocol of PLC4X --- .../java/s7/connection/S7PlcConnection.java | 60 ++++++++++++- .../plc4x/java/s7/netty/Plc4XS7Protocol.java | 85 +++++++++++++++---- .../plc4x/java/s7/netty/S7Protocol.java | 34 ++++++-- ...CpuMessageSubscriptionResponsePayload.java | 21 +++++ .../CpuMessageSubscriptionServicePayload.java | 72 ++++++++++++++++ .../model/payloads/CpuServicesPayload.java | 5 +- .../java/s7/netty/model/types/AlarmType.java | 81 ++++++++++++++++++ .../CpuServicesParameterSubFunctionGroup.java | 8 +- .../s7/netty/model/types/PushEventType.java | 67 +++++++++++++++ .../model/types/SubscribedEventType.java | 76 +++++++++++++++++ .../java/s7/netty/util/S7PlcEventHandler.java | 38 +++++++++ .../java/s7/netty/util/S7SizeHelper.java | 12 ++- vim.exe.stackdump | 19 +++++ 13 files changed, 547 insertions(+), 31 deletions(-) create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuMessageSubscriptionResponsePayload.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuMessageSubscriptionServicePayload.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/AlarmType.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/PushEventType.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/SubscribedEventType.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7PlcEventHandler.java create mode 100644 vim.exe.stackdump diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java index 60947066f60..7ce24fa7c34 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java @@ -21,11 +21,13 @@ Licensed to the Apache Software Foundation (ASF) under one import io.netty.buffer.Unpooled; import io.netty.channel.*; import java.net.InetAddress; +import java.util.Collection; import java.util.Collections; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.function.Consumer; import org.apache.commons.configuration2.Configuration; import org.apache.commons.configuration2.SystemConfiguration; import org.apache.commons.lang3.StringUtils; @@ -33,9 +35,16 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; import org.apache.plc4x.java.api.messages.PlcReadRequest; import org.apache.plc4x.java.api.messages.PlcReadResponse; +import org.apache.plc4x.java.api.messages.PlcSubscriptionEvent; +import org.apache.plc4x.java.api.messages.PlcSubscriptionRequest; +import org.apache.plc4x.java.api.messages.PlcSubscriptionResponse; +import org.apache.plc4x.java.api.messages.PlcUnsubscriptionRequest; +import org.apache.plc4x.java.api.messages.PlcUnsubscriptionResponse; import org.apache.plc4x.java.api.messages.PlcWriteRequest; import org.apache.plc4x.java.api.messages.PlcWriteResponse; +import org.apache.plc4x.java.api.model.PlcConsumerRegistration; import org.apache.plc4x.java.api.model.PlcField; +import org.apache.plc4x.java.api.model.PlcSubscriptionHandle; import org.apache.plc4x.java.base.connection.ChannelFactory; import org.apache.plc4x.java.base.connection.NettyPlcConnection; import org.apache.plc4x.java.base.events.ConnectEvent; @@ -52,6 +61,7 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.netty.S7Protocol; import org.apache.plc4x.java.s7.netty.model.types.MemoryArea; import org.apache.plc4x.java.s7.netty.strategies.DefaultS7MessageProcessor; +import org.apache.plc4x.java.s7.netty.util.S7PlcEventHandler; import org.apache.plc4x.java.s7.netty.util.S7PlcFieldHandler; import org.apache.plc4x.java.s7.types.S7ControllerType; import org.apache.plc4x.java.s7.utils.S7TsapIdEncoder; @@ -77,7 +87,7 @@ Licensed to the Apache Software Foundation (ASF) under one * where the {bit-offset} is optional. * All Available Memory Areas for this mode are defined in the {@link MemoryArea} enum. */ -public class S7PlcConnection extends NettyPlcConnection implements PlcReader, PlcWriter { +public class S7PlcConnection extends NettyPlcConnection implements PlcReader, PlcWriter, PlcSubscriber { private static final int ISO_ON_TCP_PORT = 102; @@ -284,6 +294,16 @@ public PlcWriteRequest.Builder writeRequestBuilder() { return new DefaultPlcWriteRequest.Builder(this, new S7PlcFieldHandler()); } + @Override + public PlcSubscriptionRequest.Builder subscriptionRequestBuilder() { + return new DefaultPlcSubscriptionRequest.Builder(this, new S7PlcEventHandler()); + } + + @Override + public PlcUnsubscriptionRequest.Builder unsubscriptionRequestBuilder() { + return new DefaultPlcUnsubscriptionRequest.Builder(this); + } + @Override public CompletableFuture read(PlcReadRequest readRequest) { InternalPlcReadRequest internalReadRequest = checkInternal(readRequest, InternalPlcReadRequest.class); @@ -314,4 +334,42 @@ public CompletableFuture write(PlcWriteRequest writeRequest) { .thenApply(PlcWriteResponse.class::cast); } + @Override + public CompletableFuture subscribe(PlcSubscriptionRequest subscriptionRequest) { + InternalPlcSubscriptionRequest internalSubsRequest = checkInternal(subscriptionRequest, InternalPlcSubscriptionRequest.class); + CompletableFuture future = new CompletableFuture<>(); + PlcRequestContainer container = + new PlcRequestContainer<>(internalSubsRequest, future); + channel.writeAndFlush(container).addListener(f -> { + if (!f.isSuccess()) { + future.completeExceptionally(f.cause()); + } + }); + return future.thenApply(PlcSubscriptionResponse.class::cast); + } + + @Override + public CompletableFuture unsubscribe(PlcUnsubscriptionRequest unsubscriptionRequest) { + InternalPlcUnsubscriptionRequest internalUnsubsRequest = checkInternal(unsubscriptionRequest, InternalPlcUnsubscriptionRequest.class); + CompletableFuture future = new CompletableFuture<>(); + PlcRequestContainer container = + new PlcRequestContainer<>(internalUnsubsRequest, future); + channel.writeAndFlush(container).addListener(f -> { + if (!f.isSuccess()) { + future.completeExceptionally(f.cause()); + } + }); + return future.thenApply(PlcUnsubscriptionResponse.class::cast); + } + + @Override + public PlcConsumerRegistration register(Consumer consumer, Collection handles) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void unregister(PlcConsumerRegistration registration) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + } 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 6c789dd96fa..86e91bc669d 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 @@ -21,12 +21,28 @@ Licensed to the Apache Software Foundation (ASF) under one import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; +import java.io.IOException; +import java.lang.reflect.Array; +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.temporal.ChronoUnit; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.IntStream; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; import org.apache.plc4x.java.api.exceptions.*; import org.apache.plc4x.java.api.messages.PlcReadRequest; import org.apache.plc4x.java.api.messages.PlcRequest; import org.apache.plc4x.java.api.messages.PlcResponse; +import org.apache.plc4x.java.api.messages.PlcSubscriptionRequest; +import org.apache.plc4x.java.api.messages.PlcUnsubscriptionRequest; import org.apache.plc4x.java.api.messages.PlcWriteRequest; import org.apache.plc4x.java.api.model.PlcField; import org.apache.plc4x.java.api.types.PlcResponseCode; @@ -39,31 +55,20 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.netty.model.messages.S7Message; import org.apache.plc4x.java.s7.netty.model.messages.S7RequestMessage; import org.apache.plc4x.java.s7.netty.model.messages.S7ResponseMessage; +import org.apache.plc4x.java.s7.netty.model.params.CpuServicesParameter; +import org.apache.plc4x.java.s7.netty.model.params.CpuServicesRequestParameter; +import org.apache.plc4x.java.s7.netty.model.params.S7Parameter; import org.apache.plc4x.java.s7.netty.model.params.VarParameter; import org.apache.plc4x.java.s7.netty.model.params.items.S7AnyVarParameterItem; import org.apache.plc4x.java.s7.netty.model.params.items.VarParameterItem; +import org.apache.plc4x.java.s7.netty.model.payloads.CpuMessageSubscriptionServicePayload; +import org.apache.plc4x.java.s7.netty.model.payloads.S7Payload; import org.apache.plc4x.java.s7.netty.model.payloads.VarPayload; import org.apache.plc4x.java.s7.netty.model.payloads.items.VarPayloadItem; import org.apache.plc4x.java.s7.netty.model.types.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; -import java.lang.reflect.Array; -import java.math.BigInteger; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.temporal.ChronoUnit; -import java.util.*; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - /** * This layer transforms between {@link PlcRequestContainer}s {@link S7Message}s. * And stores all "in-flight" requests in an internal structure ({@link Plc4XS7Protocol#requests}). @@ -153,9 +158,57 @@ protected void encode(ChannelHandlerContext ctx, PlcRequestContainer msg, List out) throws PlcException { + byte subsevent = 0; + List parameterItems = new LinkedList<>(); + List payloadItems = new LinkedList<>(); + + PlcSubscriptionRequest subsRequest = (PlcSubscriptionRequest) msg.getRequest(); + + for (String fieldName : subsRequest.getFieldNames()) { + if ( subsRequest.getField(fieldName) instanceof SubscribedEventType){ + SubscribedEventType event = (SubscribedEventType) subsRequest.getField(fieldName); + subsevent = (byte) (subsevent | event.getCode()); + } + } + + CpuServicesParameter cpuservice = new CpuServicesRequestParameter(CpuServicesParameterFunctionGroup.CPU_FUNCTIONS, + CpuServicesParameterSubFunctionGroup.MESSAGE_SERVICE, (byte) 0x00); + + parameterItems.add(cpuservice); + + + S7Payload Data = new CpuMessageSubscriptionServicePayload(DataTransportErrorCode.OK, + DataTransportSize.OCTET_STRING, + subsevent, + new String("HmiRtm "), + AlarmType.ALARM_S_INITIATE); + payloadItems.add(Data); + + + S7RequestMessage s7ReadRequest = new S7RequestMessage(MessageType.USER_DATA, + (short) tpduGenerator.getAndIncrement(), + parameterItems, + payloadItems, + msg); + + requests.put(s7ReadRequest.getTpduReference(), msg); + + out.add(s7ReadRequest); + + } + + private void encodeUnsubcriptionRequest(PlcRequestContainer msg, List out) throws PlcException { + + } + private void encodeReadRequest(PlcRequestContainer msg, List out) throws PlcException { List parameterItems = new LinkedList<>(); 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 8195542815a..7770c2a228f 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 @@ -25,6 +25,9 @@ Licensed to the Apache Software Foundation (ASF) under one import io.netty.handler.codec.MessageToMessageDecoder; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.PromiseCombiner; +import java.lang.reflect.Field; +import java.nio.charset.StandardCharsets; +import java.util.*; import org.apache.commons.lang3.reflect.FieldUtils; import org.apache.plc4x.java.api.exceptions.PlcProtocolException; import org.apache.plc4x.java.api.exceptions.PlcProtocolPayloadTooBigException; @@ -41,6 +44,7 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.netty.model.params.*; import org.apache.plc4x.java.s7.netty.model.params.items.S7AnyVarParameterItem; import org.apache.plc4x.java.s7.netty.model.params.items.VarParameterItem; +import org.apache.plc4x.java.s7.netty.model.payloads.CpuMessageSubscriptionServicePayload; import org.apache.plc4x.java.s7.netty.model.payloads.CpuServicesPayload; import org.apache.plc4x.java.s7.netty.model.payloads.S7Payload; import org.apache.plc4x.java.s7.netty.model.payloads.VarPayload; @@ -54,10 +58,6 @@ Licensed to the Apache Software Foundation (ASF) under one import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.lang.reflect.Field; -import java.nio.charset.StandardCharsets; -import java.util.*; - /** * Communication Layer between the Application level ({@link Plc4XS7Protocol}) and the lower level (tcp) that sends and receives {@link S7Message}s. * This layer also handles the control over the "wire", i.e., the queues of incoming and outgoing messages. @@ -230,7 +230,11 @@ private void encodePayloads(S7Message in, ByteBuf buf) throws PlcProtocolExcepti encodeWriteVarPayload((VarPayload) payload, buf, !payloadIterator.hasNext()); break; case CPU_SERVICES: - encodeCpuServicesPayload((CpuServicesPayload) payload, buf); + if (payload instanceof CpuServicesPayload) { + encodeCpuServicesPayload((CpuServicesPayload) payload, buf); + } else if (payload instanceof CpuMessageSubscriptionServicePayload) { + encodeCpuMessageSubcriptionPayload((CpuMessageSubscriptionServicePayload) payload, buf); + } break; default: throw new PlcProtocolException("Writing payloads of type " + @@ -254,8 +258,28 @@ private void encodeWriteVarPayload(VarPayload varPayload, ByteBuf buf, boolean l } } + private void encodeCpuMessageSubcriptionPayload(CpuMessageSubscriptionServicePayload cpuServicesPayload, ByteBuf buf) + throws PlcProtocolException { + buf.writeByte(cpuServicesPayload.getReturnCode().getCode()); + buf.writeByte(cpuServicesPayload.getDataTransportSize().getCode()); + if ((cpuServicesPayload.getSubscribedEvents() & 0x80) == 0){ + buf.writeShort(0x000A); + } else { + buf.writeShort(0x000C); + }; + buf.writeByte(cpuServicesPayload.getSubscribedEvents()); + buf.writeByte(0x00); + buf.writeBytes(cpuServicesPayload.getId().getBytes()); + if ((cpuServicesPayload.getSubscribedEvents() & 0x80) == 0x80){ + buf.writeByte(cpuServicesPayload.getAlarm().getCode()); + buf.writeByte(0x00); + } + System.out.println("Paso por aqui...."); + } + private void encodeCpuServicesPayload(CpuServicesPayload cpuServicesPayload, ByteBuf buf) throws PlcProtocolException { + buf.writeByte(cpuServicesPayload.getReturnCode().getCode()); // This seems to be constantly set to this. buf.writeByte(DataTransportSize.OCTET_STRING.getCode()); diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuMessageSubscriptionResponsePayload.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuMessageSubscriptionResponsePayload.java new file mode 100644 index 00000000000..25213130e86 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuMessageSubscriptionResponsePayload.java @@ -0,0 +1,21 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.apache.plc4x.java.s7.netty.model.payloads; + +import org.apache.plc4x.java.s7.netty.model.types.ParameterType; + +/** + * + * @author cgarcia + */ +public class CpuMessageSubscriptionResponsePayload implements S7Payload { + + @Override + public ParameterType getType() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuMessageSubscriptionServicePayload.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuMessageSubscriptionServicePayload.java new file mode 100644 index 00000000000..b742e4c2489 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuMessageSubscriptionServicePayload.java @@ -0,0 +1,72 @@ +/* +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.netty.model.payloads; + +import org.apache.plc4x.java.s7.netty.model.types.AlarmType; +import org.apache.plc4x.java.s7.netty.model.types.DataTransportErrorCode; +import org.apache.plc4x.java.s7.netty.model.types.DataTransportSize; +import org.apache.plc4x.java.s7.netty.model.types.ParameterType; + +/** + * + * @author cgarcia + */ +public class CpuMessageSubscriptionServicePayload implements S7Payload { + + private final DataTransportErrorCode returnCode; + private final DataTransportSize dataTransportSize; + private final byte SubscribedEvents; + private final String Id; //8 bytes string + private final AlarmType alarm; + + + public CpuMessageSubscriptionServicePayload (DataTransportErrorCode returnCode, DataTransportSize dataTransportSize, byte SubscribedEvents, String Id, AlarmType alarm) { + this.returnCode = returnCode; + this.dataTransportSize = dataTransportSize; + this.SubscribedEvents = SubscribedEvents; + this.Id = Id; + this.alarm = alarm; + } + + @Override + public ParameterType getType() { + return ParameterType.CPU_SERVICES; + } + + public DataTransportErrorCode getReturnCode() { + return returnCode; + } + + public DataTransportSize getDataTransportSize() { + return dataTransportSize; + } + + public byte getSubscribedEvents() { + return SubscribedEvents; + } + + public String getId() { + return Id; + } + + public AlarmType getAlarm() { + return alarm; + } + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuServicesPayload.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuServicesPayload.java index f62b991594c..43a33abfe97 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuServicesPayload.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuServicesPayload.java @@ -18,14 +18,13 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.s7.netty.model.payloads; +import java.util.Collections; +import java.util.List; import org.apache.plc4x.java.s7.netty.model.payloads.ssls.SslDataRecord; import org.apache.plc4x.java.s7.netty.model.types.DataTransportErrorCode; import org.apache.plc4x.java.s7.netty.model.types.ParameterType; import org.apache.plc4x.java.s7.netty.model.types.SslId; -import java.util.Collections; -import java.util.List; - public class CpuServicesPayload implements S7Payload { private DataTransportErrorCode returnCode; diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/AlarmType.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/AlarmType.java new file mode 100644 index 00000000000..9fb87785fb0 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/AlarmType.java @@ -0,0 +1,81 @@ +/* + 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.netty.model.types; + +import java.util.HashMap; +import java.util.Map; +import org.apache.plc4x.java.api.model.PlcField; + +/** + * + * @author cgarcia + */ +public enum AlarmType implements PlcField { + + SCAN_ABORT("SCAN_ABORT", (byte) 0x00), + SCAN_INITIATE("SCAN_INITIATE", (byte) 0x01), + ALARM_ABORT("ALARM_ABORT", (byte) 0x04), + ALARM_INITIATE("ALARM_INITIATE", (byte) 0x05), + ALARM_S_ABORT("ALARM_S_ABORT", (byte) 0x08), + ALARM_S_INITIATE("ALARM_S_INITIATE", (byte) 0x09), + NONE("NONE", (byte) 0xff), + ; + + + private static final Map map; + + static { + map = new HashMap<>(); + for (AlarmType subevent : AlarmType.values()) { + map.put(subevent.code, subevent); + } + } + + private final String event; + private final byte code; + + AlarmType(String event, byte code){ + this.event = event; + this.code = code; + } + + public String getEvent(){ + return event; + } + + public byte getCode() { + return code; + } + + public static AlarmType valueOfEvent(String event) { + for (AlarmType value : AlarmType.values()) { + if(value.getEvent().equals(event)) { + return value; + } + } + return null; + } + + public static AlarmType valueOf(byte code) { + return map.get(code); + } + + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuServicesParameterSubFunctionGroup.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuServicesParameterSubFunctionGroup.java index a99b6e83a15..f7e1b161acf 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuServicesParameterSubFunctionGroup.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuServicesParameterSubFunctionGroup.java @@ -18,15 +18,15 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.s7.netty.model.types; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.HashMap; import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public enum CpuServicesParameterSubFunctionGroup { - READ_SSL((byte) 0x01); + READ_SSL((byte) 0x01), + MESSAGE_SERVICE((byte) 0x02); private static final Logger logger = LoggerFactory.getLogger(CpuServicesParameterSubFunctionGroup.class); diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/PushEventType.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/PushEventType.java new file mode 100644 index 00000000000..ca9e0b01cbe --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/PushEventType.java @@ -0,0 +1,67 @@ +/* + 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.netty.model.types; + +import java.util.HashMap; +import java.util.Map; +import org.apache.plc4x.java.api.model.PlcField; + +/** + * + * @author cgarcia + */ +public enum PushEventType implements PlcField { + + ALARM_SQ("ALARM_SQ"), + ALARM_S("ALARM_S"), + ALARM_SC("ALARM_SC"), + ALARM_DQ("ALARM_DQ"), + ALARM_D("ALARM_D"), + NOTIFY_8P("NOTIFY_8P"), + ALARM("ALARM"), + ALARM_8("ALARM_8"), + ALARM_8P("ALARM_8P"), + NOTIFY("NOTIFY"); + + private static final Map map; + + static { + map = new HashMap<>(); + for (PushEventType s7event : PushEventType.values()) { + map.put(s7event.event, s7event); + } + } + + private final String event; + + PushEventType(String event){ + this.event = event; + } + + public String getEvent(){ + return event; + } + + public static PushEventType valueOfEvent(String event) { + return map.get(event); + } + + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/SubscribedEventType.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/SubscribedEventType.java new file mode 100644 index 00000000000..d963343b844 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/SubscribedEventType.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.java.s7.netty.model.types; + +import java.util.HashMap; +import java.util.Map; +import org.apache.plc4x.java.api.model.PlcField; + +/** + * + * @author cgarcia + */ +public enum SubscribedEventType implements PlcField { + + MODE("MODE", (byte) 0x01), + SYS("SYS", (byte) 0x02), + USR("USR", (byte) 0x04), + ALM("ALM", (byte) 0x80); + + private static final Map map; + + static { + map = new HashMap<>(); + for (SubscribedEventType subevent : SubscribedEventType.values()) { + map.put(subevent.code, subevent); + } + } + + private final String event; + private final byte code; + + SubscribedEventType(String event, byte code){ + this.event = event; + this.code = code; + } + + public String getEvent(){ + return event; + } + + public byte getCode() { + return code; + } + + public static SubscribedEventType valueOfEvent(String event) { + for (SubscribedEventType value : SubscribedEventType.values()) { + if(value.getEvent().equals(event)) { + return value; + } + } + return null; + } + + public static SubscribedEventType valueOf(byte code) { + return map.get(code); + } + + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7PlcEventHandler.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7PlcEventHandler.java new file mode 100644 index 00000000000..c009caee8fa --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7PlcEventHandler.java @@ -0,0 +1,38 @@ +/* + 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.netty.util; + +import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; +import org.apache.plc4x.java.api.model.PlcField; +import org.apache.plc4x.java.base.connection.DefaultPlcFieldHandler; +import org.apache.plc4x.java.s7.netty.model.types.SubscribedEventType; + +/** + * + * + */ +public class S7PlcEventHandler extends DefaultPlcFieldHandler { + + @Override + public PlcField createField(String fieldQuery) throws PlcInvalidFieldException { + return SubscribedEventType.valueOfEvent(fieldQuery); + } + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7SizeHelper.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7SizeHelper.java index 0967866390b..4a3313d32e7 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7SizeHelper.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7SizeHelper.java @@ -18,11 +18,13 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.s7.netty.util; +import java.util.List; import org.apache.plc4x.java.s7.netty.model.params.CpuServicesRequestParameter; import org.apache.plc4x.java.s7.netty.model.params.S7Parameter; import org.apache.plc4x.java.s7.netty.model.params.VarParameter; import org.apache.plc4x.java.s7.netty.model.params.items.S7AnyVarParameterItem; import org.apache.plc4x.java.s7.netty.model.params.items.VarParameterItem; +import org.apache.plc4x.java.s7.netty.model.payloads.CpuMessageSubscriptionServicePayload; import org.apache.plc4x.java.s7.netty.model.payloads.CpuServicesPayload; import org.apache.plc4x.java.s7.netty.model.payloads.S7Payload; import org.apache.plc4x.java.s7.netty.model.payloads.VarPayload; @@ -32,8 +34,6 @@ Licensed to the Apache Software Foundation (ASF) under one import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.List; - public class S7SizeHelper { private static final Logger logger = LoggerFactory.getLogger(S7SizeHelper.class); @@ -75,6 +75,14 @@ public static short getPayloadsLength(List payloads) { } return length; } + } else if(payload instanceof CpuMessageSubscriptionServicePayload) { + CpuMessageSubscriptionServicePayload submsg = (CpuMessageSubscriptionServicePayload) payload; + if ((submsg.getSubscribedEvents() & 0x80) == 0x00){ + return 14; + } else { + return 16; + } + } } return l; diff --git a/vim.exe.stackdump b/vim.exe.stackdump new file mode 100644 index 00000000000..1eb2c6b7748 --- /dev/null +++ b/vim.exe.stackdump @@ -0,0 +1,19 @@ +Stack trace: +Frame Function Args +00180000000 0018006137E (0018024DB99, 0018024E199, 000FFFFC530, 000FFFFB6C0) +00180000000 00180049229 (CCCCCC00009CC1, FF783B00767676, D6D661000CC616, 0000152ACFC) +00180000000 00180049262 (0018024DB76, 000FFFFC428, 000FFFFC530, 76767600CCCCCC) +00180000000 00180045E73 (00000000000, 00180000000, 00000000000, 001800004F4) +00180000000 0018006F6E1 (CCCCCC00009CC1, FF783B00767676, D6D661000CC616, 9E00B4005648E7) +00180000000 0018007056E (00000000000, 0010067ED68, 00000000000, 00000000000) +00180000000 00180072B34 (00000000000, 00000000008, 00000000000, 00000000000) +00000000000 00180146933 (0010067ED60, 00000000008, 00000000000, 00000000000) +00000000000 0018012C3DB (0010067ED60, 00000000008, 00000000000, 00000000000) +00000000000 001004F2A94 (001005773A5, 00100685748, 00000000000, 0010068574C) +00000000000 0010058A496 (00000000008, 00000000000, 00000000000, 00000000000) +00000000000 001005783AE (00000000000, 006000BEAE0, 00000000000, 00100000000) +00000000000 001005EAAF3 (0018021EFA0, 00000000000, 0018012C3DB, 00180339FA0) +00000000000 001005F5FE4 (00000000020, 0018030FA20, 0018004A818, 001800497E0) +000FFFFCCD0 0018004A884 (00000000000, 00000000000, 00000000000, 00000000000) +00000000000 00180048343 (00000000000, 00000000000, 00000000000, 00000000000) +End of stack trace (more stack frames may be present) From e1c5b987056c8826f0d0be11f9630bd7e7fae5db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Fri, 20 Dec 2019 19:58:47 -0400 Subject: [PATCH 03/17] Receive push messages. lack of debugging and mounting the infrastructure for the management of subscribers. --- .../plc4x/java/s7/netty/Plc4XS7Protocol.java | 30 ++ .../plc4x/java/s7/netty/S7Protocol.java | 394 ++++++++++++++++-- .../params/CpuServicesPushParameter.java | 51 +++ .../params/CpuServicesRequestParameter.java | 7 +- .../params/CpuServicesResponseParameter.java | 9 +- .../model/payloads/AlarmMessagePayload.java | 79 ++++ ...CpuMessageSubscriptionResponsePayload.java | 46 +- .../CpuMessageSubscriptionServicePayload.java | 7 +- .../payloads/items/AlarmMessageItem.java | 100 +++++ .../payloads/items/AssociatedValueItem.java | 64 +++ .../payloads/items/MessageObjectItem.java | 158 +++++++ .../CpuServicesParameterSubFunctionGroup.java | 17 +- 12 files changed, 911 insertions(+), 51 deletions(-) create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuServicesPushParameter.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/AlarmMessagePayload.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/AlarmMessageItem.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/AssociatedValueItem.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/MessageObjectItem.java 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 86e91bc669d..8c2e44b8342 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 @@ -19,6 +19,7 @@ Licensed to the Apache Software Foundation (ASF) under one package org.apache.plc4x.java.s7.netty; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import java.io.IOException; @@ -61,9 +62,12 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.netty.model.params.VarParameter; import org.apache.plc4x.java.s7.netty.model.params.items.S7AnyVarParameterItem; import org.apache.plc4x.java.s7.netty.model.params.items.VarParameterItem; +import org.apache.plc4x.java.s7.netty.model.payloads.AlarmMessagePayload; import org.apache.plc4x.java.s7.netty.model.payloads.CpuMessageSubscriptionServicePayload; import org.apache.plc4x.java.s7.netty.model.payloads.S7Payload; import org.apache.plc4x.java.s7.netty.model.payloads.VarPayload; +import org.apache.plc4x.java.s7.netty.model.payloads.items.AssociatedValueItem; +import org.apache.plc4x.java.s7.netty.model.payloads.items.MessageObjectItem; import org.apache.plc4x.java.s7.netty.model.payloads.items.VarPayloadItem; import org.apache.plc4x.java.s7.netty.model.types.*; import org.slf4j.Logger; @@ -453,13 +457,16 @@ byte[] encodeWriteRequestStringField(BaseDefaultFieldItem fieldItem, boolean isU @Override protected void decode(ChannelHandlerContext ctx, S7Message msg, List out) throws PlcException { // We're currently just expecting responses. + logger.info("Message Type: " + msg.getMessageType()); if (!(msg instanceof S7ResponseMessage)) { + logger.info("Aborta decode: " + msg.getMessageType()); return; } S7ResponseMessage responseMessage = (S7ResponseMessage) msg; short tpduReference = responseMessage.getTpduReference(); if (requests.containsKey(tpduReference)) { // As every response has a matching request, get this request based on the tpdu. + logger.info("tpduReference: " + tpduReference); PlcRequestContainer requestContainer = requests.remove(tpduReference); PlcRequest request = requestContainer.getRequest(); @@ -469,12 +476,35 @@ protected void decode(ChannelHandlerContext ctx, S7Message msg, List out response = decodeReadResponse(responseMessage, requestContainer); } else if (request instanceof PlcWriteRequest) { response = decodeWriteResponse(responseMessage, requestContainer); + } else if (request instanceof PlcSubscriptionRequest) { + logger.info("Debo verificar si la suscripción fu exitosa..."); + } else { + logger.info("Existe la solicitud del cliente, pero no es una respuesta valida..."); } // Confirm the response being handled. if (response != null) { requestContainer.getResponseFuture().complete(response); + } else { + logger.info("No se pudo procesar el mensaje..."); } + } else { + logger.info("Posible mensaje PUSH..."); + List payloads = msg.getPayloads(); + for (S7Payload payload:payloads){ + if (payload instanceof AlarmMessagePayload){ + logger.info("S7PayLoad tipo AlarmMessagePayload: " + payload.toString()); + AlarmMessagePayload alarm = (AlarmMessagePayload) payload; + List msgobjects = alarm.getMsg().getMsgItems(); + for (MessageObjectItem msgobject:msgobjects){ + logger.info("Item tipo MessageObjectItem: " + msgobject.toString() + " Size: " + msgobject.getComingValues().size()); + List items = msgobject.getComingValues(); + for (AssociatedValueItem item:items){ + logger.info("ReturnCode :" + item.getReturnCode() + " Length: " + item.getLength() + " Data: " + ByteBufUtil.hexDump(item.getData())); + } + } + } + } } } 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 7770c2a228f..7a1964bf7b7 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 @@ -44,10 +44,14 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.netty.model.params.*; import org.apache.plc4x.java.s7.netty.model.params.items.S7AnyVarParameterItem; import org.apache.plc4x.java.s7.netty.model.params.items.VarParameterItem; +import org.apache.plc4x.java.s7.netty.model.payloads.AlarmMessagePayload; import org.apache.plc4x.java.s7.netty.model.payloads.CpuMessageSubscriptionServicePayload; import org.apache.plc4x.java.s7.netty.model.payloads.CpuServicesPayload; import org.apache.plc4x.java.s7.netty.model.payloads.S7Payload; import org.apache.plc4x.java.s7.netty.model.payloads.VarPayload; +import org.apache.plc4x.java.s7.netty.model.payloads.items.AlarmMessageItem; +import org.apache.plc4x.java.s7.netty.model.payloads.items.AssociatedValueItem; +import org.apache.plc4x.java.s7.netty.model.payloads.items.MessageObjectItem; import org.apache.plc4x.java.s7.netty.model.payloads.items.VarPayloadItem; import org.apache.plc4x.java.s7.netty.model.payloads.ssls.SslDataRecord; import org.apache.plc4x.java.s7.netty.model.payloads.ssls.SslModuleIdentificationDataRecord; @@ -274,7 +278,6 @@ private void encodeCpuMessageSubcriptionPayload(CpuMessageSubscriptionServicePay buf.writeByte(cpuServicesPayload.getAlarm().getCode()); buf.writeByte(0x00); } - System.out.println("Paso por aqui...."); } private void encodeCpuServicesPayload(CpuServicesPayload cpuServicesPayload, ByteBuf buf) @@ -483,7 +486,9 @@ protected void decode(ChannelHandlerContext ctx, IsoTPMessage in, List o short userDataLength = userData.readShort(); byte errorClass = 0; byte errorCode = 0; + if (isResponse) { + logger.info("Mensaje de respuesta"); errorClass = userData.readByte(); errorCode = userData.readByte(); } @@ -499,6 +504,7 @@ protected void decode(ChannelHandlerContext ctx, IsoTPMessage in, List o } i += S7SizeHelper.getParameterLength(parameter); } + //TODO: Se pierden dos bytes de la Data List s7Payloads = decodePayloads(userData, isResponse, userDataLength, s7Parameters); @@ -549,21 +555,28 @@ protected void decode(ChannelHandlerContext ctx, IsoTPMessage in, List o } else { // CpuService responses are encoded as requests. + // for (S7Parameter s7Parameter : s7Parameters) { // Only if we have a response parameter, the payload is a response payload. if(s7Parameter instanceof CpuServicesResponseParameter) { + logger.info("*** Aqui verifica el tipo del s7Parameter..."); for (S7Payload s7Payload : s7Payloads) { if(s7Payload instanceof CpuServicesPayload) { CpuServicesPayload cpuServicesPayload = (CpuServicesPayload) s7Payload; - // Remove the current response from the list of unconfirmed messages. + logger.info("*** Aqui verifica el tipo del Payload..."); sentButUnacknowledgedTpdus.remove(tpduReference); handleIdentifyRemote(ctx, cpuServicesPayload); } } + } else if (s7Parameter instanceof CpuServicesPushParameter){ + logger.info("*** MENSAGE PUSH ***"); + out.add(new S7ResponseMessage(messageType, tpduReference, s7Parameters, s7Payloads, errorClass, errorCode)); + return; } } + logger.info("Envia el mensaje a la proxima capa como S7RequestMessage"); out.add(new S7RequestMessage(messageType, tpduReference, s7Parameters, s7Payloads, null)); } } @@ -639,7 +652,7 @@ private List decodePayloads(ByteBuf userData, boolean isResponse, sho VarPayload varPayload = decodeVarPayload(userData, isResponse, userDataLength, readWriteVarParameter); s7Payloads.add(varPayload); } else if(s7Parameter instanceof CpuServicesParameter) { - CpuServicesPayload cpuServicesPayload = decodeCpuServicesPayload(userData); + S7Payload cpuServicesPayload = decodeCpuServicesPayload((CpuServicesParameter)s7Parameter, userData); s7Payloads.add(cpuServicesPayload); } } @@ -684,43 +697,92 @@ else if ((readWriteVarParameter.getType() == ParameterType.READ_VAR) && isRespon return new VarPayload(readWriteVarParameter.getType(), payloadItems); } - private CpuServicesPayload decodeCpuServicesPayload(ByteBuf userData) { - DataTransportErrorCode returnCode = DataTransportErrorCode.valueOf(userData.readByte()); - DataTransportSize dataTransportSize = DataTransportSize.valueOf(userData.readByte()); - if(dataTransportSize != DataTransportSize.OCTET_STRING) { - // TODO: Output an error. - } - short length = userData.readShort(); - SslId sslId = SslId.valueOf(userData.readShort()); - short sslIndex = userData.readShort(); - // If the length is 4 there is no `partial list length in bytes` and `partial list count` parameters. - if(length == 4) { - return new CpuServicesPayload(returnCode, sslId, sslIndex); - } - // If the length is not 4, then it has to be at least 8. - else if(length >= 8) { - // TODO: We should probably ensure we don't read more than this. - // Skip the partial list length in words. - userData.skipBytes(2); - short partialListCount = userData.readShort(); - List sslDataRecords = new LinkedList<>(); - for(int i = 0; i < partialListCount; i++) { - short index = userData.readShort(); - byte[] articleNumberBytes = new byte[20]; - userData.readBytes(articleNumberBytes); - String articleNumber = new String(articleNumberBytes, StandardCharsets.UTF_8).trim(); - short bgType = userData.readShort(); - short moduleOrOsVersion = userData.readShort(); - short pgDescriptionFileVersion = userData.readShort(); - sslDataRecords.add(new SslModuleIdentificationDataRecord( - index, articleNumber, bgType, moduleOrOsVersion, pgDescriptionFileVersion)); + private S7Payload decodeCpuServicesPayload(CpuServicesParameter parameter, ByteBuf userData) { + + switch(parameter.getSubFunctionGroup()){ + case READ_SSL: { + DataTransportErrorCode returnCode = DataTransportErrorCode.valueOf(userData.readByte()); + DataTransportSize dataTransportSize = DataTransportSize.valueOf(userData.readByte()); + if(dataTransportSize != DataTransportSize.OCTET_STRING) { + // TODO: Output an error. + } + short length = userData.readShort(); + SslId sslId = SslId.valueOf(userData.readShort()); + short sslIndex = userData.readShort(); + // If the length is 4 there is no `partial list length in bytes` and `partial list count` parameters. + if(length == 4) { + return new CpuServicesPayload(returnCode, sslId, sslIndex); + } + // If the length is not 4, then it has to be at least 8. + else if(length >= 8) { + // TODO: We should probably ensure we don't read more than this. + // Skip the partial list length in words. + userData.skipBytes(2); + short partialListCount = userData.readShort(); + List sslDataRecords = new LinkedList<>(); + for(int i = 0; i < partialListCount; i++) { + short index = userData.readShort(); + byte[] articleNumberBytes = new byte[20]; + userData.readBytes(articleNumberBytes); + String articleNumber = new String(articleNumberBytes, StandardCharsets.UTF_8).trim(); + short bgType = userData.readShort(); + short moduleOrOsVersion = userData.readShort(); + short pgDescriptionFileVersion = userData.readShort(); + sslDataRecords.add(new SslModuleIdentificationDataRecord( + index, articleNumber, bgType, moduleOrOsVersion, pgDescriptionFileVersion)); + } + return new CpuServicesPayload(returnCode, sslId, sslIndex, sslDataRecords); + } + // In all other cases, it's probably an error. + else { + // TODO: Output an error. + } } - return new CpuServicesPayload(returnCode, sslId, sslIndex, sslDataRecords); - } - // In all other cases, it's probably an error. - else { - // TODO: Output an error. + break; + case MESSAGE_SERVICE:{ + AlarmMessagePayload msg = decodeMessageServicePayload(parameter, userData); + return msg; + } + case DIAG_MESSAGE:; + break; + case ALARM8:; + break; + case NOTIFY:; + break; + case ALARM8_LOCK:; + break; + case ALARM8_UNLOCK:; + break; + case SCAN:; + break; + case ALARM_ACK:{ + AlarmMessagePayload msg = decodeMessageServiceAckPayload(parameter, userData); + return msg; + } + case ALARM_ACK_IND:; + break; + case ALARM8_LOCK_IND:; + break; + case ALARM8_UNLOCK_IND:; + break; + case ALARM_SQ_IND:{ + AlarmMessagePayload msg = decodeMessageServicePushPayload(parameter, userData); + return msg; + } + case ALARM_S_IND: { + AlarmMessagePayload msg = decodeMessageServicePushPayload(parameter, userData); + return msg; + } + case ALARM_QUERY:{ + AlarmMessagePayload msg = decodeMessageServiceQueryPayload(parameter, userData); + return msg; + } + case NOTIFY8:; + break; + default:; + break; } + return null; } @@ -760,6 +822,7 @@ private S7Parameter decodeParameter(ByteBuf in, boolean isResponse) { } private CpuServicesParameter decodeCpuServicesParameter(ByteBuf in) { + logger.info("decodeCpuServicesParameter: \r\n " + ByteBufUtil.prettyHexDump(in) ); if(in.readShort() != 0x0112) { if (logger.isErrorEnabled()) { logger.error("Expecting 0x0112 for CPU_SERVICES parameter"); @@ -777,17 +840,26 @@ private CpuServicesParameter decodeCpuServicesParameter(ByteBuf in) { in.readByte(); byte typeAndFunctionGroup = in.readByte(); // If bit 7 is set, it's a request (if bit 8 is set it's a response). - boolean requestParameter = (typeAndFunctionGroup & 0x64) != 0; + //Must be for request: 0x40 for check X100 0X00 + //For Push message is 0000 XXXX, Request is 0100 XXXX, Response 1000 XXXX + boolean pushParameter = (typeAndFunctionGroup & 0xF0) == 0; + boolean requestParameter = (typeAndFunctionGroup & 0x40) != 0; + boolean responseParameter = (typeAndFunctionGroup & 0x80) != 0; // The last 4 bits contain the function group value. - typeAndFunctionGroup = (byte) (typeAndFunctionGroup & 0xF); + typeAndFunctionGroup = (byte) (typeAndFunctionGroup & 0x0F); CpuServicesParameterFunctionGroup functionGroup = CpuServicesParameterFunctionGroup.valueOf(typeAndFunctionGroup); CpuServicesParameterSubFunctionGroup subFunctionGroup = CpuServicesParameterSubFunctionGroup.valueOf(in.readByte()); byte sequenceNumber = in.readByte(); - if(!requestParameter) { + if(pushParameter) { + logger.info("Es un parametro push..."); + return new CpuServicesPushParameter(functionGroup, subFunctionGroup, sequenceNumber); + } else if (requestParameter) { + logger.info("Es un parametro de petición..."); return new CpuServicesRequestParameter(functionGroup, subFunctionGroup, sequenceNumber); } else { + logger.info("Es un parametro de respuesta..."); byte dataUnitReferenceNumber = in.readByte(); boolean lastDataUnit = in.readByte() == 0x00; ParameterError error = ParameterError.valueOf(in.readShort()); @@ -834,7 +906,247 @@ private List decodeReadWriteVarParameter(ByteBuf in, byte numI return items; } + + private AlarmMessagePayload decodeMessageServicePayload(CpuServicesParameter parameter, ByteBuf userData){ + logger.info("userData: \r\n" + ByteBufUtil.prettyHexDump(userData) ); + DataTransportErrorCode returnCode = DataTransportErrorCode.valueOf(userData.readByte()); + DataTransportSize dataTransportSize = DataTransportSize.valueOf(userData.readByte()); + int length = userData.readShort(); + byte result = userData.readByte(); + byte unknown = userData.readByte(); + AlarmType alarmtype = null; + + if (length>2) { + alarmtype = AlarmType.valueOf(userData.readByte()); + unknown = userData.readByte(); + unknown = userData.readByte(); + } else { + //Free dummy byte + + } + + return new AlarmMessagePayload(returnCode, + dataTransportSize, + alarmtype, + length, + null); + } + + private AlarmMessagePayload decodeMessageServicePushPayload(CpuServicesParameter parameter, ByteBuf userData){ + logger.info("Push userData: \r\n " + ByteBufUtil.prettyHexDump(userData) ); + List MessageObjects = new LinkedList<>(); + List values = new LinkedList<>(); + int length; + //Alarm message + Calendar timestamp; + Byte FunctionID; + byte NumberOfMessgaeObjects; + // + DataTransportErrorCode returnCode = DataTransportErrorCode.valueOf(userData.readByte()); + DataTransportSize dataTransportSize = DataTransportSize.valueOf(userData.readByte()); + length = userData.readShort(); + + //It is assumed that you have synchronized the time of your PLC with PC. + // + timestamp = Calendar.getInstance(); + timestamp.set(2000 + userData.readByte(), + userData.readByte()-1, + userData.readByte(), + userData.readByte(), + userData.readByte(), + userData.readByte()); + int milliseconds = (userData.readShort() & 0xfff8) >> 3; + timestamp.setTimeInMillis(timestamp.getTimeInMillis() + milliseconds); + + FunctionID = userData.readByte(); + NumberOfMessgaeObjects = userData.readByte(); + logger.info("NumberOfMessgaeObjects = " + NumberOfMessgaeObjects); + for (int i = 0; i < NumberOfMessgaeObjects; i++){ + { + byte VariableSpecification = userData.readByte(); + byte Length = userData.readByte(); + VariableAddressingMode SyntaxID = VariableAddressingMode.valueOf(userData.readByte()); + byte NumberOfValues = userData.readByte(); + int EventID = userData.readInt(); + byte EventState = userData.readByte(); + byte State = userData.readByte(); + byte AckStateGoing = userData.readByte(); + byte AckStateComming = userData.readByte(); + + List AssociatedValues = new LinkedList<>(); + + logger.info("NumberOfValues = " + NumberOfValues); + + for (int j = 0; j < NumberOfValues; j++){ + { + DataTransportErrorCode valueCode = DataTransportErrorCode.valueOf(userData.readByte()); + DataTransportSize valueTransportSize = DataTransportSize.valueOf(userData.readByte()); + int valueLength = userData.readShort(); + //Max length of value is 12 bytes + valueLength = (valueLength >> 4)*2; + logger.info("Numero de valores transferidos = " + valueLength + " Valores disponibles: " + userData.readableBytes()); + ByteBuf Data = userData.readBytes(valueLength); + AssociatedValues.add(new AssociatedValueItem(valueCode, + valueTransportSize, + valueLength, + Data)); + } + } + + MessageObjects.add( new MessageObjectItem(VariableSpecification, + Length, + SyntaxID, + NumberOfValues, + EventID, + EventState, + State, + AckStateGoing, + AckStateComming, + AssociatedValues)); + + } + return new AlarmMessagePayload(returnCode, + dataTransportSize, + parameter.getSubFunctionGroup(), + length, + new AlarmMessageItem(timestamp, + FunctionID, + NumberOfMessgaeObjects, + MessageObjects)); + + } + + + return null; + }; + + private AlarmMessagePayload decodeMessageServiceQueryPayload(CpuServicesParameter parameter, ByteBuf userData){ + List MessageObjects = new LinkedList<>(); + int length; + byte FunctionID; + byte NumberOfMessageObjects; //Say 1, but I have 2 messages? Why? + DataTransportErrorCode AlarmReturnCode; + DataTransportSize AlarmTransportSize; + int CompleteDataLength; + + //Data section + DataTransportErrorCode returnCode = DataTransportErrorCode.valueOf(userData.readByte()); + DataTransportSize dataTransportSize = DataTransportSize.valueOf(userData.readByte()); + length = userData.readShort(); //Number of message objects? + + //Alarm message information + FunctionID = userData.readByte(); + NumberOfMessageObjects = userData.readByte(); + AlarmReturnCode = DataTransportErrorCode.valueOf(userData.readByte()); + AlarmTransportSize = DataTransportSize.valueOf(userData.readByte()); + CompleteDataLength = userData.readShort(); + + //Message Object + for (int i = 0; i < NumberOfMessageObjects; i++){ + byte LengthOfDataSet = userData.readByte(); + int Unknown_1 = userData.readShort(); + Object AlarmType = CpuServicesParameterSubFunctionGroup.valueOf(userData.readByte()); + int EnentID = userData.readShort(); + int Unknown_2 = userData.readShort(); + byte EventState = userData.readByte(); + byte AckStateGoing = userData.readByte(); + byte AckStateComing = userData.readByte(); + Calendar timestampComing; + + timestampComing = Calendar.getInstance(); + timestampComing.set(2000 + userData.readByte(), + userData.readByte()-1, + userData.readByte(), + userData.readByte(), + userData.readByte(), + userData.readByte()); + int milliseconds = (userData.readInt() & 0xfff8) >> 3; + timestampComing.setTimeInMillis(timestampComing.getTimeInMillis() + milliseconds); + + List ComingValues = new LinkedList<>(); + + int NumberOfValues = 1; + + for (int j = 0; j < NumberOfValues; j++){ + DataTransportErrorCode valueCode = DataTransportErrorCode.valueOf(userData.readByte()); + DataTransportSize valueTransportSize = DataTransportSize.valueOf(userData.readByte()); + int valueLength = userData.readInt(); + ByteBuf Data = userData.readBytes(valueLength); + ComingValues.add(new AssociatedValueItem(valueCode, + valueTransportSize, + valueLength, + Data)); + } + + Calendar timestampGoing; + + timestampGoing = Calendar.getInstance(); + timestampGoing.set(2000 + userData.readByte(), + userData.readByte()-1, + userData.readByte(), + userData.readByte(), + userData.readByte(), + userData.readByte()); + milliseconds = (userData.readInt() & 0xfff8) >> 3; + timestampGoing.setTimeInMillis(timestampGoing.getTimeInMillis() + milliseconds); + + List GoingValues = new LinkedList<>(); + + for (int j = 0; j < NumberOfValues; j++){ + DataTransportErrorCode valueCode = DataTransportErrorCode.valueOf(userData.readByte()); + DataTransportSize valueTransportSize = DataTransportSize.valueOf(userData.readByte()); + int valueLength = userData.readInt(); + ByteBuf Data = userData.readBytes(valueLength); + GoingValues.add(new AssociatedValueItem(valueCode, + valueTransportSize, + valueLength, + Data)); + } + + return new AlarmMessagePayload(returnCode, + dataTransportSize, + CpuServicesParameterSubFunctionGroup.ALARM_QUERY, + length, + new AlarmMessageItem(FunctionID, + NumberOfMessageObjects, + AlarmReturnCode, + AlarmTransportSize, + CompleteDataLength, + MessageObjects)); + } + return null; + } + + private AlarmMessagePayload decodeMessageServiceAckPayload(CpuServicesParameter parameter, ByteBuf userData){ + List MessageObjects = new LinkedList<>(); + //Data section + DataTransportErrorCode returnCode = DataTransportErrorCode.valueOf(userData.readByte()); + DataTransportSize dataTransportSize = DataTransportSize.valueOf(userData.readByte()); + int length = userData.readShort(); //Number of message objects? + + //Alarm message section + byte FunctionID = userData.readByte(); + byte NumberOfMessageObjects = userData.readByte(); + + //In the next leve if is != null -> Success + if (userData.readByte() != 0xff) { + MessageObjects = null; + } + + return new AlarmMessagePayload(returnCode, + dataTransportSize, + CpuServicesParameterSubFunctionGroup.ALARM_QUERY, + length, + new AlarmMessageItem(FunctionID, + NumberOfMessageObjects, + null, + null, + 0, + MessageObjects)); + + } + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Helpers //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuServicesPushParameter.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuServicesPushParameter.java new file mode 100644 index 00000000000..8d02c60925d --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuServicesPushParameter.java @@ -0,0 +1,51 @@ +/* +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.netty.model.params; + +import org.apache.plc4x.java.s7.netty.model.types.CpuServicesParameterFunctionGroup; +import org.apache.plc4x.java.s7.netty.model.types.CpuServicesParameterSubFunctionGroup; +import org.apache.plc4x.java.s7.netty.model.types.ParameterError; + +/** + * + * @author cgarcia + */ +public class CpuServicesPushParameter extends CpuServicesParameter { + + private byte dataUnitReferenceNumber; + private boolean lastDataUnit; + private ParameterError error; + + public CpuServicesPushParameter(CpuServicesParameterFunctionGroup functionGroup, CpuServicesParameterSubFunctionGroup subFunctionGroup, byte sequenceNumber) { + super(functionGroup, subFunctionGroup, sequenceNumber); + } + + public byte getDataUnitReferenceNumber() { + return dataUnitReferenceNumber; + } + + public boolean isLastDataUnit() { + return lastDataUnit; + } + + public ParameterError getError() { + return error; + } + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuServicesRequestParameter.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuServicesRequestParameter.java index 21a0484745b..ee9509fdfb1 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuServicesRequestParameter.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuServicesRequestParameter.java @@ -18,12 +18,15 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.s7.netty.model.params; -import org.apache.plc4x.java.s7.netty.model.types.CpuServicesParameterSubFunctionGroup; import org.apache.plc4x.java.s7.netty.model.types.CpuServicesParameterFunctionGroup; +import org.apache.plc4x.java.s7.netty.model.types.CpuServicesParameterSubFunctionGroup; public class CpuServicesRequestParameter extends CpuServicesParameter { - public CpuServicesRequestParameter(CpuServicesParameterFunctionGroup functionGroup, CpuServicesParameterSubFunctionGroup subFunctionGroup, byte sequenceNumber) { + public CpuServicesRequestParameter(CpuServicesParameterFunctionGroup functionGroup, + CpuServicesParameterSubFunctionGroup subFunctionGroup, + byte sequenceNumber) { + super(functionGroup, subFunctionGroup, sequenceNumber); } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuServicesResponseParameter.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuServicesResponseParameter.java index 69fb0b63db3..35182022f9b 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuServicesResponseParameter.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuServicesResponseParameter.java @@ -18,8 +18,8 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.s7.netty.model.params; -import org.apache.plc4x.java.s7.netty.model.types.CpuServicesParameterSubFunctionGroup; import org.apache.plc4x.java.s7.netty.model.types.CpuServicesParameterFunctionGroup; +import org.apache.plc4x.java.s7.netty.model.types.CpuServicesParameterSubFunctionGroup; import org.apache.plc4x.java.s7.netty.model.types.ParameterError; public class CpuServicesResponseParameter extends CpuServicesParameter { @@ -28,7 +28,12 @@ public class CpuServicesResponseParameter extends CpuServicesParameter { private boolean lastDataUnit; private ParameterError error; - public CpuServicesResponseParameter(CpuServicesParameterFunctionGroup functionGroup, CpuServicesParameterSubFunctionGroup subFunctionGroup, byte sequenceNumber, byte dataUnitReferenceNumber, boolean lastDataUnit, ParameterError error) { + public CpuServicesResponseParameter(CpuServicesParameterFunctionGroup functionGroup, + CpuServicesParameterSubFunctionGroup subFunctionGroup, + byte sequenceNumber, + byte dataUnitReferenceNumber, + boolean lastDataUnit, ParameterError error) { + super(functionGroup, subFunctionGroup, sequenceNumber); this.dataUnitReferenceNumber = dataUnitReferenceNumber; this.lastDataUnit = lastDataUnit; diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/AlarmMessagePayload.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/AlarmMessagePayload.java new file mode 100644 index 00000000000..77bbf5262f6 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/AlarmMessagePayload.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.netty.model.payloads; + +import org.apache.plc4x.java.s7.netty.model.payloads.items.AlarmMessageItem; +import org.apache.plc4x.java.s7.netty.model.types.DataTransportErrorCode; +import org.apache.plc4x.java.s7.netty.model.types.DataTransportSize; +import org.apache.plc4x.java.s7.netty.model.types.ParameterType; + +/** + * + * @author cgarcia + */ +public class AlarmMessagePayload implements S7Payload { + + private final DataTransportErrorCode returnCode; + private final DataTransportSize dataTransportSize; + private final Object msgtype; + private final Integer length; + private final AlarmMessageItem msg; + + public AlarmMessagePayload(DataTransportErrorCode returnCode, + DataTransportSize dataTransportSize, + Object msgtype, + Integer length, + AlarmMessageItem msg) { + this.returnCode = returnCode; + this.dataTransportSize = dataTransportSize; + this.msgtype = msgtype; + this.length = length; + this.msg = msg; + } + + + @Override + public ParameterType getType() { + return ParameterType.CPU_SERVICES; + } + + public DataTransportErrorCode getReturnCode() { + return returnCode; + } + + public DataTransportSize getDataTransportSize() { + return dataTransportSize; + } + + public Object getMsgtype() { + return msgtype; + } + + public Integer getLength() { + return length; + } + + public AlarmMessageItem getMsg() { + return msg; + } + + + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuMessageSubscriptionResponsePayload.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuMessageSubscriptionResponsePayload.java index 25213130e86..ff52f4f5919 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuMessageSubscriptionResponsePayload.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuMessageSubscriptionResponsePayload.java @@ -1,10 +1,27 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ +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.netty.model.payloads; +import org.apache.plc4x.java.s7.netty.model.types.AlarmType; +import org.apache.plc4x.java.s7.netty.model.types.DataTransportErrorCode; +import org.apache.plc4x.java.s7.netty.model.types.DataTransportSize; import org.apache.plc4x.java.s7.netty.model.types.ParameterType; /** @@ -13,6 +30,27 @@ */ public class CpuMessageSubscriptionResponsePayload implements S7Payload { + private final DataTransportErrorCode returnCode; + private final DataTransportSize dataTransportSize; + private final int Length; + private final byte Result; + private final AlarmType alarm; + + public CpuMessageSubscriptionResponsePayload(DataTransportErrorCode returnCode, + DataTransportSize dataTransportSize, + int Length, + byte Result, + AlarmType alarm) { + + this.returnCode = returnCode; + this.dataTransportSize = dataTransportSize; + this.Length = Length; + this.Result = Result; + this.alarm = alarm; + } + + + @Override public ParameterType getType() { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuMessageSubscriptionServicePayload.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuMessageSubscriptionServicePayload.java index b742e4c2489..df234ac112b 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuMessageSubscriptionServicePayload.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuMessageSubscriptionServicePayload.java @@ -36,7 +36,12 @@ public class CpuMessageSubscriptionServicePayload implements S7Payload { private final AlarmType alarm; - public CpuMessageSubscriptionServicePayload (DataTransportErrorCode returnCode, DataTransportSize dataTransportSize, byte SubscribedEvents, String Id, AlarmType alarm) { + public CpuMessageSubscriptionServicePayload (DataTransportErrorCode returnCode, + DataTransportSize dataTransportSize, + byte SubscribedEvents, + String Id, + AlarmType alarm) { + this.returnCode = returnCode; this.dataTransportSize = dataTransportSize; this.SubscribedEvents = SubscribedEvents; diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/AlarmMessageItem.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/AlarmMessageItem.java new file mode 100644 index 00000000000..5cdefec32b1 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/AlarmMessageItem.java @@ -0,0 +1,100 @@ +/* +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.netty.model.payloads.items; + +import java.util.Calendar; +import java.util.List; +import org.apache.plc4x.java.s7.netty.model.types.DataTransportErrorCode; +import org.apache.plc4x.java.s7.netty.model.types.DataTransportSize; + +/** + * + * @author cgarcia + */ +public class AlarmMessageItem { + private final DataTransportErrorCode returnCode; + private final DataTransportSize dataTransportSize; + private final Calendar timestamp; + private final byte function; + private final byte objects; + private final int Length; + private final List msgItems; + + public AlarmMessageItem(Calendar timestamp, + byte function, + byte objects, + List msgItems) { + + this.timestamp = timestamp; + this.function = function; + this.objects = objects; + this.msgItems = msgItems; + this.returnCode = null; + this.dataTransportSize = null; + this.Length = 0; + } + + public AlarmMessageItem(byte function, + byte objects, + DataTransportErrorCode returnCode, + DataTransportSize dataTransportSize, + int Length, + List msgItems){ + this.function = function; + this.objects = objects; + this.returnCode = returnCode; + this.dataTransportSize = dataTransportSize; + this.Length = Length; + this.timestamp = null; + this.msgItems = msgItems; + }; + + + + public DataTransportErrorCode getReturnCode() { + return returnCode; + } + + public DataTransportSize getDataTransportSize() { + return dataTransportSize; + } + + public Calendar getTimestamp() { + return timestamp; + } + + public byte getFunction() { + return function; + } + + public byte getObjects() { + return objects; + } + + public int getLength() { + return Length; + } + + public List getMsgItems() { + return msgItems; + } + + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/AssociatedValueItem.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/AssociatedValueItem.java new file mode 100644 index 00000000000..c9676afd2e6 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/AssociatedValueItem.java @@ -0,0 +1,64 @@ +/* +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.netty.model.payloads.items; + +import io.netty.buffer.ByteBuf; +import org.apache.plc4x.java.s7.netty.model.types.DataTransportErrorCode; +import org.apache.plc4x.java.s7.netty.model.types.DataTransportSize; + +/** + * + * @author cgarcia + */ +public class AssociatedValueItem { + private final DataTransportErrorCode returnCode; + private final DataTransportSize dataTransportSize; + private final int Length; + private final ByteBuf Data; + + public AssociatedValueItem(DataTransportErrorCode returnCode, DataTransportSize dataTransportSize, int Length, ByteBuf Data) { + this.returnCode = returnCode; + this.dataTransportSize = dataTransportSize; + this.Length = Length; + this.Data = Data; + } + + public DataTransportErrorCode getReturnCode() { + return returnCode; + } + + public DataTransportSize getDataTransportSize() { + return dataTransportSize; + } + + public int getLength() { + return Length; + } + + public ByteBuf getData() { + return Data; + } + + + + + + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/MessageObjectItem.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/MessageObjectItem.java new file mode 100644 index 00000000000..a8c36458766 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/MessageObjectItem.java @@ -0,0 +1,158 @@ +/* +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.netty.model.payloads.items; + +import java.util.Calendar; +import java.util.List; + +/** + * + * @author cgarcia + */ +public class MessageObjectItem { + + private final byte VariableSpecification; + private final byte Length; + private final Object SyntaxID; + private final byte NumberOfValues; + private final int EventID; + private final byte EventState; + private final byte State; + private final byte AckStateGoing; + private final byte AckStateComming; + private final Calendar TimestampComing; + private final Calendar TimestampGoing; + private final List ComingValues; + private final List GoingValues; + + public MessageObjectItem(byte VariableSpecification, + byte Length, + Object SyntaxID, + byte NumberOfValues, + int EventID, + byte EventState, + byte State, + byte AckStateGoing, + byte AckStateComming, + List Values) { + + this.VariableSpecification = VariableSpecification; + this.Length = Length; + this.SyntaxID = SyntaxID; + this.NumberOfValues = NumberOfValues; + this.EventID = EventID; + this.EventState = EventState; + this.State = State; + this.AckStateGoing = AckStateGoing; + this.AckStateComming = AckStateComming; + this.TimestampComing = null; + this.ComingValues = Values; + this.TimestampGoing = null; + this.GoingValues = null; + } + + public MessageObjectItem(byte VariableSpecification, + byte Length, + Object SyntaxID, + byte NumberOfValues, + int EventID, + byte EventState, + byte State, + byte AckStateGoing, + byte AckStateComming, + Calendar TimestampComing, + List ComingValues, + Calendar TimestampGoing, + List GoingValues) { + + this.VariableSpecification = VariableSpecification; + this.Length = Length; + this.SyntaxID = SyntaxID; + this.NumberOfValues = NumberOfValues; + this.EventID = EventID; + this.EventState = EventState; + this.State = State; + this.AckStateGoing = AckStateGoing; + this.AckStateComming = AckStateComming; + this.TimestampComing = TimestampComing; + this.ComingValues = ComingValues; + this.TimestampGoing = TimestampGoing; + this.GoingValues = GoingValues; + } + + public byte getVariableSpecification() { + return VariableSpecification; + } + + public byte getLength() { + return Length; + } + + public Object getSyntaxID() { + return SyntaxID; + } + + public byte getNumberOfValues() { + return NumberOfValues; + } + + public int getEventID() { + return EventID; + } + + public byte getEventState() { + return EventState; + } + + public byte getState() { + return State; + } + + public byte getAckStateGoing() { + return AckStateGoing; + } + + public byte getAckStateComming() { + return AckStateComming; + } + + public Calendar getTimestampComing() { + return TimestampComing; + } + + public Calendar getTimestampGoing() { + return TimestampGoing; + } + + public List getComingValues() { + return ComingValues; + } + + public List getGoingValues() { + return GoingValues; + } + + + + + + + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuServicesParameterSubFunctionGroup.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuServicesParameterSubFunctionGroup.java index f7e1b161acf..5b679a5fe0f 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuServicesParameterSubFunctionGroup.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuServicesParameterSubFunctionGroup.java @@ -26,7 +26,22 @@ Licensed to the Apache Software Foundation (ASF) under one public enum CpuServicesParameterSubFunctionGroup { READ_SSL((byte) 0x01), - MESSAGE_SERVICE((byte) 0x02); + MESSAGE_SERVICE((byte) 0x02), + DIAG_MESSAGE((byte) 0x03), + ALARM_S((byte) 0x04), + ALARM8((byte) 0x05), + NOTIFY((byte) 0x06), + ALARM8_LOCK((byte) 0x07), + ALARM8_UNLOCK((byte) 0x08), + SCAN((byte) 0x04), + ALARM_ACK((byte) 0x0b), + ALARM_ACK_IND((byte) 0x0c), + ALARM8_LOCK_IND((byte) 0x0d), + ALARM8_UNLOCK_IND((byte) 0x0e), + ALARM_SQ_IND((byte) 0x11), + ALARM_S_IND((byte) 0x12), + ALARM_QUERY((byte) 0x13), + NOTIFY8((byte) 0x16); //TODO private static final Logger logger = LoggerFactory.getLogger(CpuServicesParameterSubFunctionGroup.class); From b0a7efadf69b091645ca97fb3ce9a08099c4d841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Fri, 27 Dec 2019 22:49:21 -0400 Subject: [PATCH 04/17] Progress for handling alarms and Push messages from the S7 PLC. --- .../java/s7/connection/S7PlcConnection.java | 78 ++- .../plc4x/java/s7/netty/Plc4XS7Protocol.java | 28 +- .../plc4x/java/s7/netty/S7Protocol.java | 80 +-- .../plc4x/java/s7/netty/events/S7Alarm.java | 498 ++++++++++++++++++ .../s7/netty/model/types/AlarmQueryType.java | 74 +++ 5 files changed, 716 insertions(+), 42 deletions(-) create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/events/S7Alarm.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/AlarmQueryType.java diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java index 7ce24fa7c34..7653b061862 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java @@ -23,6 +23,8 @@ Licensed to the Apache Software Foundation (ASF) under one import java.net.InetAddress; import java.util.Collection; import java.util.Collections; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -59,6 +61,7 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.model.S7Field; import org.apache.plc4x.java.s7.netty.Plc4XS7Protocol; import org.apache.plc4x.java.s7.netty.S7Protocol; +import org.apache.plc4x.java.s7.netty.model.payloads.AlarmMessagePayload; import org.apache.plc4x.java.s7.netty.model.types.MemoryArea; import org.apache.plc4x.java.s7.netty.strategies.DefaultS7MessageProcessor; import org.apache.plc4x.java.s7.netty.util.S7PlcEventHandler; @@ -105,6 +108,9 @@ public class S7PlcConnection extends NettyPlcConnection implements PlcReader, Pl private final short paramMaxAmqCallee; private final S7ControllerType paramControllerType; + private BlockingQueue alarmsqueue; + private AlarmsLoop alarmsloopthread; + public S7PlcConnection(InetAddress address, int rack, int slot, String params) { this(new TcpSocketChannelFactory(address, ISO_ON_TCP_PORT), rack, slot, params); @@ -165,6 +171,20 @@ public S7PlcConnection(ChannelFactory channelFactory, int rack, int slot, String this.paramMaxAmqCaller = curParamMaxAmqCaller; this.paramMaxAmqCallee = curParamMaxAmqCallee; this.paramControllerType = curParamControllerType; + + + /* + * Take into account that the size of this buffer depends on the final device. + * S7-300 goes from 20 to 300 and for S7-400 it goes from 300 to 10000. + * Depending on the configuration of the alarm system, a large number of + * them should be expected when starting the connection. + * (Examples of this are PCS7 and Braumat). + * Alarm filtering, ack, etc. must be performed by the client application. + */ + this.alarmsqueue = new ArrayBlockingQueue<>(1024); + + alarmsloopthread = new AlarmsLoop(channel,this.alarmsqueue); + } @Override @@ -176,6 +196,8 @@ public boolean canRead() { public boolean canWrite() { return true; } + + @Override protected ChannelHandler getChannelHandler(CompletableFuture sessionSetupCompleteFuture) { @@ -203,7 +225,7 @@ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exc pipeline.addLast(new IsoTPProtocol(callingTsapId, calledTsapId, TpduSize.valueForGivenSize(paramPduSize))); pipeline.addLast(new S7Protocol(paramMaxAmqCaller, paramMaxAmqCallee, paramPduSize, paramControllerType, new DefaultS7MessageProcessor())); - pipeline.addLast(new Plc4XS7Protocol()); + pipeline.addLast(new Plc4XS7Protocol(alarmsqueue)); } }; } @@ -243,8 +265,16 @@ public S7ControllerType getParamControllerType() { return paramControllerType; } + @Override + public void connect() throws PlcConnectionException { + super.connect(); + alarmsloopthread.start(); + } + + @Override public void close() throws PlcConnectionException { + alarmsloopthread.cancel(); if ((channel != null) && channel.isOpen()) { // Send the PLC a message that the connection is being closed. DisconnectRequestTpdu disconnectRequest = new DisconnectRequestTpdu( @@ -372,4 +402,50 @@ public void unregister(PlcConsumerRegistration registration) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } + private class AlarmsLoop extends Thread { + private volatile boolean cancelled; + private final Channel channel; + private boolean alarmquery; + private int delay; + private final BlockingQueue alarmsqueue; + + AlarmsLoop(Channel channel, BlockingQueue alarmsqueue) { + this.channel = channel; + this.alarmsqueue = alarmsqueue; + this.alarmquery = true; + this.delay = 1; + } + + @Override + public void run() { + while (!cancelled) { + try { + AlarmMessagePayload alarm = alarmsqueue.poll(delay, TimeUnit.SECONDS); + if (alarm != null){ + logger.info("Alarm type: " + alarm.getMsgtype() + " Número de alarmas: " + alarm.getMsg().getObjects()); + + } else { + if (alarmquery){ + //TODO Send alarm query to plc + } else { + + } + } + } catch (InterruptedException ex) { + logger.info(ex.getLocalizedMessage()); + } + } + logger.info("Closing the alarm loop."); + } + + public void cancel() { + cancelled = true; + } + + public boolean isCancelled() { + return cancelled; + } + + } + } 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 8c2e44b8342..ab34621ad23 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 @@ -19,7 +19,6 @@ Licensed to the Apache Software Foundation (ASF) under one package org.apache.plc4x.java.s7.netty; import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import java.io.IOException; @@ -32,6 +31,7 @@ Licensed to the Apache Software Foundation (ASF) under one import java.time.LocalTime; import java.time.temporal.ChronoUnit; import java.util.*; +import java.util.concurrent.BlockingQueue; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.stream.Collectors; @@ -66,8 +66,6 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.netty.model.payloads.CpuMessageSubscriptionServicePayload; import org.apache.plc4x.java.s7.netty.model.payloads.S7Payload; import org.apache.plc4x.java.s7.netty.model.payloads.VarPayload; -import org.apache.plc4x.java.s7.netty.model.payloads.items.AssociatedValueItem; -import org.apache.plc4x.java.s7.netty.model.payloads.items.MessageObjectItem; import org.apache.plc4x.java.s7.netty.model.payloads.items.VarPayloadItem; import org.apache.plc4x.java.s7.netty.model.types.*; import org.slf4j.Logger; @@ -88,10 +86,24 @@ public class Plc4XS7Protocol extends PlcMessageToMessageCodec requests; + + private final BlockingQueue alarmsqueue; public Plc4XS7Protocol() { this.requests = new HashMap<>(); + this.alarmsqueue = null; + } + /* + * @param s7Type + * + */ + public Plc4XS7Protocol(BlockingQueue alarmsqueue) { + this.requests = new HashMap<>(); + //We need check the device here + this.alarmsqueue = alarmsqueue; } + + /** * If this protocol layer catches an {@link S7ConnectedEvent} from the protocol layer beneath, @@ -490,11 +502,16 @@ protected void decode(ChannelHandlerContext ctx, S7Message msg, List out } } else { logger.info("Posible mensaje PUSH..."); - List payloads = msg.getPayloads(); + List payloads = msg.getPayloads(); + //TODO: Use alarmsqueue.addAll() method for (S7Payload payload:payloads){ if (payload instanceof AlarmMessagePayload){ logger.info("S7PayLoad tipo AlarmMessagePayload: " + payload.toString()); AlarmMessagePayload alarm = (AlarmMessagePayload) payload; + if (!alarmsqueue.offer(alarm)){ + logger.info("Alarm queue buffer is full."); + }; + /* List msgobjects = alarm.getMsg().getMsgItems(); for (MessageObjectItem msgobject:msgobjects){ logger.info("Item tipo MessageObjectItem: " + msgobject.toString() + " Size: " + msgobject.getComingValues().size()); @@ -503,6 +520,7 @@ protected void decode(ChannelHandlerContext ctx, S7Message msg, List out logger.info("ReturnCode :" + item.getReturnCode() + " Length: " + item.getLength() + " Data: " + ByteBufUtil.hexDump(item.getData())); } } + */ } } } @@ -923,5 +941,7 @@ private static int convertByteToBcd(byte incomingByte) { int dec = (incomingByte >> 4) * 10; return dec + (incomingByte & 0x0f); } + + } 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 7a1964bf7b7..50f86aa772f 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 @@ -400,6 +400,7 @@ private void encodeCpuServicesParameter(ByteBuf buf, CpuServicesParameter parame // This is a mixture of request/response and function group . byte nextByte = (byte) (((parameter instanceof CpuServicesRequestParameter) ? (byte) 0x40 : (byte) 0x80) | parameter.getFunctionGroup().getCode()); + //TODO for ALARM_QUERY bypass the next byte buf.writeByte(nextByte); buf.writeByte(parameter.getSubFunctionGroup().getCode()); buf.writeByte(parameter.getSequenceNumber()); @@ -701,44 +702,9 @@ private S7Payload decodeCpuServicesPayload(CpuServicesParameter parameter, ByteB switch(parameter.getSubFunctionGroup()){ case READ_SSL: { - DataTransportErrorCode returnCode = DataTransportErrorCode.valueOf(userData.readByte()); - DataTransportSize dataTransportSize = DataTransportSize.valueOf(userData.readByte()); - if(dataTransportSize != DataTransportSize.OCTET_STRING) { - // TODO: Output an error. - } - short length = userData.readShort(); - SslId sslId = SslId.valueOf(userData.readShort()); - short sslIndex = userData.readShort(); - // If the length is 4 there is no `partial list length in bytes` and `partial list count` parameters. - if(length == 4) { - return new CpuServicesPayload(returnCode, sslId, sslIndex); - } - // If the length is not 4, then it has to be at least 8. - else if(length >= 8) { - // TODO: We should probably ensure we don't read more than this. - // Skip the partial list length in words. - userData.skipBytes(2); - short partialListCount = userData.readShort(); - List sslDataRecords = new LinkedList<>(); - for(int i = 0; i < partialListCount; i++) { - short index = userData.readShort(); - byte[] articleNumberBytes = new byte[20]; - userData.readBytes(articleNumberBytes); - String articleNumber = new String(articleNumberBytes, StandardCharsets.UTF_8).trim(); - short bgType = userData.readShort(); - short moduleOrOsVersion = userData.readShort(); - short pgDescriptionFileVersion = userData.readShort(); - sslDataRecords.add(new SslModuleIdentificationDataRecord( - index, articleNumber, bgType, moduleOrOsVersion, pgDescriptionFileVersion)); - } - return new CpuServicesPayload(returnCode, sslId, sslIndex, sslDataRecords); - } - // In all other cases, it's probably an error. - else { - // TODO: Output an error. - } + CpuServicesPayload msg = decodeReadSslPayload(parameter, userData); + return msg; } - break; case MESSAGE_SERVICE:{ AlarmMessagePayload msg = decodeMessageServicePayload(parameter, userData); return msg; @@ -907,6 +873,46 @@ private List decodeReadWriteVarParameter(ByteBuf in, byte numI return items; } + private CpuServicesPayload decodeReadSslPayload(CpuServicesParameter parameter, ByteBuf userData){ + DataTransportErrorCode returnCode = DataTransportErrorCode.valueOf(userData.readByte()); + DataTransportSize dataTransportSize = DataTransportSize.valueOf(userData.readByte()); + if(dataTransportSize != DataTransportSize.OCTET_STRING) { + // TODO: Output an error. + } + short length = userData.readShort(); + SslId sslId = SslId.valueOf(userData.readShort()); + short sslIndex = userData.readShort(); + // If the length is 4 there is no `partial list length in bytes` and `partial list count` parameters. + if(length == 4) { + return new CpuServicesPayload(returnCode, sslId, sslIndex); + } + // If the length is not 4, then it has to be at least 8. + else if(length >= 8) { + // TODO: We should probably ensure we don't read more than this. + // Skip the partial list length in words. + userData.skipBytes(2); + short partialListCount = userData.readShort(); + List sslDataRecords = new LinkedList<>(); + for(int i = 0; i < partialListCount; i++) { + short index = userData.readShort(); + byte[] articleNumberBytes = new byte[20]; + userData.readBytes(articleNumberBytes); + String articleNumber = new String(articleNumberBytes, StandardCharsets.UTF_8).trim(); + short bgType = userData.readShort(); + short moduleOrOsVersion = userData.readShort(); + short pgDescriptionFileVersion = userData.readShort(); + sslDataRecords.add(new SslModuleIdentificationDataRecord( + index, articleNumber, bgType, moduleOrOsVersion, pgDescriptionFileVersion)); + } + return new CpuServicesPayload(returnCode, sslId, sslIndex, sslDataRecords); + } + // In all other cases, it's probably an error. + else { + // TODO: Output an error. + } + return null; + } + private AlarmMessagePayload decodeMessageServicePayload(CpuServicesParameter parameter, ByteBuf userData){ logger.info("userData: \r\n" + ByteBufUtil.prettyHexDump(userData) ); DataTransportErrorCode returnCode = DataTransportErrorCode.valueOf(userData.readByte()); diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/events/S7Alarm.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/events/S7Alarm.java new file mode 100644 index 00000000000..07b951e7778 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/events/S7Alarm.java @@ -0,0 +1,498 @@ +/* +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.netty.events; + +import io.netty.buffer.ByteBuf; +import static io.netty.buffer.Unpooled.buffer; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.Collection; +import java.util.Hashtable; +import org.apache.plc4x.java.api.messages.PlcReadRequest; +import org.apache.plc4x.java.api.messages.PlcSubscriptionEvent; +import org.apache.plc4x.java.api.model.PlcField; +import org.apache.plc4x.java.api.types.PlcResponseCode; +import org.apache.plc4x.java.s7.netty.model.payloads.items.AssociatedValueItem; +import org.apache.plc4x.java.s7.netty.model.payloads.items.MessageObjectItem; + +/** + * The S7Alarm object is a wrapper around MessageObjectItem to maintain + * compatibility with the top layer. + * At this point we can have any of the Push messages generated by the PLC for + * an event or a query request from the application, usually executed when the + * connection is initiated. The messages from the PLC can be of type: + * . Alarm + * . Alarm_8 + * . Alarm_8P + * . Alarm_S + * . Alarm_SQ + * . Alarm_D + * . Alarm_DQ + * . Alarm_DQ + * . Notify + * . Notify_8P + * To correctly evaluate the message, the "Subfunction" and "SyntaxId" field + * must be evaluated. In the case of the "Subfunction =" ALARM_QUERY "query, + * the type will be stored in" SyntaxId " + * + * @author cgarcia + */ +public class S7Alarm implements PlcSubscriptionEvent { + + private final MessageObjectItem s7alarm; + + private static final String SIG_1 = "SIG_1"; + private static final String SIG_2 = "SIG_2"; + private static final String SIG_3 = "SIG_3"; + private static final String SIG_4 = "SIG_4"; + private static final String SIG_5 = "SIG_5"; + private static final String SIG_6 = "SIG_6"; + private static final String SIG_7 = "SIG_7"; + private static final String SIG_8 = "SIG_8"; + + private static final Hashtable SIGS = new Hashtable() + {{ put(SIG_1, 0); + put(SIG_2, 1); + put(SIG_3, 2); + put(SIG_4, 3); + put(SIG_5, 4); + put(SIG_6, 5); + put(SIG_7, 6); + put(SIG_8, 7);}}; + + + public S7Alarm(MessageObjectItem s7alarm) { + this.s7alarm = s7alarm; + } + + @Override + public Instant getTimestamp() { + return s7alarm.getTimestampComing().toInstant(); + } + + @Override + public PlcReadRequest getRequest() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public int getNumberOfValues(String name) { + return s7alarm.getComingValues().size(); + } + + @Override + public Object getObject(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Object getObject(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllObjects(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidBoolean(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidBoolean(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Boolean getBoolean(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Boolean getBoolean(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllBooleans(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidByte(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidByte(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Byte getByte(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Byte getByte(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllBytes(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidShort(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidShort(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Short getShort(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Short getShort(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllShorts(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Integer getInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Integer getInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllIntegers(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidBigInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidBigInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public BigInteger getBigInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public BigInteger getBigInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllBigIntegers(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidLong(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidLong(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Long getLong(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Long getLong(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllLongs(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidFloat(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidFloat(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Float getFloat(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Float getFloat(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllFloats(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidDouble(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidDouble(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Double getDouble(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Double getDouble(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllDoubles(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidBigDecimal(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidBigDecimal(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public BigDecimal getBigDecimal(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public BigDecimal getBigDecimal(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllBigDecimals(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidString(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidString(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String getString(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String getString(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllStrings(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public LocalTime getTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public LocalTime getTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllTimes(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidDate(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidDate(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public LocalDate getDate(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public LocalDate getDate(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllDates(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidDateTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidDateTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public LocalDateTime getDateTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public LocalDateTime getDateTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllDateTimes(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidByteArray(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidByteArray(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Byte[] getByteArray(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Byte[] getByteArray(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllByteArrays(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getFieldNames() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public PlcField getField(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public PlcResponseCode getResponseCode(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + public ByteBuf getData(String name) { + return s7alarm.getComingValues().get(0).getData(); + } + + public ByteBuf getAllData() { + ByteBuf copy = buffer(12); + for(AssociatedValueItem item:s7alarm.getComingValues() ){ + copy.writeBytes(item.getData()); + } + return copy; + } + + + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/AlarmQueryType.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/AlarmQueryType.java new file mode 100644 index 00000000000..7dac7ac5a9f --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/AlarmQueryType.java @@ -0,0 +1,74 @@ +/* + 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.netty.model.types; + +import java.util.HashMap; +import java.util.Map; + +/** + * + * @author cgarcia + */ +public enum AlarmQueryType { + + SCAN("SCAN", (byte) 0x01), + ALARM_8("ALARM_8", (byte) 0x02), + ALARM_S("ALARM_S", (byte) 0x04), + NONE("NONE", (byte) 0x00); + + + private static final Map map; + + static { + map = new HashMap<>(); + for (AlarmQueryType subevent : AlarmQueryType .values()) { + map.put(subevent.code, subevent); + } + } + + private final String event; + private final byte code; + + AlarmQueryType(String event, byte code){ + this.event = event; + this.code = code; + } + + public String getEvent(){ + return event; + } + + public byte getCode() { + return code; + } + + public static AlarmQueryType valueOfEvent(String event) { + for (AlarmQueryType value : AlarmQueryType .values()) { + if(value.getEvent().equals(event)) { + return value; + } + } + return null; + } + + public static AlarmQueryType valueOf(byte code) { + return map.get(code); + } +} From 93d6e890686e97cde10a99012d25799fe1734a36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Tue, 7 Jan 2020 19:19:27 -0400 Subject: [PATCH 05/17] ALARM_S reception and PLC diagnostic messages are working. Preparation to perform alarm recognition from the application level. --- .../java/s7/connection/S7PlcConnection.java | 36 +- .../apache/plc4x/java/s7/model/S7Field.java | 15 +- .../plc4x/java/s7/netty/Plc4XS7Protocol.java | 61 ++- .../plc4x/java/s7/netty/S7Protocol.java | 247 ++++++--- .../netty/model/messages/S7PushMessage.java | 28 + .../params/CpuDiagnosticPushParameter.java | 87 ++++ .../params/CpuServicesPushParameter.java | 5 + .../model/payloads/AlarmMessagePayload.java | 13 +- .../payloads/CpuDiagnosticMessagePayload.java | 82 +++ .../payloads/items/AlarmMessageItem.java | 20 +- .../payloads/items/AssociatedValueItem.java | 13 +- .../items/CpuDiagnosticMessageItem.java | 95 ++++ .../payloads/items/MessageObjectItem.java | 20 + .../netty/model/types/CpuCurrentModeType.java | 83 +++ ...ServicesParameterSubFunctionGroupType.java | 79 +++ .../model/types/CpuUserDataMethodType.java | 77 +++ ...CpuUserDataParameterFunctionGroupType.java | 83 +++ .../model/types/CpuUserDataParameterType.java | 80 +++ .../s7/netty/model/types/ParameterType.java | 6 +- .../java/s7/netty/util/S7SizeHelper.java | 2 + .../java/s7/utils/S7DiagnosticEventId.java | 492 ++++++++++++++++++ .../plc4x/java/s7/utils/S7ParamErrorCode.java | 276 ++++++++++ 22 files changed, 1781 insertions(+), 119 deletions(-) create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/messages/S7PushMessage.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuDiagnosticPushParameter.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuDiagnosticMessagePayload.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/CpuDiagnosticMessageItem.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuCurrentModeType.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuCyclicServicesParameterSubFunctionGroupType.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuUserDataMethodType.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuUserDataParameterFunctionGroupType.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuUserDataParameterType.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7DiagnosticEventId.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7ParamErrorCode.java diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java index 7653b061862..3c7de57905a 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java @@ -61,7 +61,11 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.model.S7Field; import org.apache.plc4x.java.s7.netty.Plc4XS7Protocol; import org.apache.plc4x.java.s7.netty.S7Protocol; +import org.apache.plc4x.java.s7.netty.model.messages.S7PushMessage; +import org.apache.plc4x.java.s7.netty.model.params.CpuDiagnosticPushParameter; +import org.apache.plc4x.java.s7.netty.model.params.CpuServicesPushParameter; import org.apache.plc4x.java.s7.netty.model.payloads.AlarmMessagePayload; +import org.apache.plc4x.java.s7.netty.model.payloads.CpuDiagnosticMessagePayload; import org.apache.plc4x.java.s7.netty.model.types.MemoryArea; import org.apache.plc4x.java.s7.netty.strategies.DefaultS7MessageProcessor; import org.apache.plc4x.java.s7.netty.util.S7PlcEventHandler; @@ -108,7 +112,7 @@ public class S7PlcConnection extends NettyPlcConnection implements PlcReader, Pl private final short paramMaxAmqCallee; private final S7ControllerType paramControllerType; - private BlockingQueue alarmsqueue; + private BlockingQueue alarmsqueue; private AlarmsLoop alarmsloopthread; public S7PlcConnection(InetAddress address, int rack, int slot, String params) { @@ -171,8 +175,7 @@ public S7PlcConnection(ChannelFactory channelFactory, int rack, int slot, String this.paramMaxAmqCaller = curParamMaxAmqCaller; this.paramMaxAmqCallee = curParamMaxAmqCallee; this.paramControllerType = curParamControllerType; - - + /* * Take into account that the size of this buffer depends on the final device. * S7-300 goes from 20 to 300 and for S7-400 it goes from 300 to 10000. @@ -197,8 +200,6 @@ public boolean canWrite() { return true; } - - @Override protected ChannelHandler getChannelHandler(CompletableFuture sessionSetupCompleteFuture) { //short calledTsapId = S7TsapIdEncoder.encodeS7TsapId(DeviceGroup.OS, 0, 0); @@ -407,9 +408,9 @@ private class AlarmsLoop extends Thread { private final Channel channel; private boolean alarmquery; private int delay; - private final BlockingQueue alarmsqueue; + private final BlockingQueue alarmsqueue; - AlarmsLoop(Channel channel, BlockingQueue alarmsqueue) { + AlarmsLoop(Channel channel, BlockingQueue alarmsqueue) { this.channel = channel; this.alarmsqueue = alarmsqueue; this.alarmquery = true; @@ -420,10 +421,23 @@ private class AlarmsLoop extends Thread { public void run() { while (!cancelled) { try { - AlarmMessagePayload alarm = alarmsqueue.poll(delay, TimeUnit.SECONDS); - if (alarm != null){ - logger.info("Alarm type: " + alarm.getMsgtype() + " Número de alarmas: " + alarm.getMsg().getObjects()); - + S7PushMessage msg = alarmsqueue.poll(delay, TimeUnit.SECONDS); + if (msg != null){ + if (msg instanceof AlarmMessagePayload){ + AlarmMessagePayload themsg = (AlarmMessagePayload) msg; + logger.info("AlarmMessagePayload: " + themsg); + } else if (msg instanceof CpuDiagnosticPushParameter) { + CpuDiagnosticPushParameter themsg = (CpuDiagnosticPushParameter) msg; + logger.info("CpuDiagnosticPushParameter: " + themsg);; + } else if (msg instanceof CpuDiagnosticMessagePayload) { + CpuDiagnosticMessagePayload themsg = (CpuDiagnosticMessagePayload) msg; + logger.info("CpuDiagnosticMessagePayload: " + themsg); + } else if (msg instanceof CpuServicesPushParameter) { + CpuServicesPushParameter themsg = (CpuServicesPushParameter) msg; + logger.info("CpuServicesPushParameter: " + themsg); + } else { + logger.info("Object type: " + msg.getClass()); + } } else { if (alarmquery){ //TODO Send alarm query to plc diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java index 04620844b0a..13e2dd93370 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java @@ -18,17 +18,16 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.s7.model; -import org.apache.commons.lang3.NotImplementedException; -import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; -import org.apache.plc4x.java.api.model.PlcField; -import org.apache.plc4x.java.s7.netty.model.types.MemoryArea; -import org.apache.plc4x.java.s7.netty.model.types.TransportSize; - import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.commons.lang3.NotImplementedException; +import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; +import org.apache.plc4x.java.api.model.PlcField; +import org.apache.plc4x.java.s7.netty.model.types.MemoryArea; +import org.apache.plc4x.java.s7.netty.model.types.TransportSize; public class S7Field implements PlcField { @@ -39,6 +38,10 @@ public class S7Field implements PlcField { //blockNumber usually has its max hat around 64000 --> 5digits private static final Pattern DATA_BLOCK_ADDRESS_PATTERN = Pattern.compile("^%DB(?\\d{1,5}).DB(?[XBWD]?)(?\\d{1,7})(.(?[0-7]))?:(?[a-zA-Z_]+)(\\[(?\\d+)])?"); + + //Event Subscription + private static final Pattern EVENT_SUBSCRIPTION_TYPE_PATTERN = + Pattern.compile("MODE SYS USR ALM"); private static final String DATA_TYPE = "dataType"; private static final String TRANSFER_SIZE_CODE = "transferSizeCode"; 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 ab34621ad23..05f6df97b48 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 @@ -54,6 +54,7 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.model.S7Field; import org.apache.plc4x.java.s7.netty.events.S7ConnectedEvent; import org.apache.plc4x.java.s7.netty.model.messages.S7Message; +import org.apache.plc4x.java.s7.netty.model.messages.S7PushMessage; import org.apache.plc4x.java.s7.netty.model.messages.S7RequestMessage; import org.apache.plc4x.java.s7.netty.model.messages.S7ResponseMessage; import org.apache.plc4x.java.s7.netty.model.params.CpuServicesParameter; @@ -87,7 +88,7 @@ public class Plc4XS7Protocol extends PlcMessageToMessageCodec requests; - private final BlockingQueue alarmsqueue; + private final BlockingQueue alarmsqueue; public Plc4XS7Protocol() { this.requests = new HashMap<>(); @@ -97,7 +98,7 @@ public Plc4XS7Protocol() { * @param s7Type * */ - public Plc4XS7Protocol(BlockingQueue alarmsqueue) { + public Plc4XS7Protocol(BlockingQueue alarmsqueue) { this.requests = new HashMap<>(); //We need check the device here this.alarmsqueue = alarmsqueue; @@ -222,7 +223,7 @@ private void encodeSubcriptionRequest(PlcRequestContainer msg, List out) } private void encodeUnsubcriptionRequest(PlcRequestContainer msg, List out) throws PlcException { - + //TODO : Perform subscription termination } private void encodeReadRequest(PlcRequestContainer msg, List out) throws PlcException { @@ -460,7 +461,7 @@ byte[] encodeWriteRequestStringField(BaseDefaultFieldItem fieldItem, boolean isU // TODO: Implement this ... return new byte[0]; } - + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Decoding //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -469,16 +470,16 @@ byte[] encodeWriteRequestStringField(BaseDefaultFieldItem fieldItem, boolean isU @Override protected void decode(ChannelHandlerContext ctx, S7Message msg, List out) throws PlcException { // We're currently just expecting responses. - logger.info("Message Type: " + msg.getMessageType()); + if (!(msg instanceof S7ResponseMessage)) { logger.info("Aborta decode: " + msg.getMessageType()); return; } + S7ResponseMessage responseMessage = (S7ResponseMessage) msg; short tpduReference = responseMessage.getTpduReference(); if (requests.containsKey(tpduReference)) { // As every response has a matching request, get this request based on the tpdu. - logger.info("tpduReference: " + tpduReference); PlcRequestContainer requestContainer = requests.remove(tpduReference); PlcRequest request = requestContainer.getRequest(); @@ -489,43 +490,40 @@ protected void decode(ChannelHandlerContext ctx, S7Message msg, List out } else if (request instanceof PlcWriteRequest) { response = decodeWriteResponse(responseMessage, requestContainer); } else if (request instanceof PlcSubscriptionRequest) { - logger.info("Debo verificar si la suscripción fu exitosa..."); + response = decodeSubscriptionResponse(responseMessage, requestContainer); } else { - logger.info("Existe la solicitud del cliente, pero no es una respuesta valida..."); + logger.info("There is the client's request, but it is not a valid response...."); } // Confirm the response being handled. if (response != null) { requestContainer.getResponseFuture().complete(response); } else { - logger.info("No se pudo procesar el mensaje..."); + logger.info("The message could not be processed..."); } } else { - logger.info("Posible mensaje PUSH..."); + //PUSH Message + List parameters = msg.getParameters(); + for (S7Parameter parameter:parameters){ + if (parameter instanceof S7PushMessage){ + if (!alarmsqueue.offer((S7PushMessage) parameter)){ + logger.info("Alarm queue buffer is full."); + }; + } + } + List payloads = msg.getPayloads(); //TODO: Use alarmsqueue.addAll() method for (S7Payload payload:payloads){ - if (payload instanceof AlarmMessagePayload){ - logger.info("S7PayLoad tipo AlarmMessagePayload: " + payload.toString()); - AlarmMessagePayload alarm = (AlarmMessagePayload) payload; - if (!alarmsqueue.offer(alarm)){ + if (payload instanceof S7PushMessage){ + if (!alarmsqueue.offer((S7PushMessage) payload)){ logger.info("Alarm queue buffer is full."); }; - /* - List msgobjects = alarm.getMsg().getMsgItems(); - for (MessageObjectItem msgobject:msgobjects){ - logger.info("Item tipo MessageObjectItem: " + msgobject.toString() + " Size: " + msgobject.getComingValues().size()); - List items = msgobject.getComingValues(); - for (AssociatedValueItem item:items){ - logger.info("ReturnCode :" + item.getReturnCode() + " Length: " + item.getLength() + " Data: " + ByteBufUtil.hexDump(item.getData())); - } - } - */ } } } } - + // TODO: Check if it is a CPU service response and proceed as applicable. @SuppressWarnings("unchecked") private PlcResponse decodeReadResponse(S7ResponseMessage responseMessage, PlcRequestContainer requestContainer) throws PlcProtocolException { InternalPlcReadRequest plcReadRequest = (InternalPlcReadRequest) requestContainer.getRequest(); @@ -841,6 +839,19 @@ private PlcResponse decodeWriteResponse(S7ResponseMessage responseMessage, PlcRe return new DefaultPlcWriteResponse(plcWriteRequest, values); } + private PlcResponse decodeSubscriptionResponse(S7ResponseMessage responseMessage, PlcRequestContainer requestContainer) throws PlcProtocolException { + InternalPlcSubscriptionRequest subsRequest = (InternalPlcSubscriptionRequest) requestContainer.getRequest(); + List payloads = responseMessage.getPayloads(); + for (S7Payload payload:payloads){ + if(payload instanceof AlarmMessagePayload) { + logger.info("OK. Si pasa el mensaje como un Payload...: " + ((AlarmMessagePayload) payload).getReturnCode()); + //logger.info("Alarm Type...: " + ((AlarmMessagePayload) payload).getMsgtype()); + } + } + return new DefaultPlcSubscriptionResponse(subsRequest, null); + } + + private PlcResponseCode decodeResponseCode(DataTransportErrorCode dataTransportErrorCode) { if (dataTransportErrorCode == null) { return PlcResponseCode.INTERNAL_ERROR; 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 50f86aa772f..914abe9f912 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 @@ -27,6 +27,10 @@ Licensed to the Apache Software Foundation (ASF) under one import io.netty.util.concurrent.PromiseCombiner; import java.lang.reflect.Field; import java.nio.charset.StandardCharsets; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.temporal.ChronoUnit; import java.util.*; import org.apache.commons.lang3.reflect.FieldUtils; import org.apache.plc4x.java.api.exceptions.PlcProtocolException; @@ -45,12 +49,14 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.netty.model.params.items.S7AnyVarParameterItem; import org.apache.plc4x.java.s7.netty.model.params.items.VarParameterItem; import org.apache.plc4x.java.s7.netty.model.payloads.AlarmMessagePayload; +import org.apache.plc4x.java.s7.netty.model.payloads.CpuDiagnosticMessagePayload; import org.apache.plc4x.java.s7.netty.model.payloads.CpuMessageSubscriptionServicePayload; import org.apache.plc4x.java.s7.netty.model.payloads.CpuServicesPayload; import org.apache.plc4x.java.s7.netty.model.payloads.S7Payload; import org.apache.plc4x.java.s7.netty.model.payloads.VarPayload; import org.apache.plc4x.java.s7.netty.model.payloads.items.AlarmMessageItem; import org.apache.plc4x.java.s7.netty.model.payloads.items.AssociatedValueItem; +import org.apache.plc4x.java.s7.netty.model.payloads.items.CpuDiagnosticMessageItem; import org.apache.plc4x.java.s7.netty.model.payloads.items.MessageObjectItem; import org.apache.plc4x.java.s7.netty.model.payloads.items.VarPayloadItem; import org.apache.plc4x.java.s7.netty.model.payloads.ssls.SslDataRecord; @@ -489,7 +495,6 @@ protected void decode(ChannelHandlerContext ctx, IsoTPMessage in, List o byte errorCode = 0; if (isResponse) { - logger.info("Mensaje de respuesta"); errorClass = userData.readByte(); errorCode = userData.readByte(); } @@ -555,30 +560,29 @@ protected void decode(ChannelHandlerContext ctx, IsoTPMessage in, List o } } else { - // CpuService responses are encoded as requests. - // + // !CpuService responses are encoded as requests. + // No!, we need check in the next layer Plc4XS7Protocol like response for (S7Parameter s7Parameter : s7Parameters) { // Only if we have a response parameter, the payload is a response payload. if(s7Parameter instanceof CpuServicesResponseParameter) { - logger.info("*** Aqui verifica el tipo del s7Parameter..."); + for (S7Payload s7Payload : s7Payloads) { if(s7Payload instanceof CpuServicesPayload) { CpuServicesPayload cpuServicesPayload = (CpuServicesPayload) s7Payload; // Remove the current response from the list of unconfirmed messages. - logger.info("*** Aqui verifica el tipo del Payload..."); + sentButUnacknowledgedTpdus.remove(tpduReference); handleIdentifyRemote(ctx, cpuServicesPayload); } } } else if (s7Parameter instanceof CpuServicesPushParameter){ - logger.info("*** MENSAGE PUSH ***"); - out.add(new S7ResponseMessage(messageType, tpduReference, s7Parameters, s7Payloads, errorClass, errorCode)); - return; + //*** MENSAGE PUSH ***" + //out.add(new S7ResponseMessage(messageType, tpduReference, s7Parameters, s7Payloads, errorClass, errorCode)); } - } - logger.info("Envia el mensaje a la proxima capa como S7RequestMessage"); - out.add(new S7RequestMessage(messageType, tpduReference, s7Parameters, s7Payloads, null)); + } + //out.add(new S7RequestMessage(messageType, tpduReference, s7Parameters, s7Payloads, null)); + out.add(new S7ResponseMessage(messageType, tpduReference, s7Parameters, s7Payloads, errorClass, errorCode)); } } @@ -655,6 +659,9 @@ private List decodePayloads(ByteBuf userData, boolean isResponse, sho } else if(s7Parameter instanceof CpuServicesParameter) { S7Payload cpuServicesPayload = decodeCpuServicesPayload((CpuServicesParameter)s7Parameter, userData); s7Payloads.add(cpuServicesPayload); + } else if (s7Parameter instanceof CpuServicesPushParameter){ + S7Payload cpuServicesPayload = decodeCpuServicesPayload((CpuServicesParameter)s7Parameter, userData); + s7Payloads.add(cpuServicesPayload); } } return s7Payloads; @@ -702,15 +709,17 @@ private S7Payload decodeCpuServicesPayload(CpuServicesParameter parameter, ByteB switch(parameter.getSubFunctionGroup()){ case READ_SSL: { - CpuServicesPayload msg = decodeReadSslPayload(parameter, userData); - return msg; + CpuServicesPayload payload = decodeReadSslPayload(parameter, userData); + return payload; } case MESSAGE_SERVICE:{ - AlarmMessagePayload msg = decodeMessageServicePayload(parameter, userData); - return msg; + AlarmMessagePayload payload = decodeMessageServicePayload(parameter, userData); + return payload; + } + case DIAG_MESSAGE:{ + CpuDiagnosticMessagePayload payload = decodeCpuDiagnosticMessagePayload(parameter, userData); + return payload; } - case DIAG_MESSAGE:; - break; case ALARM8:; break; case NOTIFY:; @@ -722,8 +731,8 @@ private S7Payload decodeCpuServicesPayload(CpuServicesParameter parameter, ByteB case SCAN:; break; case ALARM_ACK:{ - AlarmMessagePayload msg = decodeMessageServiceAckPayload(parameter, userData); - return msg; + AlarmMessagePayload payload = decodeMessageServiceAckPayload(parameter, userData); + return payload; } case ALARM_ACK_IND:; break; @@ -732,16 +741,16 @@ private S7Payload decodeCpuServicesPayload(CpuServicesParameter parameter, ByteB case ALARM8_UNLOCK_IND:; break; case ALARM_SQ_IND:{ - AlarmMessagePayload msg = decodeMessageServicePushPayload(parameter, userData); - return msg; + AlarmMessagePayload payload = decodeMessageServicePushPayload(parameter, userData); + return payload; } case ALARM_S_IND: { - AlarmMessagePayload msg = decodeMessageServicePushPayload(parameter, userData); - return msg; + AlarmMessagePayload payload = decodeMessageServicePushPayload(parameter, userData); + return payload; } case ALARM_QUERY:{ - AlarmMessagePayload msg = decodeMessageServiceQueryPayload(parameter, userData); - return msg; + AlarmMessagePayload payload = decodeMessageServiceQueryPayload(parameter, userData); + return payload; } case NOTIFY8:; break; @@ -761,6 +770,8 @@ private S7Parameter decodeParameter(ByteBuf in, boolean isResponse) { switch (parameterType) { case CPU_SERVICES: return decodeCpuServicesParameter(in); + case MODE_TRANSITION: + return decodePushModeTransitionParameter(in); case READ_VAR: case WRITE_VAR: List varParameterItems; @@ -788,13 +799,14 @@ private S7Parameter decodeParameter(ByteBuf in, boolean isResponse) { } private CpuServicesParameter decodeCpuServicesParameter(ByteBuf in) { - logger.info("decodeCpuServicesParameter: \r\n " + ByteBufUtil.prettyHexDump(in) ); + if(in.readShort() != 0x0112) { if (logger.isErrorEnabled()) { logger.error("Expecting 0x0112 for CPU_SERVICES parameter"); } return null; } + byte parameterLength = in.readByte(); if((parameterLength != 4) && (parameterLength != 8)) { if (logger.isErrorEnabled()) { @@ -819,13 +831,10 @@ private CpuServicesParameter decodeCpuServicesParameter(ByteBuf in) { CpuServicesParameterSubFunctionGroup.valueOf(in.readByte()); byte sequenceNumber = in.readByte(); if(pushParameter) { - logger.info("Es un parametro push..."); return new CpuServicesPushParameter(functionGroup, subFunctionGroup, sequenceNumber); } else if (requestParameter) { - logger.info("Es un parametro de petición..."); return new CpuServicesRequestParameter(functionGroup, subFunctionGroup, sequenceNumber); } else { - logger.info("Es un parametro de respuesta..."); byte dataUnitReferenceNumber = in.readByte(); boolean lastDataUnit = in.readByte() == 0x00; ParameterError error = ParameterError.valueOf(in.readShort()); @@ -834,6 +843,32 @@ private CpuServicesParameter decodeCpuServicesParameter(ByteBuf in) { } } + private CpuDiagnosticPushParameter decodePushModeTransitionParameter(ByteBuf in) { + + if(in.readShort() != 0x0010) { + if (logger.isErrorEnabled()) { + logger.error("Expecting 0x0010 for MODE_TRANSITION parameter"); + } + return null; + } + + byte parameterLength = in.readByte(); + if((parameterLength != 16)) { + if (logger.isErrorEnabled()) { + logger.error("Parameter length should be 16, but was {}", parameterLength); + } + return null; + } + CpuUserDataMethodType usermethodtype = CpuUserDataMethodType.valueOf(in.readByte()); + byte typeandfunc = in.readByte(); + CpuUserDataParameterType userparamtype = CpuUserDataParameterType.valueOf((byte)(typeandfunc >> 4)); + CpuUserDataParameterFunctionGroupType userfunction = CpuUserDataParameterFunctionGroupType.valueOf((byte)(typeandfunc & 0x0f)); + CpuCurrentModeType cpumode = CpuCurrentModeType.valueOf(in.readByte()); + byte sequencenumber = in.readByte(); + return new CpuDiagnosticPushParameter(usermethodtype, userparamtype, userfunction, cpumode, sequencenumber); + } + + private List decodeReadWriteVarParameter(ByteBuf in, byte numItems) { List items = new LinkedList<>(); for (int i = 0; i < numItems; i++) { @@ -914,7 +949,7 @@ else if(length >= 8) { } private AlarmMessagePayload decodeMessageServicePayload(CpuServicesParameter parameter, ByteBuf userData){ - logger.info("userData: \r\n" + ByteBufUtil.prettyHexDump(userData) ); + DataTransportErrorCode returnCode = DataTransportErrorCode.valueOf(userData.readByte()); DataTransportSize dataTransportSize = DataTransportSize.valueOf(userData.readByte()); int length = userData.readShort(); @@ -938,13 +973,44 @@ private AlarmMessagePayload decodeMessageServicePayload(CpuServicesParameter par null); } + private CpuDiagnosticMessagePayload decodeCpuDiagnosticMessagePayload(CpuServicesParameter parameter, ByteBuf userData){ + + LocalDateTime timestamp; + DataTransportErrorCode returnCode = DataTransportErrorCode.valueOf(userData.readByte()); + DataTransportSize dataTransportSize = DataTransportSize.valueOf(userData.readByte()); + int length = userData.readShort(); //TODO: Validate userData length + short EventID = userData.readShort(); + byte PriorityClass = userData.readByte(); + byte ObNumber = userData.readByte(); + short DatID = userData.readShort(); + short Info1 = userData.readShort(); + int Info2 = userData.readInt(); + + //It is assumed that you have synchronized the time of your PLC with PC. + //TODO: Write util function for translate S7 DateTime + timestamp = readDateAndTime(userData); + + CpuDiagnosticMessageItem diagnosticitem = new CpuDiagnosticMessageItem(EventID, + PriorityClass, + ObNumber, + DatID, + Info1, + Info2, + timestamp); + + return new CpuDiagnosticMessagePayload(returnCode, + dataTransportSize, + length, + diagnosticitem); + } + private AlarmMessagePayload decodeMessageServicePushPayload(CpuServicesParameter parameter, ByteBuf userData){ - logger.info("Push userData: \r\n " + ByteBufUtil.prettyHexDump(userData) ); + List MessageObjects = new LinkedList<>(); List values = new LinkedList<>(); int length; //Alarm message - Calendar timestamp; + LocalDateTime timestamp; Byte FunctionID; byte NumberOfMessgaeObjects; // @@ -954,19 +1020,11 @@ private AlarmMessagePayload decodeMessageServicePushPayload(CpuServicesParameter //It is assumed that you have synchronized the time of your PLC with PC. // - timestamp = Calendar.getInstance(); - timestamp.set(2000 + userData.readByte(), - userData.readByte()-1, - userData.readByte(), - userData.readByte(), - userData.readByte(), - userData.readByte()); - int milliseconds = (userData.readShort() & 0xfff8) >> 3; - timestamp.setTimeInMillis(timestamp.getTimeInMillis() + milliseconds); + timestamp = readDateAndTime(userData); FunctionID = userData.readByte(); NumberOfMessgaeObjects = userData.readByte(); - logger.info("NumberOfMessgaeObjects = " + NumberOfMessgaeObjects); + for (int i = 0; i < NumberOfMessgaeObjects; i++){ { byte VariableSpecification = userData.readByte(); @@ -980,8 +1038,6 @@ private AlarmMessagePayload decodeMessageServicePushPayload(CpuServicesParameter byte AckStateComming = userData.readByte(); List AssociatedValues = new LinkedList<>(); - - logger.info("NumberOfValues = " + NumberOfValues); for (int j = 0; j < NumberOfValues; j++){ { @@ -990,8 +1046,9 @@ private AlarmMessagePayload decodeMessageServicePushPayload(CpuServicesParameter int valueLength = userData.readShort(); //Max length of value is 12 bytes valueLength = (valueLength >> 4)*2; - logger.info("Numero de valores transferidos = " + valueLength + " Valores disponibles: " + userData.readableBytes()); + ByteBuf Data = userData.readBytes(valueLength); + AssociatedValues.add(new AssociatedValueItem(valueCode, valueTransportSize, valueLength, @@ -1058,17 +1115,9 @@ private AlarmMessagePayload decodeMessageServiceQueryPayload(CpuServicesParamete byte EventState = userData.readByte(); byte AckStateGoing = userData.readByte(); byte AckStateComing = userData.readByte(); - Calendar timestampComing; + LocalDateTime timestampComing; - timestampComing = Calendar.getInstance(); - timestampComing.set(2000 + userData.readByte(), - userData.readByte()-1, - userData.readByte(), - userData.readByte(), - userData.readByte(), - userData.readByte()); - int milliseconds = (userData.readInt() & 0xfff8) >> 3; - timestampComing.setTimeInMillis(timestampComing.getTimeInMillis() + milliseconds); + timestampComing = readDateAndTime(userData); List ComingValues = new LinkedList<>(); @@ -1085,17 +1134,9 @@ private AlarmMessagePayload decodeMessageServiceQueryPayload(CpuServicesParamete Data)); } - Calendar timestampGoing; + LocalDateTime timestampGoing; - timestampGoing = Calendar.getInstance(); - timestampGoing.set(2000 + userData.readByte(), - userData.readByte()-1, - userData.readByte(), - userData.readByte(), - userData.readByte(), - userData.readByte()); - milliseconds = (userData.readInt() & 0xfff8) >> 3; - timestampGoing.setTimeInMillis(timestampGoing.getTimeInMillis() + milliseconds); + timestampGoing = readDateAndTime(userData); List GoingValues = new LinkedList<>(); @@ -1216,4 +1257,80 @@ private S7ControllerType lookupControllerType(String articleNumber) { } } + /* + * Date and time of day (BCD coded). + * +----------------+ + * Byte n | Year 0 to 99 | + * +----------------+ + * Byte n+1 | Month 0 to 12 | + * +----------------+ + * Byte n+2 | Day 0 to 31 | + * +----------------+ + * Byte n+3 | Hour 0 to 23 | + * +----------------+ + * Byte n+4 | Minute 0 to 59 | + * +----------------+ + * Byte n+5 | Second 0 to 59 | + * +----------------+ + * Byte n+6 | ms 0 to 999 | + * Byte n+7 | X X X X X D O W| + * +----------------+ + * DOW: Day of weed (last 3 bits) + */ + private LocalDateTime readDateAndTime(ByteBuf data) { + //from Plc4XS7Protocol + + int year=convertByteToBcd(data.readByte()); + int month=convertByteToBcd(data.readByte()); + int day=convertByteToBcd(data.readByte()); + int hour=convertByteToBcd(data.readByte()); + int minute=convertByteToBcd(data.readByte()); + int second=convertByteToBcd(data.readByte()); + int milliseconds = (data.readShort() & 0xfff0) >> 4; + + int cen = ((milliseconds & 0x0f00) >> 8) * 100; + int dec = ((milliseconds & 0x00f0) >> 4) * 10; + milliseconds = cen + dec + (milliseconds & 0x000f); + int nanoseconds = milliseconds * 1000000; + + //data-type ranges from 1990 up to 2089 + if(year>=90){ + year+=1900; + } + else{ + year+=2000; + } + + return LocalDateTime.of(year,month,day,hour,minute,second, nanoseconds); + } + + private LocalTime readTimeOfDay(ByteBuf data) { + //per definition for Date_And_Time only the first 6 bytes are used + + int millisSinsMidnight = data.readInt(); + + return LocalTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0).plus(millisSinsMidnight, ChronoUnit.MILLIS); + + } + + private LocalDate readDate(ByteBuf data) { + //per definition for Date_And_Time only the first 6 bytes are used + + int daysSince1990 = data.readUnsignedShort(); + + System.out.println(daysSince1990); + return LocalDate.now().withYear(1990).withDayOfMonth(1).withMonth(1).plus(daysSince1990, ChronoUnit.DAYS); + + } + + /** + * converts incoming byte to an integer regarding used BCD format + * @param incomingByte + * @return converted BCD number + */ + private static int convertByteToBcd(byte incomingByte) { + int dec = (incomingByte >> 4) * 10; + return dec + (incomingByte & 0x0f); + } + } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/messages/S7PushMessage.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/messages/S7PushMessage.java new file mode 100644 index 00000000000..29835684d3c --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/messages/S7PushMessage.java @@ -0,0 +1,28 @@ +/* +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.netty.model.messages; + +/** + * + * @author cgarcia + */ +public interface S7PushMessage { + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuDiagnosticPushParameter.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuDiagnosticPushParameter.java new file mode 100644 index 00000000000..40b364a54c9 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuDiagnosticPushParameter.java @@ -0,0 +1,87 @@ +/* +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.netty.model.params; + +import org.apache.plc4x.java.s7.netty.model.messages.S7PushMessage; +import org.apache.plc4x.java.s7.netty.model.types.CpuCurrentModeType; +import org.apache.plc4x.java.s7.netty.model.types.CpuUserDataMethodType; +import org.apache.plc4x.java.s7.netty.model.types.CpuUserDataParameterFunctionGroupType; +import org.apache.plc4x.java.s7.netty.model.types.CpuUserDataParameterType; +import org.apache.plc4x.java.s7.netty.model.types.ParameterType; + +/** + * + * @author cgarcia + */ +public class CpuDiagnosticPushParameter implements S7Parameter, S7PushMessage { + + private CpuUserDataMethodType Method; + private CpuUserDataParameterType parameterType; + private CpuUserDataParameterFunctionGroupType ParameterFunction; + private CpuCurrentModeType CurrentMode; + private byte sequenceNumber; + + public CpuDiagnosticPushParameter( + CpuUserDataMethodType Method, + CpuUserDataParameterType ParameterType, + CpuUserDataParameterFunctionGroupType ParameterFunction, + CpuCurrentModeType CurrentMode, + byte sequenceNumber) { + this.Method = Method; + this.parameterType = ParameterType; + this.ParameterFunction = ParameterFunction; + this.CurrentMode = CurrentMode; + this.sequenceNumber = sequenceNumber; + } + + public CpuUserDataMethodType getMethod() { + return Method; + } + + public CpuUserDataParameterType getParameterType() { + return parameterType; + } + + public CpuUserDataParameterFunctionGroupType getParameterFunction() { + return ParameterFunction; + } + + public CpuCurrentModeType getCurrentMode() { + return CurrentMode; + } + + @Override + public ParameterType getType() { + return ParameterType.MODE_TRANSITION; + } + + @Override + public String toString() { + return "CpuDiagnosticPushParameter{" + "Method=" + Method + + ", parameterType=" + parameterType + + ", ParameterFunction=" + ParameterFunction + + ", CurrentMode=" + CurrentMode + + ", sequenceNumber=" + sequenceNumber + + '}'; + } + + + + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuServicesPushParameter.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuServicesPushParameter.java index 8d02c60925d..36b93c25b10 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuServicesPushParameter.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuServicesPushParameter.java @@ -47,5 +47,10 @@ public boolean isLastDataUnit() { public ParameterError getError() { return error; } + + @Override + public String toString() { + return "CpuServicesPushParameter{" + "dataUnitReferenceNumber=" + dataUnitReferenceNumber + ", lastDataUnit=" + lastDataUnit + ", error=" + error + '}'; + } } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/AlarmMessagePayload.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/AlarmMessagePayload.java index 77bbf5262f6..1689b705c4d 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/AlarmMessagePayload.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/AlarmMessagePayload.java @@ -19,6 +19,7 @@ Licensed to the Apache Software Foundation (ASF) under one package org.apache.plc4x.java.s7.netty.model.payloads; +import org.apache.plc4x.java.s7.netty.model.messages.S7PushMessage; import org.apache.plc4x.java.s7.netty.model.payloads.items.AlarmMessageItem; import org.apache.plc4x.java.s7.netty.model.types.DataTransportErrorCode; import org.apache.plc4x.java.s7.netty.model.types.DataTransportSize; @@ -28,7 +29,7 @@ Licensed to the Apache Software Foundation (ASF) under one * * @author cgarcia */ -public class AlarmMessagePayload implements S7Payload { +public class AlarmMessagePayload implements S7Payload, S7PushMessage { private final DataTransportErrorCode returnCode; private final DataTransportSize dataTransportSize; @@ -73,6 +74,16 @@ public Integer getLength() { public AlarmMessageItem getMsg() { return msg; } + + @Override + public String toString() { + return "AlarmMessagePayload{" + "returnCode=" + returnCode + + ", dataTransportSize=" + dataTransportSize + + ", msgtype=" + msgtype + + ", length=" + length + + ", msg=" + msg + + '}'; + } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuDiagnosticMessagePayload.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuDiagnosticMessagePayload.java new file mode 100644 index 00000000000..fbf5c35ee54 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuDiagnosticMessagePayload.java @@ -0,0 +1,82 @@ +/* +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.netty.model.payloads; + +import org.apache.plc4x.java.s7.netty.model.messages.S7PushMessage; +import org.apache.plc4x.java.s7.netty.model.payloads.items.CpuDiagnosticMessageItem; +import org.apache.plc4x.java.s7.netty.model.types.DataTransportErrorCode; +import org.apache.plc4x.java.s7.netty.model.types.DataTransportSize; +import org.apache.plc4x.java.s7.netty.model.types.ParameterType; + +/** + * + * @author cgarcia + */ +public class CpuDiagnosticMessagePayload implements S7Payload, S7PushMessage { + + private final DataTransportErrorCode returnCode; + private final DataTransportSize dataTransportSize; + private final Integer length; + private final CpuDiagnosticMessageItem msg; + + public CpuDiagnosticMessagePayload(DataTransportErrorCode returnCode, DataTransportSize dataTransportSize, Integer length, CpuDiagnosticMessageItem msg) { + this.returnCode = returnCode; + this.dataTransportSize = dataTransportSize; + this.length = length; + this.msg = msg; + } + + public DataTransportErrorCode getReturnCode() { + return returnCode; + } + + public DataTransportSize getDataTransportSize() { + return dataTransportSize; + } + + public Integer getLength() { + return length; + } + + public CpuDiagnosticMessageItem getMsg() { + return msg; + } + + @Override + public ParameterType getType() { + return ParameterType.CPU_SERVICES; + } + + @Override + public String toString() { + return "CpuDiagnosticMessagePayload{" + "returnCode=" + returnCode + + ", dataTransportSize=" + dataTransportSize + + ", length=" + length + + ", msg=" + msg + + '}'; + } + + + + + + + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/AlarmMessageItem.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/AlarmMessageItem.java index 5cdefec32b1..50afe30be52 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/AlarmMessageItem.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/AlarmMessageItem.java @@ -19,7 +19,7 @@ Licensed to the Apache Software Foundation (ASF) under one package org.apache.plc4x.java.s7.netty.model.payloads.items; -import java.util.Calendar; +import java.time.LocalDateTime; import java.util.List; import org.apache.plc4x.java.s7.netty.model.types.DataTransportErrorCode; import org.apache.plc4x.java.s7.netty.model.types.DataTransportSize; @@ -31,13 +31,13 @@ Licensed to the Apache Software Foundation (ASF) under one public class AlarmMessageItem { private final DataTransportErrorCode returnCode; private final DataTransportSize dataTransportSize; - private final Calendar timestamp; + private final LocalDateTime timestamp; private final byte function; private final byte objects; private final int Length; private final List msgItems; - public AlarmMessageItem(Calendar timestamp, + public AlarmMessageItem(LocalDateTime timestamp, byte function, byte objects, List msgItems) { @@ -76,7 +76,7 @@ public DataTransportSize getDataTransportSize() { return dataTransportSize; } - public Calendar getTimestamp() { + public LocalDateTime getTimestamp() { return timestamp; } @@ -95,6 +95,18 @@ public int getLength() { public List getMsgItems() { return msgItems; } + + @Override + public String toString() { + return "AlarmMessageItem{" + "returnCode=" + returnCode + + ", dataTransportSize=" + dataTransportSize + + ", timestamp=" + timestamp + + ", function=" + function + + ", objects=" + objects + + ", Length=" + Length + + ", msgItems=" + msgItems + + '}'; + } } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/AssociatedValueItem.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/AssociatedValueItem.java index c9676afd2e6..dfee604a861 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/AssociatedValueItem.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/AssociatedValueItem.java @@ -20,6 +20,7 @@ Licensed to the Apache Software Foundation (ASF) under one package org.apache.plc4x.java.s7.netty.model.payloads.items; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import org.apache.plc4x.java.s7.netty.model.types.DataTransportErrorCode; import org.apache.plc4x.java.s7.netty.model.types.DataTransportSize; @@ -56,9 +57,13 @@ public ByteBuf getData() { return Data; } - - - - + @Override + public String toString() { + return "AssociatedValueItem{" + "returnCode=" + returnCode + + ", dataTransportSize=" + dataTransportSize + + ", Length=" + Length + + ", Data=" + ByteBufUtil.hexDump(Data) + + '}'; + } } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/CpuDiagnosticMessageItem.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/CpuDiagnosticMessageItem.java new file mode 100644 index 00000000000..0ed066d9177 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/CpuDiagnosticMessageItem.java @@ -0,0 +1,95 @@ +/* +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.netty.model.payloads.items; + +import java.time.LocalDateTime; + +/** + * Diagnostic message from PLC, is transfer by payload. + * EventID: System specific messages W#16#8xyz and W#16#9xyz. + * User messages W#16#Axyz and W#16#Bxyz + * where x=0 output event, x=1 input event + * and yz hex number in message handler. + * + * @author cgarcia + */ +public class CpuDiagnosticMessageItem { + + private final Short EventID; + private final Byte PriorityClass; + private final Byte ObNumber; + private final Short DatID; + private final Short Info1; + private final Integer Info2; + private LocalDateTime TimeStamp; + + public CpuDiagnosticMessageItem(Short EventID, Byte PriorityClass, Byte ObNumber, Short DatID, Short Info1, Integer Info2, LocalDateTime TimeStamp) { + this.EventID = EventID; + this.PriorityClass = PriorityClass; + this.ObNumber = ObNumber; + this.DatID = DatID; + this.Info1 = Info1; + this.Info2 = Info2; + this.TimeStamp = TimeStamp; + } + + public Short getEventID() { + return EventID; + } + + public Byte getPriorityClass() { + return PriorityClass; + } + + public Byte getObNumber() { + return ObNumber; + } + + public Short getDatID() { + return DatID; + } + + public Short getInfo1() { + return Info1; + } + + public Integer getInfo2() { + return Info2; + } + + public LocalDateTime getTimeStamp() { + return TimeStamp; + } + + @Override + public String toString() { + return "CpuDiagnosticMessageItem{" + "EventID=" + EventID + + ", PriorityClass=" + PriorityClass + + ", ObNumber=" + ObNumber + + ", DatID=" + DatID + + ", Info1=" + Info1 + + ", Info2=" + Info2 + + ", TimeStamp=" + TimeStamp + + '}'; + } + + + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/MessageObjectItem.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/MessageObjectItem.java index a8c36458766..081b3460619 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/MessageObjectItem.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/MessageObjectItem.java @@ -19,6 +19,7 @@ Licensed to the Apache Software Foundation (ASF) under one package org.apache.plc4x.java.s7.netty.model.payloads.items; +import java.time.format.DateTimeFormatter; import java.util.Calendar; import java.util.List; @@ -149,6 +150,25 @@ public List getGoingValues() { return GoingValues; } + @Override + public String toString() { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss.SSS"); + return "MessageObjectItem{" + "VariableSpecification=" + VariableSpecification + + ", Length=" + Length + + ", SyntaxID=" + SyntaxID + + ", NumberOfValues=" + NumberOfValues + + ", EventID=" + EventID + + ", EventState=" + EventState + + ", State=" + State + + ", AckStateGoing=" + AckStateGoing + + ", AckStateComming=" + AckStateComming + + ", TimestampComing=" + TimestampComing + + ", TimestampGoing=" + TimestampGoing + + ", ComingValues=" + ComingValues + + ", GoingValues=" + GoingValues + + '}'; + } + diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuCurrentModeType.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuCurrentModeType.java new file mode 100644 index 00000000000..626c205ace9 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuCurrentModeType.java @@ -0,0 +1,83 @@ +/* + 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.netty.model.types; + +import java.util.HashMap; +import java.util.Map; +import org.apache.plc4x.java.api.model.PlcField; + +/** + * + * @author cgarcia + */ +public enum CpuCurrentModeType implements PlcField { + + STOP("STOP", (byte) 0x00), + WARM_RESTART("WARM_RESTART", (byte) 0x01), + RUN("RUN", (byte) 0x02), + HOT_RESTART("HOT_RESTART", (byte) 0x03), + HOLD("HOLD", (byte) 0x04), + COLD_RESTART("COLD_RESTART", (byte) 0x06), + RUN_R("RUN_R", (byte) 0x09), + LINK_UP("LINK_UP", (byte) 0x0b), + UPDATE("UPDATE", (byte) 0x0c), + ; + + + private static final Map map; + + static { + map = new HashMap<>(); + for (CpuCurrentModeType subevent : CpuCurrentModeType.values()) { + map.put(subevent.code, subevent); + } + } + + private final String event; + private final byte code; + + CpuCurrentModeType(String event, byte code){ + this.event = event; + this.code = code; + } + + public String getEvent(){ + return event; + } + + public byte getCode() { + return code; + } + + public static CpuCurrentModeType valueOfEvent(String event) { + for (CpuCurrentModeType value : CpuCurrentModeType.values()) { + if(value.getEvent().equals(event)) { + return value; + } + } + return null; + } + + public static CpuCurrentModeType valueOf(byte code) { + return map.get(code); + } + + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuCyclicServicesParameterSubFunctionGroupType.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuCyclicServicesParameterSubFunctionGroupType.java new file mode 100644 index 00000000000..0ad38d55aa2 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuCyclicServicesParameterSubFunctionGroupType.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.netty.model.types; + +import java.util.HashMap; +import java.util.Map; +import org.apache.plc4x.java.api.model.PlcField; + +/** + * + * @author cgarcia + */ +public enum CpuCyclicServicesParameterSubFunctionGroupType implements PlcField { + + CYCLIC_TRANSFER("CYCLIC_TRANSFER", (byte) 0x01), + CYCLIC_UNSUBSCRIBE("CYCLIC_UNSUBSCRIBE", (byte) 0x04), + CYCLIC_CHANGE("CYCLIC_CHANGE", (byte) 0x05), + CYCLIC_CHANGE_MODIFY("CYCLIC_CHANGE_MODIFY", (byte) 0x07), + CYCLIC_RDREC("CYCLIC_RDREC", (byte) 0x08), + ; + + + private static final Map map; + + static { + map = new HashMap<>(); + for (CpuCyclicServicesParameterSubFunctionGroupType subevent : CpuCyclicServicesParameterSubFunctionGroupType.values()) { + map.put(subevent.code, subevent); + } + } + + private final String event; + private final byte code; + + CpuCyclicServicesParameterSubFunctionGroupType(String event, byte code){ + this.event = event; + this.code = code; + } + + public String getEvent(){ + return event; + } + + public byte getCode() { + return code; + } + + public static CpuCyclicServicesParameterSubFunctionGroupType valueOfEvent(String event) { + for (CpuCyclicServicesParameterSubFunctionGroupType value : CpuCyclicServicesParameterSubFunctionGroupType.values()) { + if(value.getEvent().equals(event)) { + return value; + } + } + return null; + } + + public static CpuCyclicServicesParameterSubFunctionGroupType valueOf(byte code) { + return map.get(code); + } + + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuUserDataMethodType.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuUserDataMethodType.java new file mode 100644 index 00000000000..7043e7d7de2 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuUserDataMethodType.java @@ -0,0 +1,77 @@ +/* + 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.netty.model.types; + +import java.util.HashMap; +import java.util.Map; +import org.apache.plc4x.java.api.model.PlcField; + +/** + * + * @author cgarcia + */ +public enum CpuUserDataMethodType implements PlcField { + + UNDEF("UNDEF", (byte) 0x00), + REQUEST("REQUEST", (byte) 0x11), + RESPONSE("RESPONSE", (byte) 0x12), + ; + + + private static final Map map; + + static { + map = new HashMap<>(); + for (CpuUserDataMethodType subevent : CpuUserDataMethodType.values()) { + map.put(subevent.code, subevent); + } + } + + private final String event; + private final byte code; + + CpuUserDataMethodType(String event, byte code){ + this.event = event; + this.code = code; + } + + public String getEvent(){ + return event; + } + + public byte getCode() { + return code; + } + + public static CpuUserDataMethodType valueOfEvent(String event) { + for (CpuUserDataMethodType value : CpuUserDataMethodType.values()) { + if(value.getEvent().equals(event)) { + return value; + } + } + return null; + } + + public static CpuUserDataMethodType valueOf(byte code) { + return map.get(code); + } + + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuUserDataParameterFunctionGroupType.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuUserDataParameterFunctionGroupType.java new file mode 100644 index 00000000000..b392d26947d --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuUserDataParameterFunctionGroupType.java @@ -0,0 +1,83 @@ +/* + 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.netty.model.types; + +import java.util.HashMap; +import java.util.Map; +import org.apache.plc4x.java.api.model.PlcField; + +/** + * + * @author cgarcia + */ +public enum CpuUserDataParameterFunctionGroupType implements PlcField { + + MODE_TRANSITION("MODE_TRANSITION", (byte) 0x00), + PROG_COMMANDS("PROG", (byte) 0x01), + CYCLIC_SERVICES("CYCLIC_SERVICES", (byte) 0x02), + BLOCK_FUNCTIONS("BLOCK", (byte) 0x03), + CPU_FUNCTIONS("CPU_FUNCTIONS", (byte) 0x04), + SECURITY("SECURITY", (byte) 0x05), + PBC("PBC", (byte) 0x06), + TIME_FUNCTIONS("TIME_FUNCTIONS", (byte) 0x07), + NCPRG("NCPRG", (byte) 0x0f), + ; + + + private static final Map map; + + static { + map = new HashMap<>(); + for (CpuUserDataParameterFunctionGroupType subevent : CpuUserDataParameterFunctionGroupType.values()) { + map.put(subevent.code, subevent); + } + } + + private final String event; + private final byte code; + + CpuUserDataParameterFunctionGroupType(String event, byte code){ + this.event = event; + this.code = code; + } + + public String getEvent(){ + return event; + } + + public byte getCode() { + return code; + } + + public static CpuUserDataParameterFunctionGroupType valueOfEvent(String event) { + for (CpuUserDataParameterFunctionGroupType value : CpuUserDataParameterFunctionGroupType.values()) { + if(value.getEvent().equals(event)) { + return value; + } + } + return null; + } + + public static CpuUserDataParameterFunctionGroupType valueOf(byte code) { + return map.get(code); + } + + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuUserDataParameterType.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuUserDataParameterType.java new file mode 100644 index 00000000000..d51fc26ff1a --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuUserDataParameterType.java @@ -0,0 +1,80 @@ +/* + 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.netty.model.types; + +import java.util.HashMap; +import java.util.Map; +import org.apache.plc4x.java.api.model.PlcField; + +/** + * + * @author cgarcia + */ +public enum CpuUserDataParameterType implements PlcField { + + PUSH("PUSH", (byte) 0x00), + REQUEST("REQUEST", (byte) 0x04), + RESPONSE("RESPONSE", (byte) 0x08), + NCPUSH("BLOCK", (byte) 0x03), + NCREQUEST("CPU_FUNCTIONS", (byte) 0x07), + NCRESPONSE("SECURITY", (byte) 0x0B), + ; + + + private static final Map map; + + static { + map = new HashMap<>(); + for (CpuUserDataParameterType subevent : CpuUserDataParameterType.values()) { + map.put(subevent.code, subevent); + } + } + + private final String event; + private final byte code; + + CpuUserDataParameterType(String event, byte code){ + this.event = event; + this.code = code; + } + + public String getEvent(){ + return event; + } + + public byte getCode() { + return code; + } + + public static CpuUserDataParameterType valueOfEvent(String event) { + for (CpuUserDataParameterType value : CpuUserDataParameterType.values()) { + if(value.getEvent().equals(event)) { + return value; + } + } + return null; + } + + public static CpuUserDataParameterType valueOf(byte code) { + return map.get(code); + } + + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/ParameterType.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/ParameterType.java index 16a565cf619..ed7da61b4a3 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/ParameterType.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/ParameterType.java @@ -18,17 +18,17 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.s7.netty.model.types; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.HashMap; import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * (Values determined by evaluating generated ".pcap" files) */ public enum ParameterType { CPU_SERVICES((byte) 0x00), + MODE_TRANSITION((byte) 0x01), READ_VAR((byte) 0x04), WRITE_VAR((byte) 0x05), REQUEST_DOWNLOAD((byte) 0x1A), diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7SizeHelper.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7SizeHelper.java index 4a3313d32e7..0010d7871c1 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7SizeHelper.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7SizeHelper.java @@ -94,6 +94,8 @@ public static short getParameterLength(S7Parameter parameter) { } switch (parameter.getType()) { + case MODE_TRANSITION: + return 8; case READ_VAR: case WRITE_VAR: return getReadWriteVarParameterLength((VarParameter) parameter); diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7DiagnosticEventId.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7DiagnosticEventId.java new file mode 100644 index 00000000000..087ae85d53b --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7DiagnosticEventId.java @@ -0,0 +1,492 @@ +/* + 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.utils; + +import java.util.HashMap; +import java.util.Map; + +/** + * + * @author cgarcia + */ +public enum S7DiagnosticEventId { + + EVENTID_0x113A((short) 0x113A, "Start request for cyclic interrupt OB with special handling (S7-300 only)"), + EVENTID_0x1155((short) 0x1155, "Status alarm for PROFIBUS DP"), + EVENTID_0x1156((short) 0x1156, "Update interrupt for PROFIBUS DP"), + EVENTID_0x1157((short) 0x1157, "Manufacturer interrupt for PROFIBUS DP"), + EVENTID_0x1158((short) 0x1158, "Status interrupt for PROFINET IO"), + EVENTID_0x1159((short) 0x1159, "Update interrupt for PROFINET IO"), + EVENTID_0x115A((short) 0x115A, "Manufacturer interrupt for PROFINET IO"), + EVENTID_0x115B((short) 0x115B, "IO: Profile-specific interrupt"), + EVENTID_0x116A((short) 0x116A, "Technology synchronization interrupt"), + EVENTID_0x1381((short) 0x1381, "Request for manual warm restart"), + EVENTID_0x1382((short) 0x1382, "Request for automatic warm restart"), + EVENTID_0x1383((short) 0x1383, "Request for manual hot restart"), + EVENTID_0x1384((short) 0x1384, "Request for automatic hot restart"), + EVENTID_0x1385((short) 0x1385, "Request for manual cold restart"), + EVENTID_0x1386((short) 0x1386, "Request for automatic cold restart"), + EVENTID_0x1387((short) 0x1387, "Master CPU: request for manual cold restart"), + EVENTID_0x1388((short) 0x1388, "Master CPU: request for automatic cold restart"), + EVENTID_0x138A((short) 0x138A, "Master CPU: request for manual warm restart"), + EVENTID_0x138B((short) 0x138B, "Master CPU: request for automatic warm restart"), + EVENTID_0x138C((short) 0x138C, "Standby CPU: request for manual hot restart"), + EVENTID_0x138D((short) 0x138D, "Standby CPU: request for automatic hot restart"), + EVENTID_0x2521((short) 0x2521, "BCD conversion error"), + EVENTID_0x2522((short) 0x2522, "Area length error when reading"), + EVENTID_0x2523((short) 0x2523, "Area length error when writing"), + EVENTID_0x2524((short) 0x2524, "Area error when reading"), + EVENTID_0x2525((short) 0x2525, "Area error when writing"), + EVENTID_0x2526((short) 0x2526, "Timer number error"), + EVENTID_0x2527((short) 0x2527, "Counter number error"), + EVENTID_0x2528((short) 0x2528, "Alignment error when reading"), + EVENTID_0x2529((short) 0x2529, "Alignment error when writing"), + EVENTID_0x2530((short) 0x2530, "Write error when accessing the DB"), + EVENTID_0x2531((short) 0x2531, "Write error when accessing the DI"), + EVENTID_0x2532((short) 0x2532, "Block number error when opening a DB"), + EVENTID_0x2533((short) 0x2533, "Block number error when opening a DI"), + EVENTID_0x2534((short) 0x2534, "Block number error when calling an FC"), + EVENTID_0x2535((short) 0x2535, "Block number error when calling an FB"), + EVENTID_0x253A((short) 0x253A, "DB not loaded"), + EVENTID_0x253C((short) 0x253C, "FC not loaded"), + EVENTID_0x253D((short) 0x253D, "SFC not loaded"), + EVENTID_0x253E((short) 0x253E, "FB not loaded"), + EVENTID_0x253F((short) 0x253F, "SFB not loaded"), + EVENTID_0x2942((short) 0x2942, "I/O access error, reading"), + EVENTID_0x2943((short) 0x2943, "I/O access error, writing"), + EVENTID_0x3267((short) 0x3267, "End of module reconfiguration"), + EVENTID_0x3367((short) 0x3367, "Start of module reconfiguration"), + EVENTID_0x34A4((short) 0x34A4, "PROFInet Interface DB can be addressed again"), + EVENTID_0x3501((short) 0x3501, "Cycle time exceeded"), + EVENTID_0x3502((short) 0x3502, "User interface (OB or FRB) request error"), + EVENTID_0x3503((short) 0x3503, "Delay too long processing a priority class"), + EVENTID_0x3505((short) 0x3505, "Time-of-day interrupt(s) skipped due to new clock setting"), + EVENTID_0x3506((short) 0x3506, "Time-of-day interrupt(s) skipped when changing to RUN after HOLD"), + EVENTID_0x3507((short) 0x3507, "Multiple OB request errors caused internal buffer overflow"), + EVENTID_0x3508((short) 0x3508, "Synchronous cycle interrupt-timing error"), + EVENTID_0x3509((short) 0x3509, "Interrupt loss due to excess interrupt load"), + EVENTID_0x350A((short) 0x350A, "Resume RUN mode after CiR"), + EVENTID_0x350B((short) 0x350B, "Technology synchronization interrupt - timing error"), + EVENTID_0x3571((short) 0x3571, "Nesting depth too high in nesting levels"), + EVENTID_0x3572((short) 0x3572, "Nesting depth for Master Control Relays too high"), + EVENTID_0x3573((short) 0x3573, "Nesting depth too high after synchronous errors"), + EVENTID_0x3574((short) 0x3574, "Nesting depth for block calls (U stack) too high"), + EVENTID_0x3575((short) 0x3575, "Nesting depth for block calls (B stack) too high"), + EVENTID_0x3576((short) 0x3576, "Local data allocation error"), + EVENTID_0x3578((short) 0x3578, "Unknown instruction"), + EVENTID_0x357A((short) 0x357A, "Jump instruction to target outside of the block"), + EVENTID_0x3582((short) 0x3582, "Memory error detected and corrected by operating system"), + EVENTID_0x3583((short) 0x3583, "Accumulation of detected and corrected memo errors"), + EVENTID_0x3585((short) 0x3585, "Error in the PC operating system (only for LC RTX)"), + EVENTID_0x3587((short) 0x3587, "Multi-bit memory error detected and corrected"), + EVENTID_0x35A1((short) 0x35A1, "User interface (OB or FRB) not found"), + EVENTID_0x35A2((short) 0x35A2, "OB not loaded (started by SFC or operating system due to configuration)"), + EVENTID_0x35A3((short) 0x35A3, "Error when operating system accesses a block"), + EVENTID_0x35A4((short) 0x35A4, "PROFInet Interface DB cannot be addressed"), + EVENTID_0x35D2((short) 0x35D2, "Diagnostic entries cannot be sent at present"), + EVENTID_0x35D3((short) 0x35D3, "Synchronization frames cannot be sent"), + EVENTID_0x35D4((short) 0x35D4, "Illegal time jump resulting from synchronization"), + EVENTID_0x35D5((short) 0x35D5, "Error adopting the synchronization time"), + EVENTID_0x35E1((short) 0x35E1, "Incorrect frame ID in GD"), + EVENTID_0x35E2((short) 0x35E2, "GD packet status cannot be entered in DB"), + EVENTID_0x35E3((short) 0x35E3, "Frame length error in GD"), + EVENTID_0x35E4((short) 0x35E4, "Illegal GD packet number received"), + EVENTID_0x35E5((short) 0x35E5, "Error accessing DB in communication SFBs for configured S7 connections"), + EVENTID_0x35E6((short) 0x35E6, "GD total status cannot be entered in DB"), + EVENTID_0x3821((short) 0x3821, "BATTF: failure on at least one backup battery of the central rack, problem eliminated"), + EVENTID_0x3822((short) 0x3822, "BAF: failure of backup voltage on central rack, problem eliminated"), + EVENTID_0x3823((short) 0x3823, "24 volt supply failure on central rack, problem eliminated"), + EVENTID_0x3825((short) 0x3825, "BATTF: failure on at least one backup battery of the redundant central rack, problem eliminated"), + EVENTID_0x3826((short) 0x3826, "BAF: failure of backup voltage on redundant central rack, problem eliminated"), + EVENTID_0x3827((short) 0x3827, "24 volt supply failure on redundant central rack, problem eliminated"), + EVENTID_0x3831((short) 0x3831, "BATTF: failure of at least one backup battery of the expansion rack, problem eliminated"), + EVENTID_0x3832((short) 0x3832, "BAF: failure of backup voltage on expansion rack, problem eliminated"), + EVENTID_0x3833((short) 0x3833, "24 volt supply failure on at least one expansion rack, problem eliminated"), + EVENTID_0x3842((short) 0x3842, "Module OK"), + EVENTID_0x3854((short) 0x3854, "PROFINET IO interface submodule/submodule and matches the configured interface submodule/submodule"), + EVENTID_0x3855((short) 0x3855, "PROFINET IO interface submodule/submodule inserted, but does not match the configured interface submodule/submodule"), + EVENTID_0x3856((short) 0x3856, "PROFINET IO interface submodule/submodule inserted, but error in module parameter assignment"), + EVENTID_0x3858((short) 0x3858, "PROFINET IO interface submodule access error corrected"), + EVENTID_0x3861((short) 0x3861, "Module/interface module inserted, module type OK"), + EVENTID_0x3863((short) 0x3863, "Module/interface module plugged in, but wrong module type"), + EVENTID_0x3864((short) 0x3864, "Module/interface module plugged in, but causing problem (type ID unreadable)"), + EVENTID_0x3865((short) 0x3865, "Module plugged in, but error in module parameter assignment"), + EVENTID_0x3866((short) 0x3866, "Module can be addressed again, load voltage error removed"), + EVENTID_0x3881((short) 0x3881, "Interface error leaving state"), + EVENTID_0x3884((short) 0x3884, "Interface module plugged in"), + EVENTID_0x38B3((short) 0x38B3, "I/O access error when updating the process image input table"), + EVENTID_0x38B4((short) 0x38B4, "I/O access error when transferring the process image to the output modules"), + EVENTID_0x38C1((short) 0x38C1, "Expansion rack operational again (1 to 21), leaving state"), + EVENTID_0x38C2((short) 0x38C2, "Expansion rack operational again but mismatch between setpoint and actual configuration"), + EVENTID_0x38C4((short) 0x38C4, "Distributed I/Os: station failure, leaving state"), + EVENTID_0x38C5((short) 0x38C5, "Distributed I/Os: station fault, leaving state"), + EVENTID_0x38C6((short) 0x38C6, "Expansion rack operational again, but error(s) in module parameter assignment"), + EVENTID_0x38C7((short) 0x38C7, "DP: station operational again, but error(s) in module parameter assignment"), + EVENTID_0x38C8((short) 0x38C8, "DP: station operational again, but mismatch between setpoint and actual configuration"), + EVENTID_0x38CB((short) 0x38CB, "PROFINET IO station operational again"), + EVENTID_0x38CC((short) 0x38CC, "PROFINET IO station error corrected"), + EVENTID_0x3921((short) 0x3921, "BATTF: failure on at least one backup battery of the central rack"), + EVENTID_0x3922((short) 0x3922, "BAF: failure of backup voltage on central rack"), + EVENTID_0x3923((short) 0x3923, "24 volt supply failure on central rack"), + EVENTID_0x3925((short) 0x3925, "BATTF: failure on at least one backup battery of the redundant central rack"), + EVENTID_0x3926((short) 0x3926, "BAF: failure of backup voltage on redundant central rack"), + EVENTID_0x3927((short) 0x3927, "24 volt supply failure on redundant central rack"), + EVENTID_0x3931((short) 0x3931, "BATTF: failure of at least one backup battery of the expansion rack"), + EVENTID_0x3932((short) 0x3932, "BAF: failure of backup voltage on expansion rack"), + EVENTID_0x3933((short) 0x3933, "24 volt supply failure on at least one expansion rack"), + EVENTID_0x3942((short) 0x3942, "Module error"), + EVENTID_0x3951((short) 0x3951, "PROFINET IO submodule removed"), + EVENTID_0x3954((short) 0x3954, "PROFINET IO interface submodule/submodule removed"), + EVENTID_0x3961((short) 0x3961, "Module/interface module removed, cannot be addressed"), + EVENTID_0x3966((short) 0x3966, "Module cannot be addressed, load voltage error"), + EVENTID_0x3968((short) 0x3968, "Module reconfiguration has ended with error"), + EVENTID_0x3981((short) 0x3981, "Interface error entering state"), + EVENTID_0x3984((short) 0x3984, "Interface module removed"), + EVENTID_0x3986((short) 0x3986, "Performance of an H-Sync link negatively affected"), + EVENTID_0x39B1((short) 0x39B1, "I/O access error when updating the process image input table"), + EVENTID_0x39B2((short) 0x39B2, "I/O access error when transferring the process image to the output modules"), + EVENTID_0x39B3((short) 0x39B3, "I/O access error when updating the process image input table"), + EVENTID_0x39B4((short) 0x39B4, "I/O access error when transferring the process image to the output modules"), + EVENTID_0x39C1((short) 0x39C1, "Expansion rack failure (1 to 21), entering state"), + EVENTID_0x39C3((short) 0x39C3, "Distributed I/Os: master system failure entering state"), + EVENTID_0x39C4((short) 0x39C4, "Distributed I/Os: station failure, entering state"), + EVENTID_0x39C5((short) 0x39C5, "Distributed I/Os: station fault, entering state"), + EVENTID_0x39CA((short) 0x39CA, "PROFINET IO system failure"), + EVENTID_0x39CB((short) 0x39CB, "PROFINET IO station failure"), + EVENTID_0x39CC((short) 0x39CC, "PROFINET IO station error"), + EVENTID_0x39CD((short) 0x39CD, "PROFINET IO station operational again, but expected configuration does not match actual configuration"), + EVENTID_0x39CE((short) 0x39CE, "PROFINET IO station operational again, but error(s) in module parameter assignment"), + EVENTID_0x42F3((short) 0x42F3, "Checksum error detected and corrected by the operating system"), + EVENTID_0x42F4((short) 0x42F4, "Standby CPU: connection/update via SFC90 is locked in the master CPU"), + EVENTID_0x4300((short) 0x4300, "Backed-up power on"), + EVENTID_0x4301((short) 0x4301, "Mode transition from STOP to STARTUP"), + EVENTID_0x4302((short) 0x4302, "Mode transition from STARTUP to RUN"), + EVENTID_0x4303((short) 0x4303, "STOP caused by stop switch being activated"), + EVENTID_0x4304((short) 0x4304, "STOP caused by PG STOP operation or by SFB 20 STOP"), + EVENTID_0x4305((short) 0x4305, "HOLD: breakpoint reached"), + EVENTID_0x4306((short) 0x4306, "HOLD: breakpoint exited"), + EVENTID_0x4307((short) 0x4307, "Memory reset started by PG operation"), + EVENTID_0x4308((short) 0x4308, "Memory reset started by switch setting"), + EVENTID_0x4309((short) 0x4309, "Memory reset started automatically (power on not backed up)"), + EVENTID_0x430A((short) 0x430A, "HOLD exited, transition to STOP"), + EVENTID_0x430D((short) 0x430D, "STOP caused by other CPU in multicomputing"), + EVENTID_0x430E((short) 0x430E, "Memory reset executed"), + EVENTID_0x430F((short) 0x430F, "STOP on the module due to STOP on a CPU"), + EVENTID_0x4318((short) 0x4318, "Start of CiR"), + EVENTID_0x4319((short) 0x4319, "CiR completed"), + EVENTID_0x4357((short) 0x4357, "Module watchdog started"), + EVENTID_0x4358((short) 0x4358, "All modules are ready for operation"), + EVENTID_0x43B0((short) 0x43B0, "Firmware update was successful"), + EVENTID_0x43B4((short) 0x43B4, "Error in firmware fuse"), + EVENTID_0x43B6((short) 0x43B6, "Firmware updates canceled by redundant modules"), + EVENTID_0x43D3((short) 0x43D3, "STOP on standby CPU"), + EVENTID_0x43DC((short) 0x43DC, "Abort during link-up with switchover"), + EVENTID_0x43DE((short) 0x43DE, "Updating aborted due to monitoring time being exceeded during the n-th attempt, new update attempt initiated"), + EVENTID_0x43DF((short) 0x43DF, "Updating aborted for final time due to monitoring time being exceeded after completing the maximum amount of attempts. User intervention required"), + EVENTID_0x43E0((short) 0x43E0, "Change from solo mode after link-up"), + EVENTID_0x43E1((short) 0x43E1, "Change from link-up after updating"), + EVENTID_0x43E2((short) 0x43E2, "Change from updating to redundant mode"), + EVENTID_0x43E3((short) 0x43E3, "Master CPU: change from redundant mode to solo mode"), + EVENTID_0x43E4((short) 0x43E4, "Standby CPU: change from redundant mode after error-search mode"), + EVENTID_0x43E5((short) 0x43E5, "Standby CPU: change from error-search mode after link-up or STOP"), + EVENTID_0x43E6((short) 0x43E6, "Link-up aborted on the standby CPU"), + EVENTID_0x43E7((short) 0x43E7, "Updating aborted on the standby CPU"), + EVENTID_0x43E8((short) 0x43E8, "Standby CPU: change from link-up after startup"), + EVENTID_0x43E9((short) 0x43E9, "Standby CPU: change from startup after updating"), + EVENTID_0x43F1((short) 0x43F1, "Reserve-master switchover"), + EVENTID_0x43F2((short) 0x43F2, "Coupling of incompatible H-CPUs blocked by system program"), + EVENTID_0x4510((short) 0x4510, "STOP violation of the CPU's data range"), + EVENTID_0x4520((short) 0x4520, "DEFECTIVE: STOP not possible"), + EVENTID_0x4521((short) 0x4521, "DEFECTIVE: failure of instruction processing processor"), + EVENTID_0x4522((short) 0x4522, "DEFECTIVE: failure of clock chip"), + EVENTID_0x4523((short) 0x4523, "DEFECTIVE: failure of clock pulse generator"), + EVENTID_0x4524((short) 0x4524, "DEFECTIVE: failure of timer update function"), + EVENTID_0x4525((short) 0x4525, "DEFECTIVE: failure of multicomputing synchronization"), + EVENTID_0x4527((short) 0x4527, "DEFECTIVE: failure of I/O access monitoring"), + EVENTID_0x4528((short) 0x4528, "DEFECTIVE: failure of scan time monitoring"), + EVENTID_0x4530((short) 0x4530, "DEFECTIVE: memory test error in internal memory"), + EVENTID_0x4532((short) 0x4532, "DEFECTIVE: failure of core resources"), + EVENTID_0x4536((short) 0x4536, "DEFECTIVE: switch defective"), + EVENTID_0x4540((short) 0x4540, "STOP: Memory expansion of the internal work memory has gaps. First memory expansion too small or missing"), + EVENTID_0x4541((short) 0x4541, "STOP caused by priority class system"), + EVENTID_0x4542((short) 0x4542, "STOP caused by object management system"), + EVENTID_0x4543((short) 0x4543, "STOP caused by test functions"), + EVENTID_0x4544((short) 0x4544, "STOP caused by diagnostic system"), + EVENTID_0x4545((short) 0x4545, "STOP caused by communication system"), + EVENTID_0x4546((short) 0x4546, "STOP caused by CPU memory management"), + EVENTID_0x4547((short) 0x4547, "STOP caused by process image management"), + EVENTID_0x4548((short) 0x4548, "STOP caused by I/O management"), + EVENTID_0x454A((short) 0x454A, "STOP caused by configuration: an OB deselected with STEP 7 was being loaded into the CPU during STARTUP"), + EVENTID_0x4550((short) 0x4550, "DEFECTIVE: internal system error"), + EVENTID_0x4555((short) 0x4555, "No restart possible, monitoring time elapsed"), + EVENTID_0x4556((short) 0x4556, "STOP: memory reset request from communication system / due to data inconsistency"), + EVENTID_0x4562((short) 0x4562, "STOP caused by programming error (OB not loaded or not possible)"), + EVENTID_0x4563((short) 0x4563, "STOP caused by I/O access error (OB not loaded or not possible)"), + EVENTID_0x4567((short) 0x4567, "STOP caused by H event"), + EVENTID_0x4568((short) 0x4568, "STOP caused by time error (OB not loaded or not possible)"), + EVENTID_0x456A((short) 0x456A, "STOP caused by diagnostic interrupt (OB not loaded or not possible)"), + EVENTID_0x456B((short) 0x456B, "STOP caused by removing/inserting module (OB not loaded or not possible)"), + EVENTID_0x456C((short) 0x456C, "STOP caused by CPU hardware error (OB not loaded or not possible, or no FRB)"), + EVENTID_0x456D((short) 0x456D, "STOP caused by program sequence error (OB not loaded or not possible)"), + EVENTID_0x456E((short) 0x456E, "STOP caused by communication error (OB not loaded or not possible)"), + EVENTID_0x456F((short) 0x456F, "STOP caused by rack failure OB (OB not loaded or not possible)"), + EVENTID_0x4570((short) 0x4570, "STOP caused by process interrupt (OB not loaded or not possible)"), + EVENTID_0x4571((short) 0x4571, "STOP caused by nesting stack error"), + EVENTID_0x4572((short) 0x4572, "STOP caused by master control relay stack error"), + EVENTID_0x4573((short) 0x4573, "STOP caused by exceeding the nesting depth for synchronous errors"), + EVENTID_0x4574((short) 0x4574, "STOP caused by exceeding interrupt stack nesting depth in the priority class stack"), + EVENTID_0x4575((short) 0x4575, "STOP caused by exceeding block stack nesting depth in the priority class stack"), + EVENTID_0x4576((short) 0x4576, "STOP caused by error when allocating the local data"), + EVENTID_0x4578((short) 0x4578, "STOP caused by unknown opcode"), + EVENTID_0x457A((short) 0x457A, "STOP caused by code length error"), + EVENTID_0x457B((short) 0x457B, "STOP caused by DB not being loaded on on-board I/Os"), + EVENTID_0x457D((short) 0x457D, "Reset/clear request because the version of the internal interface to the integrated technology was changed"), + EVENTID_0x457F((short) 0x457F, "STOP caused by STOP command"), + EVENTID_0x4580((short) 0x4580, "STOP: back-up buffer contents inconsistent (no transition to RUN)"), + EVENTID_0x4590((short) 0x4590, "STOP caused by overloading the internal functions"), + EVENTID_0x45D5((short) 0x45D5, "LINK-UP rejected due to mismatched CPU memory configuration of the sub-PLC"), + EVENTID_0x45D6((short) 0x45D6, "LINK-UP rejected due to mismatched system program of the sub-PLC"), + EVENTID_0x45D8((short) 0x45D8, "DEFECTIVE: hardware fault detected due to other error"), + EVENTID_0x45D9((short) 0x45D9, "STOP due to SYNC module error"), + EVENTID_0x45DA((short) 0x45DA, "STOP due to synchronization error between H CPUs"), + EVENTID_0x45DD((short) 0x45DD, "LINK-UP rejected due to running test or other online functions"), + EVENTID_0x4926((short) 0x4926, "DEFECTIVE: failure of the watchdog for I/O access"), + EVENTID_0x4931((short) 0x4931, "STOP or DEFECTIVE: memory test error in memory submodule"), + EVENTID_0x4933((short) 0x4933, "Checksum error"), + EVENTID_0x4934((short) 0x4934, "DEFECTIVE: memory not available"), + EVENTID_0x4935((short) 0x4935, "DEFECTIVE: cancelled by watchdog/processor exceptions"), + EVENTID_0x4949((short) 0x4949, "STOP caused by continuous hardware interrupt"), + EVENTID_0x494D((short) 0x494D, "STOP caused by I/O error"), + EVENTID_0x494E((short) 0x494E, "STOP caused by power failure"), + EVENTID_0x494F((short) 0x494F, "STOP caused by configuration error"), + EVENTID_0x4959((short) 0x4959, "One or more modules not ready for operation"), + EVENTID_0x497C((short) 0x497C, "STOP caused by integrated technology"), + EVENTID_0x49A0((short) 0x49A0, "STOP caused by parameter assignment error or non-permissible variation of setpoint and actual extension: Start-up blocked"), + EVENTID_0x49A1((short) 0x49A1, "STOP caused by parameter assignment error: memory reset request"), + EVENTID_0x49A2((short) 0x49A2, "STOP caused by error in parameter modification: startup disabled"), + EVENTID_0x49A3((short) 0x49A3, "STOP caused by error in parameter modification: memory reset request"), + EVENTID_0x49A4((short) 0x49A4, "STOP: inconsistency in configuration data"), + EVENTID_0x49A5((short) 0x49A5, "STOP: distributed I/Os: inconsistency in the loaded configuration information"), + EVENTID_0x49A6((short) 0x49A6, "STOP: distributed I/Os: invalid configuration information"), + EVENTID_0x49A7((short) 0x49A7, "STOP: distributed I/Os: no configuration information"), + EVENTID_0x49A8((short) 0x49A8, "STOP: error indicated by the interface module for the distributed I/Os"), + EVENTID_0x49B1((short) 0x49B1, "Firmware update data incorrect"), + EVENTID_0x49B2((short) 0x49B2, "Firmware update: hardware version does not match firmware"), + EVENTID_0x49B3((short) 0x49B3, "Firmware update: module type does not match firmware"), + EVENTID_0x49D0((short) 0x49D0, "LINK-UP aborted due to violation of coordination rules"), + EVENTID_0x49D1((short) 0x49D1, "LINK-UP/UPDATE sequence aborted"), + EVENTID_0x49D2((short) 0x49D2, "Standby CPU changed to STOP due to STOP on the master CPU during link-up"), + EVENTID_0x49D4((short) 0x49D4, "STOP on a master, since partner CPU is also a master (link-up error)"), + EVENTID_0x49D7((short) 0x49D7, "LINK-UP rejected due to change in user program or in configuration"), + EVENTID_0x510F((short) 0x510F, "A problem as occurred with WinLC. This problem has caused the CPU to go into STOP mode or has caused a fault in the CPU"), + EVENTID_0x530D((short) 0x530D, "New startup information in the STOP mode"), + EVENTID_0x5311((short) 0x5311, "Startup despite Not Ready message from module(s)"), + EVENTID_0x5371((short) 0x5371, "Distributed I/Os: end of the synchronization with a DP master"), + EVENTID_0x5380((short) 0x5380, "Diagnostic buffer entries of interrupt and asynchronous errors disabled"), + EVENTID_0x5395((short) 0x5395, "Distributed I/Os: reset of a DP master"), + EVENTID_0x53A2((short) 0x53A2, "Download of technology firmware successful"), + EVENTID_0x53A4((short) 0x53A4, "Download of technology DB not successful"), + EVENTID_0x53FF((short) 0x53FF, "Reset to factory setting"), + EVENTID_0x5445((short) 0x5445, "Start of System reconfiguration in RUN mode"), + EVENTID_0x5481((short) 0x5481, "All licenses for runtime software are complete again"), + EVENTID_0x5498((short) 0x5498, "No more inconsistency with DP master systems due to CiR"), + EVENTID_0x5545((short) 0x5545, "Start of System reconfiguration in RUN mode"), + EVENTID_0x5581((short) 0x5581, "One or several licenses for runtime software are missing"), + EVENTID_0x558A((short) 0x558A, "Difference between the MLFB of the configured and inserted CPU"), + EVENTID_0x558B((short) 0x558B, "Difference in the firmware version of the configured and inserted CPU"), + EVENTID_0x5598((short) 0x5598, "Start of possible inconsistency with DP master systems due to CiR"), + EVENTID_0x55A5((short) 0x55A5, "Version conflict: internal interface with integrated technology"), + EVENTID_0x55A6((short) 0x55A6, "The maximum number of technology objects has been exceeded"), + EVENTID_0x55A7((short) 0x55A7, "A technology DB of this type is already present"), + EVENTID_0x5879((short) 0x5879, "Diagnostic message from DP interface: EXTF LED off"), + EVENTID_0x5960((short) 0x5960, "Parameter assignment error when switching"), + EVENTID_0x5961((short) 0x5961, "Parameter assignment error"), + EVENTID_0x5962((short) 0x5962, "Parameter assignment error preventing startup"), + EVENTID_0x5963((short) 0x5963, "Parameter assignment error with memory reset request"), + EVENTID_0x5966((short) 0x5966, "Parameter assignment error when switching"), + EVENTID_0x5969((short) 0x5969, "Parameter assignment error with startup blocked"), + EVENTID_0x596A((short) 0x596A, "PROFINET IO: IP address of an IO device already present"), + EVENTID_0x596B((short) 0x596B, "IP address of an Ethernet interface already exists"), + EVENTID_0x596C((short) 0x596C, "Name of an Ethernet interface already exists"), + EVENTID_0x596D((short) 0x596D, "The existing network configuration does not mach the system requirements or configuration"), + EVENTID_0x5979((short) 0x5979, "Diagnostic message from DP interface: EXTF LED on"), + EVENTID_0x597C((short) 0x597C, "DP Global Control command failed or moved"), + EVENTID_0x59A0((short) 0x59A0, "The interrupt can not be associated in the CPU"), + EVENTID_0x59A1((short) 0x59A1, "Configuration error in the integrated technology"), + EVENTID_0x59A3((short) 0x59A3, "Error when downloading the integrated technology"), + EVENTID_0x6253((short) 0x6253, "Firmware update: End of firmware download over the network"), + EVENTID_0x6316((short) 0x6316, "Interface error when starting programmable controller"), + EVENTID_0x6353((short) 0x6353, "Firmware update: Start of firmware download over the network"), + EVENTID_0x6390((short) 0x6390, "Formatting of Micro Memory Card complete"), + EVENTID_0x6500((short) 0x6500, "Connection ID exists twice on module"), + EVENTID_0x6501((short) 0x6501, "Connection resources inadequate"), + EVENTID_0x6502((short) 0x6502, "Error in the connection description"), + EVENTID_0x6510((short) 0x6510, "CFB structure error detected in instance DB when evaluating EPROM"), + EVENTID_0x6514((short) 0x6514, "GD packet number exists twice on the module"), + EVENTID_0x6515((short) 0x6515, "Inconsistent length specifications in GD configuration information"), + EVENTID_0x6521((short) 0x6521, "No memory submodule and no internal memory available"), + EVENTID_0x6522((short) 0x6522, "Illegal memory submodule: replace submodule and reset memory"), + EVENTID_0x6523((short) 0x6523, "Memory reset request due to error accessing submodule"), + EVENTID_0x6524((short) 0x6524, "Memory reset request due to error in block header"), + EVENTID_0x6526((short) 0x6526, "Memory reset request due to memory replacement"), + EVENTID_0x6527((short) 0x6527, "Memory replaced, therefore restart not possible"), + EVENTID_0x6528((short) 0x6528, "Object handling function in the STOP/HOLD mode, no restart possible"), + EVENTID_0x6529((short) 0x6529, "No startup possible during the load"), + EVENTID_0x652A((short) 0x652A, "No startup because block exists twice in user memory user program function"), + EVENTID_0x652B((short) 0x652B, "No startup because block is too long for submodule - replace submodule"), + EVENTID_0x652C((short) 0x652C, "No startup due to illegal OB on submodule"), + EVENTID_0x6532((short) 0x6532, "No startup because illegal configuration information on submodule"), + EVENTID_0x6533((short) 0x6533, "Memory reset request because of invalid submodule content"), + EVENTID_0x6534((short) 0x6534, "No startup: block exists more than once on submodule"), + EVENTID_0x6535((short) 0x6535, "No startup: not enough memory to transfer block from submodule"), + EVENTID_0x6536((short) 0x6536, "No startup: submodule contains an illegal block number"), + EVENTID_0x6537((short) 0x6537, "No startup: submodule contains a block with an illegal length"), + EVENTID_0x6538((short) 0x6538, "Local data or write-protection ID (for DB) of a block illegal for CPU"), + EVENTID_0x6539((short) 0x6539, "Illegal command in block (detected by compiler)"), + EVENTID_0x653A((short) 0x653A, "Memory reset request because local OB data on submodule too short"), + EVENTID_0x6543((short) 0x6543, "No startup: illegal block type"), + EVENTID_0x6544((short) 0x6544, "No startup: attribute relevant for processing illegal"), + EVENTID_0x6545((short) 0x6545, "Source language illegal"), + EVENTID_0x6546((short) 0x6546, "Maximum amount of configuration information reached"), + EVENTID_0x6547((short) 0x6547, "Parameter assignment error assigning parameters to modules (not on P bus, cancel download)"), + EVENTID_0x6548((short) 0x6548, "Plausibility error during block check"), + EVENTID_0x6549((short) 0x6549, "Structure error in block"), + EVENTID_0x6550((short) 0x6550, "A block has an error in the CRC"), + EVENTID_0x6551((short) 0x6551, "A block has no CRC"), + EVENTID_0x6560((short) 0x6560, "SCAN overflow"), + EVENTID_0x6805((short) 0x6805, "Resource problem on configured connections, eliminated"), + EVENTID_0x6881((short) 0x6881, "Interface error leaving state"), + EVENTID_0x6905((short) 0x6905, "Resource problem on configured connections"), + EVENTID_0x6981((short) 0x6981, "Interface error entering state"), + EVENTID_0x72A2((short) 0x72A2, "Failure of a DP master or a DP master system"), + EVENTID_0x72A3((short) 0x72A3, "Redundancy restored on the DP slave"), + EVENTID_0x72DB((short) 0x72DB, "Safety program: safety mode disabled"), + EVENTID_0x72E0((short) 0x72E0, "Loss of redundancy in communication, problem eliminated"), + EVENTID_0x7301((short) 0x7301, "Loss of redundancy (1 of 2) due to failure of a CPU"), + EVENTID_0x7302((short) 0x7302, "Loss of redundancy (1 of 2) due to STOP on the standby triggered by user"), + EVENTID_0x7303((short) 0x7303, "H system (1 of 2) changed to redundant mode"), + EVENTID_0x7323((short) 0x7323, "Discrepancy found in operating system data"), + EVENTID_0x7331((short) 0x7331, "Standby-master switchover due to master failure"), + EVENTID_0x7333((short) 0x7333, "Standby-master switchover due to system modification during runtime"), + EVENTID_0x7334((short) 0x7334, "Standby-master switchover due to communication error at the synchronization module"), + EVENTID_0x7340((short) 0x7340, "Synchronization error in user program due to elapsed wait time"), + EVENTID_0x7341((short) 0x7341, "Synchronization error in user program due to waiting at different synchronization points"), + EVENTID_0x7342((short) 0x7342, "Synchronization error in operating system due to waiting at different synchronization points"), + EVENTID_0x7343((short) 0x7343, "Synchronization error in operating system due to elapsed wait time"), + EVENTID_0x7344((short) 0x7344, "Synchronization error in operating system due to incorrect data"), + EVENTID_0x734A((short) 0x734A, "The \"Re-enable\" job triggered by SFC 90 \"H_CTRL\" was executed"), + EVENTID_0x73A3((short) 0x73A3, "Loss of redundancy on the DP slave"), + EVENTID_0x73C1((short) 0x73C1, "Update process canceled"), + EVENTID_0x73C2((short) 0x73C2, "Updating aborted due to monitoring time being exceeded during the n-th attempt (1 = n = max. possible number of update attempts after abort due to excessive monitoring time)"), + EVENTID_0x73D8((short) 0x73D8, "Safety mode disabled"), + EVENTID_0x73DB((short) 0x73DB, "Safety program: safety mode enabled"), + EVENTID_0x73E0((short) 0x73E0, "Loss of redundancy in communication"), + EVENTID_0x74DD((short) 0x74DD, "Safety program: Shutdown of a fail-save runtime group disabled"), + EVENTID_0x74DE((short) 0x74DE, "Safety program: Shutdown of the F program disabled"), + EVENTID_0x74DF((short) 0x74DF, "Start of F program initialization"), + EVENTID_0x7520((short) 0x7520, "Error in RAM comparison"), + EVENTID_0x7521((short) 0x7521, "Error in comparison of process image output value"), + EVENTID_0x7522((short) 0x7522, "Error in comparison of memory bits, timers, or counters"), + EVENTID_0x75D1((short) 0x75D1, "Safety program: Internal CPU error"), + EVENTID_0x75D2((short) 0x75D2, "Safety program error: Cycle time time-out"), + EVENTID_0x75D6((short) 0x75D6, "Data corrupted in safety program prior to the output to F I/O"), + EVENTID_0x75D7((short) 0x75D7, "Data corrupted in safety program prior to the output to partner F-CPU"), + EVENTID_0x75D9((short) 0x75D9, "Invalid REAL number in a DB"), + EVENTID_0x75DA((short) 0x75DA, "Safety program: Error in safety data format"), + EVENTID_0x75DC((short) 0x75DC, "Runtime group, internal protocol error"), + EVENTID_0x75DD((short) 0x75DD, "Safety program: Shutdown of a fail-save runtime group enabled"), + EVENTID_0x75DE((short) 0x75DE, "Safety program: Shutdown of the F program enabled"), + EVENTID_0x75DF((short) 0x75DF, "End of F program initialization"), + EVENTID_0x75E1((short) 0x75E1, "Safety program: Error in FB \"F_PLK\" or \"F_PLK_O\" or \"F_CYC_CO\" or \"F_TEST\" or \"F_TESTC\""), + EVENTID_0x75E2((short) 0x75E2, "Safety program: Area length error"), + EVENTID_0x7852((short) 0x7852, "SYNC module inserted"), + EVENTID_0x7855((short) 0x7855, "SYNC module eliminated"), + EVENTID_0x78D3((short) 0x78D3, "Communication error between PROFIsafe and F I/O"), + EVENTID_0x78D4((short) 0x78D4, "Error in safety relevant communication between F CPUs"), + EVENTID_0x78D5((short) 0x78D5, "Error in safety relevant communication between F CPUs"), + EVENTID_0x78E3((short) 0x78E3, "F-I/O device input channel depassivated"), + EVENTID_0x78E4((short) 0x78E4, "F-I/O device output channel depassivated"), + EVENTID_0x78E5((short) 0x78E5, "F-I/O device depassivated"), + EVENTID_0x7934((short) 0x7934, "Standby-master switchover due to connection problem at the SYNC module"), + EVENTID_0x7950((short) 0x7950, "Synchronization module missing"), + EVENTID_0x7951((short) 0x7951, "Change at the SYNC module without Power On"), + EVENTID_0x7952((short) 0x7952, "SYNC module removed"), + EVENTID_0x7953((short) 0x7953, "Change at the SYNC-module without reset"), + EVENTID_0x7954((short) 0x7954, "SYNC module: rack number assigned twice"), + EVENTID_0x7955((short) 0x7955, "SYNC module error"), + EVENTID_0x7956((short) 0x7956, "Illegal rack number set on SYNC module"), + EVENTID_0x7960((short) 0x7960, "Redundant I/O: Time-out of discrepancy time at digital input, error is not yet localized"), + EVENTID_0x7961((short) 0x7961, "Redundant I/O, digital input error: Signal change after expiration of the discrepancy time"), + EVENTID_0x7962((short) 0x7962, "Redundant I/O: Digital input error"), + EVENTID_0x796F((short) 0x796F, "Redundant I/O: The I/O was globally disabled"), + EVENTID_0x7970((short) 0x7970, "Redundant I/O: Digital output error"), + EVENTID_0x7980((short) 0x7980, "Redundant I/O: Time-out of discrepancy time at analog input"), + EVENTID_0x7981((short) 0x7981, "Redundant I/O: Analog input error"), + EVENTID_0x7990((short) 0x7990, "Redundant I/O: Analog output error"), + EVENTID_0x79D3((short) 0x79D3, "Communication error between PROFIsafe and F I/O"), + EVENTID_0x79D4((short) 0x79D4, "Error in safety relevant communication between F CPUs"), + EVENTID_0x79D5((short) 0x79D5, "Error in safety relevant communication between F CPUs"), + EVENTID_0x79E3((short) 0x79E3, "F-I/O device input channel passivated"), + EVENTID_0x79E4((short) 0x79E4, "F-I/O device output channel passivated"), + EVENTID_0x79E5((short) 0x79E5, "F-I/O device passivated"), + EVENTID_0x79E6((short) 0x79E6, "Inconsistent safety program"), + EVENTID_0x79E7((short) 0x79E7, "Simulation block (F system block) loaded"), + EVENTID_0x0000((short) 0x0000, "NULL"),; + + + + private static final Map map; + + static { + map = new HashMap<>(); + for (S7DiagnosticEventId subevent : S7DiagnosticEventId .values()) { + map.put(subevent.code, subevent); + } + } + + private final String event; + private final short code; + + S7DiagnosticEventId(short code, String event){ + this.event = event; + this.code = code; + } + + public String getEvent(){ + return event; + } + + public short getCode() { + return code; + } + + public static S7DiagnosticEventId valueOfEvent(String event) { + for (S7DiagnosticEventId value : S7DiagnosticEventId .values()) { + if(value.getEvent().equals(event)) { + return value; + } + } + return null; + } + + public static S7DiagnosticEventId valueOf(short code) { + return map.get(code); + } +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7ParamErrorCode.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7ParamErrorCode.java new file mode 100644 index 00000000000..9fe86d25e0f --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7ParamErrorCode.java @@ -0,0 +1,276 @@ +/* + 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.utils; + +import java.util.HashMap; +import java.util.Map; + +/** + * + * @author cgarcia + */ +public enum S7ParamErrorCode { + + ERROR_0x0000((short) 0x0000, "No error"), + ERROR_0x0110((short) 0x0110, "Invalid block number"), + ERROR_0x0111((short) 0x0111, "Invalid request length"), + ERROR_0x0112((short) 0x0112, "Invalid parameter"), + ERROR_0x0113((short) 0x0113, "Invalid block type"), + ERROR_0x0114((short) 0x0114, "Block not found"), + ERROR_0x0115((short) 0x0115, "Block already exists"), + ERROR_0x0116((short) 0x0116, "Block is write-protected"), + ERROR_0x0117((short) 0x0117, "The block/operating system update is too large"), + ERROR_0x0118((short) 0x0118, "Invalid block number"), + ERROR_0x0119((short) 0x0119, "Incorrect password entered"), + ERROR_0x011A((short) 0x011A, "PG resource error"), + ERROR_0x011B((short) 0x011B, "PLC resource error"), + ERROR_0x011C((short) 0x011C, "Protocol error"), + ERROR_0x011D((short) 0x011D, "Too many blocks (module-related restriction)"), + ERROR_0x011E((short) 0x011E, "There is no longer a connection to the database, or S7DOS handle is invalid"), + ERROR_0x011F((short) 0x011F, "Result buffer too small"), + ERROR_0x0120((short) 0x0120, "End of block list"), + ERROR_0x0140((short) 0x0140, "Insufficient memory available"), + ERROR_0x0141((short) 0x0141, "Job cannot be processed because of a lack of resources"), + ERROR_0x8001((short) 0x8001, "The requested service cannot be performed while the block is in the current status"), + ERROR_0x8003((short) 0x8003, "S7 protocol error: Error occurred while transferring the block"), + ERROR_0x8100((short) 0x8100, "Application, general error: Service unknown to remote module"), + ERROR_0x8104((short) 0x8104, "This service is not implemented on the module or a frame error was reported"), + ERROR_0x8204((short) 0x8204, "The type specification for the object is inconsistent"), + ERROR_0x8205((short) 0x8205, "A copied block already exists and is not linked"), + ERROR_0x8301((short) 0x8301, "Insufficient memory space or work memory on the module, or specified storage medium not accessible"), + ERROR_0x8302((short) 0x8302, "Too few resources available or the processor resources are not available"), + ERROR_0x8304((short) 0x8304, "No further parallel upload possible. There is a resource bottleneck"), + ERROR_0x8305((short) 0x8305, "Function not available"), + ERROR_0x8306((short) 0x8306, "Insufficient work memory (for copying, linking, loading AWP)"), + ERROR_0x8307((short) 0x8307, "Not enough retentive work memory (for copying, linking, loading AWP)"), + ERROR_0x8401((short) 0x8401, "S7 protocol error: Invalid service sequence (for example, loading or uploading a block)"), + ERROR_0x8402((short) 0x8402, "Service cannot execute owing to status of the addressed object"), + ERROR_0x8404((short) 0x8404, "S7 protocol: The function cannot be performed"), + ERROR_0x8405((short) 0x8405, "Remote block is in DISABLE state (CFB). The function cannot be performed"), + ERROR_0x8500((short) 0x8500, "S7 protocol error: Wrong frames"), + ERROR_0x8503((short) 0x8503, "Alarm from the module: Service canceled prematurely"), + ERROR_0x8701((short) 0x8701, "Error addressing the object on the communications partner (for example, area length error)"), + ERROR_0x8702((short) 0x8702, "The requested service is not supported by the module"), + ERROR_0x8703((short) 0x8703, "Access to object refused"), + ERROR_0x8704((short) 0x8704, "Access error: Object damaged"), + ERROR_0xD001((short) 0xD001, "Protocol error: Illegal job number"), + ERROR_0xD002((short) 0xD002, "Parameter error: Illegal job variant"), + ERROR_0xD003((short) 0xD003, "Parameter error: Debugging function not supported by module"), + ERROR_0xD004((short) 0xD004, "Parameter error: Illegal job status"), + ERROR_0xD005((short) 0xD005, "Parameter error: Illegal job termination"), + ERROR_0xD006((short) 0xD006, "Parameter error: Illegal link disconnection ID"), + ERROR_0xD007((short) 0xD007, "Parameter error: Illegal number of buffer elements"), + ERROR_0xD008((short) 0xD008, "Parameter error: Illegal scan rate"), + ERROR_0xD009((short) 0xD009, "Parameter error: Illegal number of executions"), + ERROR_0xD00A((short) 0xD00A, "Parameter error: Illegal trigger event"), + ERROR_0xD00B((short) 0xD00B, "Parameter error: Illegal trigger condition"), + ERROR_0xD011((short) 0xD011, "Parameter error in path of the call environment: Block does not exist"), + ERROR_0xD012((short) 0xD012, "Parameter error: Wrong address in block"), + ERROR_0xD014((short) 0xD014, "Parameter error: Block being deleted/overwritten"), + ERROR_0xD015((short) 0xD015, "Parameter error: Illegal tag address"), + ERROR_0xD016((short) 0xD016, "Parameter error: Test jobs not possible, because of errors in user program"), + ERROR_0xD017((short) 0xD017, "Parameter error: Illegal trigger number"), + ERROR_0xD025((short) 0xD025, "Parameter error: Invalid path"), + ERROR_0xD026((short) 0xD026, "Parameter error: Illegal access type"), + ERROR_0xD027((short) 0xD027, "Parameter error: This number of data blocks is not permitted"), + ERROR_0xD031((short) 0xD031, "Internal protocol error"), + ERROR_0xD032((short) 0xD032, "Parameter error: Wrong result buffer length"), + ERROR_0xD033((short) 0xD033, "Protocol error: Wrong job length"), + ERROR_0xD03F((short) 0xD03F, "Coding error: Error in parameter section (for example, reserve bytes not equal to 0)"), + ERROR_0xD041((short) 0xD041, "Data error: Illegal status list ID"), + ERROR_0xD042((short) 0xD042, "Data error: Illegal tag address"), + ERROR_0xD043((short) 0xD043, "Data error: Referenced job not found, check job data"), + ERROR_0xD044((short) 0xD044, "Data error: Illegal tag value, check job data"), + ERROR_0xD045((short) 0xD045, "Data error: Exiting the ODIS control is not allowed in HOLD"), + ERROR_0xD046((short) 0xD046, "Data error: Illegal measuring stage during run-time measurement"), + ERROR_0xD047((short) 0xD047, "Data error: Illegal hierarchy in 'Read job list'"), + ERROR_0xD048((short) 0xD048, "Data error: Illegal deletion ID in 'Delete job'"), + ERROR_0xD049((short) 0xD049, "Invalid substitute ID in 'Replace job'"), + ERROR_0xD04A((short) 0xD04A, "Error executing 'program status'"), + ERROR_0xD05F((short) 0xD05F, "Coding error: Error in data section (for example, reserve bytes not equal to 0, ...)"), + ERROR_0xD061((short) 0xD061, "Resource error: No memory space for job"), + ERROR_0xD062((short) 0xD062, "Resource error: Job list full"), + ERROR_0xD063((short) 0xD063, "Resource error: Trigger event occupied"), + ERROR_0xD064((short) 0xD064, "Resource error: Not enough memory space for one result buffer element"), + ERROR_0xD065((short) 0xD065, "Resource error: Not enough memory space for several result buffer elements"), + ERROR_0xD066((short) 0xD066, "Resource error: The timer available for run-time measurement is occupied by another job"), + ERROR_0xD067((short) 0xD067, "Resource error: Too many 'modify tag' jobs active (in particular multi-processor operation)"), + ERROR_0xD081((short) 0xD081, "Function not permitted in current mode"), + ERROR_0xD082((short) 0xD082, "Mode error: Cannot exit HOLD mode"), + ERROR_0xD0A1((short) 0xD0A1, "Function not permitted in current protection level"), + ERROR_0xD0A2((short) 0xD0A2, "Function not possible at present, because a function is running that modifies memory"), + ERROR_0xD0A3((short) 0xD0A3, "Too many 'modify tag' jobs active on the I/O (in particular multi-processor operation)"), + ERROR_0xD0A4((short) 0xD0A4, "Forcing' has already been established"), + ERROR_0xD0A5((short) 0xD0A5, "Referenced job not found"), + ERROR_0xD0A6((short) 0xD0A6, "Job cannot be disabled/enabled"), + ERROR_0xD0A7((short) 0xD0A7, "Job cannot be deleted, for example because it is currently being read"), + ERROR_0xD0A8((short) 0xD0A8, "Job cannot be replaced, for example because it is currently being read or deleted"), + ERROR_0xD0A9((short) 0xD0A9, "Job cannot be read, for example because it is currently being deleted"), + ERROR_0xD0AA((short) 0xD0AA, "Time limit exceeded in processing operation"), + ERROR_0xD0AB((short) 0xD0AB, "Invalid job parameters in process operation"), + ERROR_0xD0AC((short) 0xD0AC, "Invalid job data in process operation"), + ERROR_0xD0AD((short) 0xD0AD, "Operating mode already set"), + ERROR_0xD0AE((short) 0xD0AE, "The job was set up over a different connection and can only be handled over this connection"), + ERROR_0xD0C1((short) 0xD0C1, "At least one error has been detected while accessing the tag(s)"), + ERROR_0xD0C2((short) 0xD0C2, "Change to STOP/HOLD mode"), + ERROR_0xD0C3((short) 0xD0C3, "At least one error was detected while accessing the tag(s). Mode change to STOP/HOLD"), + ERROR_0xD0C4((short) 0xD0C4, "Timeout during run-time measurement"), + ERROR_0xD0C5((short) 0xD0C5, "Display of block stack inconsistent, because blocks were deleted/reloaded"), + ERROR_0xD0C6((short) 0xD0C6, "Job was automatically deleted as the jobs it referenced have been deleted"), + ERROR_0xD0C7((short) 0xD0C7, "The job was automatically deleted because STOP mode was exited"), + ERROR_0xD0C8((short) 0xD0C8, "Block status' aborted because of inconsistencies between test job and running program"), + ERROR_0xD0C9((short) 0xD0C9, "Exit the status area by resetting OB90"), + ERROR_0xD0CA((short) 0xD0CA, "Exiting the status range by resetting OB90 and access error reading tags before exiting"), + ERROR_0xD0CB((short) 0xD0CB, "The output disable for the peripheral outputs has been activated again"), + ERROR_0xD0CC((short) 0xD0CC, "The amount of data for the debugging functions is restricted by the time limit"), + ERROR_0xD201((short) 0xD201, "Syntax error in block name"), + ERROR_0xD202((short) 0xD202, "Syntax error in function parameters"), + ERROR_0xD205((short) 0xD205, "Linked block already exists in RAM: Conditional copying is not possible"), + ERROR_0xD206((short) 0xD206, "Linked block already exists in EPROM: Conditional copying is not possible"), + ERROR_0xD208((short) 0xD208, "Maximum number of copied (not linked) blocks on module exceeded"), + ERROR_0xD209((short) 0xD209, "(At least) one of the given blocks not found on the module"), + ERROR_0xD20A((short) 0xD20A, "The maximum number of blocks that can be linked with one job was exceeded"), + ERROR_0xD20B((short) 0xD20B, "The maximum number of blocks that can be deleted with one job was exceeded"), + ERROR_0xD20C((short) 0xD20C, "OB cannot be copied because the associated priority class does not exist"), + ERROR_0xD20D((short) 0xD20D, "SDB cannot be interpreted (for example, unknown number)"), + ERROR_0xD20E((short) 0xD20E, "No (further) block available"), + ERROR_0xD20F((short) 0xD20F, "Module-specific maximum block size exceeded"), + ERROR_0xD210((short) 0xD210, "Invalid block number"), + ERROR_0xD212((short) 0xD212, "Incorrect header attribute (run-time relevant)"), + ERROR_0xD213((short) 0xD213, "Too many SDBs. Note the restrictions on the module being used"), + ERROR_0xD216((short) 0xD216, "Invalid user program - reset module"), + ERROR_0xD217((short) 0xD217, "Protection level specified in module properties not permitted"), + ERROR_0xD218((short) 0xD218, "Incorrect attribute (active/passive)"), + ERROR_0xD219((short) 0xD219, "Incorrect block lengths (for example, incorrect length of first section or of the whole block)"), + ERROR_0xD21A((short) 0xD21A, "Incorrect local data length or write-protection code faulty"), + ERROR_0xD21B((short) 0xD21B, "Module cannot compress or compression was interrupted early"), + ERROR_0xD21D((short) 0xD21D, "The volume of dynamic project data transferred is illegal"), + ERROR_0xD21E((short) 0xD21E, "Unable to assign parameters to a module (such as FM, CP). The system data could not be linked"), + ERROR_0xD220((short) 0xD220, "Invalid programming language. Note the restrictions on the module being used"), + ERROR_0xD221((short) 0xD221, "The system data for connections or routing are not valid"), + ERROR_0xD222((short) 0xD222, "The system data of the global data definition contain invalid parameters"), + ERROR_0xD223((short) 0xD223, "Error in instance data block for communication function block or maximum number of instance DBs exceeded"), + ERROR_0xD224((short) 0xD224, "The SCAN system data block contains invalid parameters"), + ERROR_0xD225((short) 0xD225, "The DP system data block contains invalid parameters"), + ERROR_0xD226((short) 0xD226, "A structural error occurred in a block"), + ERROR_0xD230((short) 0xD230, "A structural error occurred in a block"), + ERROR_0xD231((short) 0xD231, "At least one loaded OB cannot be copied because the associated priority class does not exist"), + ERROR_0xD232((short) 0xD232, "At least one block number of a loaded block is illegal"), + ERROR_0xD234((short) 0xD234, "Block exists twice in the specified memory medium or in the job"), + ERROR_0xD235((short) 0xD235, "The block contains an incorrect checksum"), + ERROR_0xD236((short) 0xD236, "The block does not contain a checksum"), + ERROR_0xD237((short) 0xD237, "You are about to load the block twice, i.e. a block with the same time stamp already exists on the CPU"), + ERROR_0xD238((short) 0xD238, "At least one of the blocks specified is not a DB"), + ERROR_0xD239((short) 0xD239, "At least one of the DBs specified is not available as a linked variant in the load memory"), + ERROR_0xD23A((short) 0xD23A, "At least one of the specified DBs is considerably different from the copied and linked variant"), + ERROR_0xD240((short) 0xD240, "Coordination rules violated"), + ERROR_0xD241((short) 0xD241, "The function is not permitted in the current protection level"), + ERROR_0xD242((short) 0xD242, "Protection violation while processing F blocks"), + ERROR_0xD250((short) 0xD250, "Update and module ID or version do not match"), + ERROR_0xD251((short) 0xD251, "Incorrect sequence of operating system components"), + ERROR_0xD252((short) 0xD252, "Checksum error"), + ERROR_0xD253((short) 0xD253, "No executable loader available; update only possible using a memory card"), + ERROR_0xD254((short) 0xD254, "Storage error in operating system"), + ERROR_0xD280((short) 0xD280, "Error compiling block in S7-300 CPU"), + ERROR_0xD2A1((short) 0xD2A1, "Another block function or a trigger on a block is active"), + ERROR_0xD2A2((short) 0xD2A2, "A trigger is active on a block. Complete the debugging function first"), + ERROR_0xD2A3((short) 0xD2A3, "The block is not active (linked), the block is occupied or the block is currently marked for deletion"), + ERROR_0xD2A4((short) 0xD2A4, "The block is already being processed by another block function"), + ERROR_0xD2A6((short) 0xD2A6, "It is not possible to save and change the user program simultaneously"), + ERROR_0xD2A7((short) 0xD2A7, "The block has the attribute 'unlinked' or is not processed"), + ERROR_0xD2A8((short) 0xD2A8, "An active debugging function is preventing parameters from being assigned to the CPU"), + ERROR_0xD2A9((short) 0xD2A9, "New parameters are being assigned to the CPU"), + ERROR_0xD2AA((short) 0xD2AA, "New parameters are currently being assigned to the modules"), + ERROR_0xD2AB((short) 0xD2AB, "The dynamic configuration limits are currently being changed"), + ERROR_0xD2AC((short) 0xD2AC, "A running active or deactivate assignment (SFC 12) is temporarily preventing R-KiR process"), + ERROR_0xD2B0((short) 0xD2B0, "An error occurred while configuring in RUN (CiR)"), + ERROR_0xD2C0((short) 0xD2C0, "The maximum number of technological objects has been exceeded"), + ERROR_0xD2C1((short) 0xD2C1, "The same technology data block already exists on the module"), + ERROR_0xD2C2((short) 0xD2C2, "Downloading the user program or downloading the hardware configuration is not possible"), + ERROR_0xD401((short) 0xD401, "Information function unavailable"), + ERROR_0xD402((short) 0xD402, "Information function unavailable"), + ERROR_0xD403((short) 0xD403, "Service has already been logged on/off (Diagnostics/PMC)"), + ERROR_0xD404((short) 0xD404, "Maximum number of nodes reached. No more logons possible for diagnostics/PMC"), + ERROR_0xD405((short) 0xD405, "Service not supported or syntax error in function parameters"), + ERROR_0xD406((short) 0xD406, "Required information currently unavailable"), + ERROR_0xD407((short) 0xD407, "Diagnostics error occurred"), + ERROR_0xD408((short) 0xD408, "Update aborted"), + ERROR_0xD409((short) 0xD409, "Error on DP bus"), + ERROR_0xD601((short) 0xD601, "Syntax error in function parameter"), + ERROR_0xD602((short) 0xD602, "Incorrect password entered"), + ERROR_0xD603((short) 0xD603, "The connection has already been legitimized"), + ERROR_0xD604((short) 0xD604, "The connection has already been enabled"), + ERROR_0xD605((short) 0xD605, "Legitimization not possible because password does not exist"), + ERROR_0xD801((short) 0xD801, "At least one tag address is invalid"), + ERROR_0xD802((short) 0xD802, "Specified job does not exist"), + ERROR_0xD803((short) 0xD803, "Illegal job status"), + ERROR_0xD804((short) 0xD804, "Illegal cycle time (illegal time base or multiple)"), + ERROR_0xD805((short) 0xD805, "No more cyclic read jobs can be set up"), + ERROR_0xD806((short) 0xD806, "The referenced job is in a state in which the requested function cannot be performed"), + ERROR_0xD807((short) 0xD807, "Function aborted due to overload, meaning executing the read cycle takes longer than the set scan cycle time"), + ERROR_0xDC01((short) 0xDC01, "Date and/or time invalid"), + ERROR_0xE201((short) 0xE201, "CPU is already the master"), + ERROR_0xE202((short) 0xE202, "Connect and update not possible due to different user program in flash module"), + ERROR_0xE203((short) 0xE203, "Connect and update not possible due to different firmware"), + ERROR_0xE204((short) 0xE204, "Connect and update not possible due to different memory configuration"), + ERROR_0xE205((short) 0xE205, "Connect/update aborted due to synchronization error"), + ERROR_0xE206((short) 0xE206, "Connect/update denied due to coordination violation"), + ERROR_0xEF01((short) 0xEF01, "S7 protocol error: Error at ID2; only 00H permitted in job"), + ERROR_0xEF02((short) 0xEF02, "S7 protocol error: Error at ID2; set of resources does not exist"),; + + + private static final Map map; + + static { + map = new HashMap<>(); + for (S7ParamErrorCode subevent : S7ParamErrorCode .values()) { + map.put(subevent.code, subevent); + } + } + + private final String event; + private final short code; + + S7ParamErrorCode(short code, String event){ + this.event = event; + this.code = code; + } + + public String getEvent(){ + return event; + } + + public short getCode() { + return code; + } + + public static S7ParamErrorCode valueOfEvent(String event) { + for (S7ParamErrorCode value : S7ParamErrorCode .values()) { + if(value.getEvent().equals(event)) { + return value; + } + } + return null; + } + + public static S7ParamErrorCode valueOf(short code) { + return map.get(code); + } +} From d26cabc62aea1484ce2e85c746756b7bd23cdee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Mon, 20 Jan 2020 17:13:45 -0400 Subject: [PATCH 06/17] Recibing events. Next translate in standard message --- .../java/s7/connection/S7PlcConnection.java | 119 ++- .../apache/plc4x/java/s7/model/S7Field.java | 6 +- .../java/s7/model/S7SubscriptionField.java | 166 +++++ .../plc4x/java/s7/netty/Plc4XS7Protocol.java | 396 +++++++++- .../plc4x/java/s7/netty/S7Protocol.java | 688 +++++++++++++----- .../plc4x/java/s7/netty/events/S7Alarm.java | 5 +- .../CpuCyclicServicesRequestParameter.java | 60 ++ .../CpuCyclicServicesResponseParameter.java | 50 ++ .../params/CpuServicesResponseParameter.java | 10 + .../model/payloads/AlarmMessagePayload.java | 11 + .../CpuCyclicServicesRequestPayload.java | 91 +++ .../CpuCyclicServicesResponsePayload.java | 84 +++ .../CpuCyclicServicesUnsubscribePayload.java | 79 ++ .../s7/netty/model/payloads/VarPayload.java | 5 +- .../payloads/items/AlarmMessageItem.java | 24 +- .../payloads/items/MessageObjectItem.java | 158 +++- .../payloads/items/S7AnyVarPayloadItem.java | 95 +++ .../types/CpuCyclicServiceTimeBaseType.java | 76 ++ .../CpuServicesParameterFunctionGroup.java | 15 +- .../s7/netty/model/types/ParameterType.java | 1 + .../java/s7/netty/model/types/QueryType.java | 73 ++ .../model/types/VariableAddressingMode.java | 2 + ...ndler.java => S7PlcFieldEventHandler.java} | 9 +- .../java/s7/netty/util/S7SizeHelper.java | 15 + .../S7CyclicServicesSubscriptionHandle.java | 83 +++ .../S7DiagnosticSubscriptionHandle.java | 46 ++ .../s7/types/S7SubscriptionFieldType.java | 34 + 27 files changed, 2150 insertions(+), 251 deletions(-) create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7SubscriptionField.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuCyclicServicesRequestParameter.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuCyclicServicesResponseParameter.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuCyclicServicesRequestPayload.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuCyclicServicesResponsePayload.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuCyclicServicesUnsubscribePayload.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/S7AnyVarPayloadItem.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuCyclicServiceTimeBaseType.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/QueryType.java rename plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/{S7PlcEventHandler.java => S7PlcFieldEventHandler.java} (78%) create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7CyclicServicesSubscriptionHandle.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7DiagnosticSubscriptionHandle.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/types/S7SubscriptionFieldType.java diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java index 3c7de57905a..b4cc4499790 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java @@ -18,11 +18,15 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.s7.connection; +import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.*; import java.net.InetAddress; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.CompletableFuture; @@ -33,6 +37,7 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.commons.configuration2.Configuration; import org.apache.commons.configuration2.SystemConfiguration; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; import org.apache.plc4x.java.api.exceptions.PlcConnectionException; import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; import org.apache.plc4x.java.api.messages.PlcReadRequest; @@ -47,6 +52,7 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.api.model.PlcConsumerRegistration; import org.apache.plc4x.java.api.model.PlcField; import org.apache.plc4x.java.api.model.PlcSubscriptionHandle; +import org.apache.plc4x.java.api.types.PlcResponseCode; import org.apache.plc4x.java.base.connection.ChannelFactory; import org.apache.plc4x.java.base.connection.NettyPlcConnection; import org.apache.plc4x.java.base.events.ConnectEvent; @@ -65,11 +71,14 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.netty.model.params.CpuDiagnosticPushParameter; import org.apache.plc4x.java.s7.netty.model.params.CpuServicesPushParameter; import org.apache.plc4x.java.s7.netty.model.payloads.AlarmMessagePayload; +import org.apache.plc4x.java.s7.netty.model.payloads.CpuCyclicServicesResponsePayload; import org.apache.plc4x.java.s7.netty.model.payloads.CpuDiagnosticMessagePayload; +import org.apache.plc4x.java.s7.netty.model.payloads.items.AssociatedValueItem; import org.apache.plc4x.java.s7.netty.model.types.MemoryArea; import org.apache.plc4x.java.s7.netty.strategies.DefaultS7MessageProcessor; -import org.apache.plc4x.java.s7.netty.util.S7PlcEventHandler; +import org.apache.plc4x.java.s7.netty.util.S7PlcFieldEventHandler; import org.apache.plc4x.java.s7.netty.util.S7PlcFieldHandler; +import org.apache.plc4x.java.s7.protocol.S7CyclicServicesSubscriptionHandle; import org.apache.plc4x.java.s7.types.S7ControllerType; import org.apache.plc4x.java.s7.utils.S7TsapIdEncoder; import org.apache.plc4x.java.tcp.connection.TcpSocketChannelFactory; @@ -113,7 +122,12 @@ public class S7PlcConnection extends NettyPlcConnection implements PlcReader, Pl private final S7ControllerType paramControllerType; private BlockingQueue alarmsqueue; - private AlarmsLoop alarmsloopthread; + + Map> cyclicServicesSubscriptions = new HashMap(); + + Map cyclicServicesHandles = new HashMap(); + + private EventLoop alarmsloopthread; public S7PlcConnection(InetAddress address, int rack, int slot, String params) { this(new TcpSocketChannelFactory(address, ISO_ON_TCP_PORT), rack, slot, params); @@ -186,7 +200,10 @@ public S7PlcConnection(ChannelFactory channelFactory, int rack, int slot, String */ this.alarmsqueue = new ArrayBlockingQueue<>(1024); - alarmsloopthread = new AlarmsLoop(channel,this.alarmsqueue); + alarmsloopthread = new EventLoop(channel, + this.alarmsqueue, + cyclicServicesSubscriptions, + cyclicServicesHandles); } @@ -327,7 +344,7 @@ public PlcWriteRequest.Builder writeRequestBuilder() { @Override public PlcSubscriptionRequest.Builder subscriptionRequestBuilder() { - return new DefaultPlcSubscriptionRequest.Builder(this, new S7PlcEventHandler()); + return new DefaultPlcSubscriptionRequest.Builder(this, new S7PlcFieldEventHandler()); } @Override @@ -367,35 +384,59 @@ public CompletableFuture write(PlcWriteRequest writeRequest) { @Override public CompletableFuture subscribe(PlcSubscriptionRequest subscriptionRequest) { + InternalPlcSubscriptionRequest internalSubsRequest = checkInternal(subscriptionRequest, InternalPlcSubscriptionRequest.class); + CompletableFuture future = new CompletableFuture<>(); + PlcRequestContainer container = new PlcRequestContainer<>(internalSubsRequest, future); + channel.writeAndFlush(container).addListener(f -> { if (!f.isSuccess()) { future.completeExceptionally(f.cause()); } - }); + }); + return future.thenApply(PlcSubscriptionResponse.class::cast); } @Override public CompletableFuture unsubscribe(PlcUnsubscriptionRequest unsubscriptionRequest) { + InternalPlcUnsubscriptionRequest internalUnsubsRequest = checkInternal(unsubscriptionRequest, InternalPlcUnsubscriptionRequest.class); + CompletableFuture future = new CompletableFuture<>(); + PlcRequestContainer container = new PlcRequestContainer<>(internalUnsubsRequest, future); + channel.writeAndFlush(container).addListener(f -> { if (!f.isSuccess()) { future.completeExceptionally(f.cause()); } - }); + }); + return future.thenApply(PlcUnsubscriptionResponse.class::cast); } @Override public PlcConsumerRegistration register(Consumer consumer, Collection handles) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + //Add any handler to + handles.forEach(handle ->{ + if (handle instanceof S7CyclicServicesSubscriptionHandle) { + S7CyclicServicesSubscriptionHandle s7handle = (S7CyclicServicesSubscriptionHandle) handle; + if (!cyclicServicesHandles.containsKey(s7handle.getJobId())){ + cyclicServicesHandles.put(s7handle.getJobId(), s7handle); + } + } + }); + + if (!cyclicServicesSubscriptions.containsKey(consumer)){ + cyclicServicesSubscriptions.put(consumer, handles); + } + + return null; } @Override @@ -403,25 +444,33 @@ public void unregister(PlcConsumerRegistration registration) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - private class AlarmsLoop extends Thread { + private class EventLoop extends Thread { private volatile boolean cancelled; private final Channel channel; private boolean alarmquery; private int delay; + private final Map> cyclicServicesSubscriptions; + private final Map cyclicServicesHandles; private final BlockingQueue alarmsqueue; - AlarmsLoop(Channel channel, BlockingQueue alarmsqueue) { + EventLoop(Channel channel, + BlockingQueue alarmsqueue, + Map> cyclicServicesSubscriptions, + Map cyclicServicesHandles) { this.channel = channel; this.alarmsqueue = alarmsqueue; + this.cyclicServicesSubscriptions = cyclicServicesSubscriptions; + this.cyclicServicesHandles = cyclicServicesHandles; this.alarmquery = true; - this.delay = 1; + this.delay = 1000; } @Override public void run() { while (!cancelled) { try { - S7PushMessage msg = alarmsqueue.poll(delay, TimeUnit.SECONDS); + S7PushMessage msg = alarmsqueue.poll(delay, TimeUnit.MILLISECONDS); + if (msg != null){ if (msg instanceof AlarmMessagePayload){ AlarmMessagePayload themsg = (AlarmMessagePayload) msg; @@ -435,6 +484,16 @@ public void run() { } else if (msg instanceof CpuServicesPushParameter) { CpuServicesPushParameter themsg = (CpuServicesPushParameter) msg; logger.info("CpuServicesPushParameter: " + themsg); + } else if (msg instanceof CpuCyclicServicesResponsePayload) { + CpuCyclicServicesResponsePayload themsg = (CpuCyclicServicesResponsePayload) msg; + logger.debug("CpuCyclicServicesResponsePayload: " + themsg + " JobId:" + themsg.getJobId()); + + S7CyclicServicesSubscriptionHandle handle = + (S7CyclicServicesSubscriptionHandle) cyclicServicesHandles.get(themsg.getJobId()); + if (handle != null) { + UpdateCyclicServicesData(handle, themsg); + }; + } else { logger.info("Object type: " + msg.getClass()); } @@ -445,6 +504,9 @@ public void run() { } } + + + } catch (InterruptedException ex) { logger.info(ex.getLocalizedMessage()); } @@ -452,6 +514,41 @@ public void run() { logger.info("Closing the alarm loop."); } + private void UpdateCyclicServicesData(S7CyclicServicesSubscriptionHandle handle,CpuCyclicServicesResponsePayload themsg){ + + Map items = handle.getItems(); + Collection values = items.values(); + List newvalues = themsg.getItems(); + int i = 0; + synchronized(values) { + for (AssociatedValueItem value:values){ + AssociatedValueItem newvalue = newvalues.get(i); + value.getData().setBytes(0, newvalue.getData()); + i++; + } + } + + cyclicServicesSubscriptions.forEach((consumer,handles)->{ + if (handles.contains(handle)){ + handles.forEach((exehandle)->{ + Map> fields = new HashMap<>(); + S7CyclicServicesSubscriptionHandle exe2handle = (S7CyclicServicesSubscriptionHandle) exehandle; + Map values2consumer = exe2handle.getItems(); + + //PlcSubscriptionEvent event = new DefaultPlcSubscriptionEvent(Instant.now(), fields); + + values2consumer.forEach((index, itemvalue)->{ + consumer.accept(null); + //logger.info("Procesando valores : " + index + "\r\n" + ByteBufUtil.prettyHexDump(itemvalue.getData())); + }); + //Pair newPair = new ImmutablePair<>(PlcResponseCode, stringItem); + //exehandle + }); + } + }); + + } + public void cancel() { cancelled = true; } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java index 13e2dd93370..3e55238677c 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java @@ -39,10 +39,8 @@ public class S7Field implements PlcField { private static final Pattern DATA_BLOCK_ADDRESS_PATTERN = Pattern.compile("^%DB(?\\d{1,5}).DB(?[XBWD]?)(?\\d{1,7})(.(?[0-7]))?:(?[a-zA-Z_]+)(\\[(?\\d+)])?"); - //Event Subscription - private static final Pattern EVENT_SUBSCRIPTION_TYPE_PATTERN = - Pattern.compile("MODE SYS USR ALM"); + private static final String DATA_TYPE = "dataType"; private static final String TRANSFER_SIZE_CODE = "transferSizeCode"; private static final String BLOCK_NUMBER = "blockNumber"; @@ -186,6 +184,8 @@ public static S7Field of(String fieldString) { return new S7Field(dataType, memoryArea, (short) 0, byteOffset, bitOffset, numElements); } } + + throw new PlcInvalidFieldException("Unable to parse address: " + fieldString); } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7SubscriptionField.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7SubscriptionField.java new file mode 100644 index 00000000000..07c24d57663 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7SubscriptionField.java @@ -0,0 +1,166 @@ +/* +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.model; + +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; +import org.apache.plc4x.java.api.model.PlcField; +import org.apache.plc4x.java.s7.netty.model.types.AlarmQueryType; +import org.apache.plc4x.java.s7.netty.model.types.SubscribedEventType; +import org.apache.plc4x.java.s7.types.S7SubscriptionFieldType; + +/** + * + * @author cgarcia + */ +public class S7SubscriptionField implements PlcField { + + //Event Subscription + private static final Pattern EVENT_SUBSCRIPTION_TYPE_PATTERN = + Pattern.compile("(^MODE)|(^SYS)|(^USR)|(^ALM)"); + + //Event ack + private static final Pattern EVENT_ALARM_ACK_PATTERN = + Pattern.compile("(^ACK:)(((?:,{0,1})(16#[0-9a-fA-F]{8}))+)"); + + //Query alarms from PLC. + //TODO: Query SCAN + private static final Pattern EVENT_ALARM_QUERY_PATTERN = + Pattern.compile("(^QUERY:)((ALARM_S)|(ALARM_8))"); + + private final S7SubscriptionFieldType fieldtype; + private final SubscribedEventType eventtype; + private final S7Field s7field; + private final ArrayList ackalarms; + private final AlarmQueryType alarmquerytype; + + public S7SubscriptionField(S7SubscriptionFieldType fieldtype, SubscribedEventType eventtype){ + this.fieldtype = fieldtype; + this.eventtype = eventtype; + this.s7field = null; + this.ackalarms = null; + this.alarmquerytype = null; + } + + public S7SubscriptionField(S7SubscriptionFieldType fieldtype, ArrayList ackalarms){ + this.fieldtype = fieldtype; + this.eventtype = null; + this.s7field = null; + this.ackalarms = ackalarms; + this.alarmquerytype = null; + } + + public S7SubscriptionField(S7SubscriptionFieldType fieldtype, AlarmQueryType alarmquerytype){ + this.fieldtype = fieldtype; + this.eventtype = null; + this.s7field = null; + this.ackalarms = null; + this.alarmquerytype = alarmquerytype; + } + + public S7SubscriptionField(S7SubscriptionFieldType fieldtype, S7Field s7field){ + this.fieldtype = fieldtype; + this.eventtype = null; + this.s7field = s7field; + this.ackalarms = null; + this.alarmquerytype = null; + } + + public S7SubscriptionFieldType getFieldtype() { + return fieldtype; + } + + public SubscribedEventType getEventtype() { + return eventtype; + } + + public S7Field getS7field() { + return s7field; + } + + public ArrayList getAckalarms() { + return ackalarms; + } + + public AlarmQueryType getAlarmquerytype() { + return alarmquerytype; + } + + public static boolean matches(String fieldString) { + return EVENT_SUBSCRIPTION_TYPE_PATTERN.matcher(fieldString).matches() || + EVENT_ALARM_ACK_PATTERN.matcher(fieldString).matches() || + EVENT_ALARM_QUERY_PATTERN.matcher(fieldString).matches() || + S7Field.matches(fieldString); + } + + public static S7SubscriptionField of(String fieldString) { + { + Matcher matcher = EVENT_SUBSCRIPTION_TYPE_PATTERN.matcher(fieldString); + if (matcher.matches()){ + return new S7SubscriptionField(S7SubscriptionFieldType.EVENT_SUBSCRIPTION, + SubscribedEventType.valueOf(fieldString)); + } + } + + { + //TODO: Actually only ALARM_S (SIG_1) + Matcher matcher = EVENT_ALARM_ACK_PATTERN.matcher(fieldString); + if (matcher.matches()){ + String EventIds = matcher.group(2); + String[] arrStrEventId = EventIds.split(","); + ArrayList arrEventId = new ArrayList<>(); + for (String EventId:arrStrEventId){ + EventId = EventId.replaceAll("16#", ""); + arrEventId.add(Integer.parseInt(EventId, 16)); + } + return new S7SubscriptionField(S7SubscriptionFieldType.ALARM_ACK, + arrEventId); + + } + } + + { + //TODO: Support for ALARM_8 + Matcher matcher = EVENT_ALARM_QUERY_PATTERN.matcher(fieldString); + if (matcher.matches()){ + return new S7SubscriptionField(S7SubscriptionFieldType.ALARM_QUERY, + AlarmQueryType.ALARM_S); + } + } + + { + if (S7Field.matches(fieldString)){ + S7Field s7field = S7Field.of(fieldString); + switch(s7field.getDataType()) { + case BYTE: + + default:; + + } + return new S7SubscriptionField(S7SubscriptionFieldType.CYCLIC_SUBSCRIPTION, + s7field); + } + } + throw new PlcInvalidFieldException("Unable to parse address: " + fieldString); + } + + +} 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 05f6df97b48..35a426a6e86 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 @@ -20,12 +20,15 @@ Licensed to the Apache Software Foundation (ASF) under one import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import java.io.IOException; import java.lang.reflect.Array; import java.math.BigInteger; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; @@ -34,6 +37,7 @@ Licensed to the Apache Software Foundation (ASF) under one import java.util.concurrent.BlockingQueue; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; +import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.IntStream; import org.apache.commons.lang3.tuple.ImmutablePair; @@ -46,29 +50,41 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.api.messages.PlcUnsubscriptionRequest; import org.apache.plc4x.java.api.messages.PlcWriteRequest; import org.apache.plc4x.java.api.model.PlcField; +import org.apache.plc4x.java.api.model.PlcSubscriptionHandle; import org.apache.plc4x.java.api.types.PlcResponseCode; import org.apache.plc4x.java.base.PlcMessageToMessageCodec; import org.apache.plc4x.java.base.events.ConnectedEvent; import org.apache.plc4x.java.base.messages.*; import org.apache.plc4x.java.base.messages.items.*; +import org.apache.plc4x.java.base.model.SubscriptionPlcField; import org.apache.plc4x.java.s7.model.S7Field; +import org.apache.plc4x.java.s7.model.S7SubscriptionField; import org.apache.plc4x.java.s7.netty.events.S7ConnectedEvent; import org.apache.plc4x.java.s7.netty.model.messages.S7Message; import org.apache.plc4x.java.s7.netty.model.messages.S7PushMessage; import org.apache.plc4x.java.s7.netty.model.messages.S7RequestMessage; import org.apache.plc4x.java.s7.netty.model.messages.S7ResponseMessage; +import org.apache.plc4x.java.s7.netty.model.params.CpuCyclicServicesRequestParameter; import org.apache.plc4x.java.s7.netty.model.params.CpuServicesParameter; import org.apache.plc4x.java.s7.netty.model.params.CpuServicesRequestParameter; +import org.apache.plc4x.java.s7.netty.model.params.CpuServicesResponseParameter; import org.apache.plc4x.java.s7.netty.model.params.S7Parameter; import org.apache.plc4x.java.s7.netty.model.params.VarParameter; import org.apache.plc4x.java.s7.netty.model.params.items.S7AnyVarParameterItem; import org.apache.plc4x.java.s7.netty.model.params.items.VarParameterItem; import org.apache.plc4x.java.s7.netty.model.payloads.AlarmMessagePayload; +import org.apache.plc4x.java.s7.netty.model.payloads.CpuCyclicServicesRequestPayload; +import org.apache.plc4x.java.s7.netty.model.payloads.CpuCyclicServicesResponsePayload; import org.apache.plc4x.java.s7.netty.model.payloads.CpuMessageSubscriptionServicePayload; import org.apache.plc4x.java.s7.netty.model.payloads.S7Payload; import org.apache.plc4x.java.s7.netty.model.payloads.VarPayload; +import org.apache.plc4x.java.s7.netty.model.payloads.items.AlarmMessageItem; +import org.apache.plc4x.java.s7.netty.model.payloads.items.AssociatedValueItem; +import org.apache.plc4x.java.s7.netty.model.payloads.items.MessageObjectItem; +import org.apache.plc4x.java.s7.netty.model.payloads.items.S7AnyVarPayloadItem; import org.apache.plc4x.java.s7.netty.model.payloads.items.VarPayloadItem; import org.apache.plc4x.java.s7.netty.model.types.*; +import org.apache.plc4x.java.s7.protocol.S7CyclicServicesSubscriptionHandle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -171,6 +187,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws E @Override protected void encode(ChannelHandlerContext ctx, PlcRequestContainer msg, List out) throws PlcException { PlcRequest request = msg.getRequest(); + if (request instanceof PlcReadRequest) { encodeReadRequest(msg, out); } else if (request instanceof PlcWriteRequest) { @@ -182,7 +199,48 @@ protected void encode(ChannelHandlerContext ctx, PlcRequestContainer msg, List out) throws PlcException { + //Chequear el campo prueba que ya incluyte la información del tipo + + PlcSubscriptionRequest subsRequest = (PlcSubscriptionRequest) msg.getRequest(); + + if ( subsRequest.getFields().get(0) instanceof S7SubscriptionField){ + + S7SubscriptionField event = (S7SubscriptionField) subsRequest.getFields().get(0); + + switch(event.getFieldtype()){ + case EVENT_SUBSCRIPTION:; + encodeEventSubcriptionRequest(msg, out); + break; + case EVENT_UNSUBSCRIPTION:; + encodeEventUnSubcriptionRequest(msg, out); + break; + case ALARM_ACK:; + encodeAlarmAckRequest(msg, out); + break; + case ALARM_QUERY:; + encodeAlarmQueryRequest(msg, out); + break; + case CYCLIC_SUBSCRIPTION:; + encodeCycledSubscriptionRequest(msg, out); + break; + case CYCLIC_UNSUBSCRIPTION:; + break; + default:; + }; + + }; + } + + //TODO: Suppport for ALARM_8 + private void encodeEventSubcriptionRequest(PlcRequestContainer msg, List out) throws PlcException { byte subsevent = 0; List parameterItems = new LinkedList<>(); List payloadItems = new LinkedList<>(); @@ -190,9 +248,9 @@ private void encodeSubcriptionRequest(PlcRequestContainer msg, List out) PlcSubscriptionRequest subsRequest = (PlcSubscriptionRequest) msg.getRequest(); for (String fieldName : subsRequest.getFieldNames()) { - if ( subsRequest.getField(fieldName) instanceof SubscribedEventType){ - SubscribedEventType event = (SubscribedEventType) subsRequest.getField(fieldName); - subsevent = (byte) (subsevent | event.getCode()); + if ( subsRequest.getField(fieldName) instanceof S7SubscriptionField){ + S7SubscriptionField event = (S7SubscriptionField) subsRequest.getField(fieldName); + subsevent = (byte) (subsevent | event.getEventtype().getCode()); } } @@ -218,8 +276,209 @@ private void encodeSubcriptionRequest(PlcRequestContainer msg, List out) requests.put(s7ReadRequest.getTpduReference(), msg); - out.add(s7ReadRequest); - + out.add(s7ReadRequest); + } + + private void encodeEventUnSubcriptionRequest(PlcRequestContainer msg, List out) throws PlcException { + byte subsevent = 0; + List parameterItems = new LinkedList<>(); + List payloadItems = new LinkedList<>(); + + PlcSubscriptionRequest subsRequest = (PlcSubscriptionRequest) msg.getRequest(); + + for (String fieldName : subsRequest.getFieldNames()) { + if ( subsRequest.getField(fieldName) instanceof S7SubscriptionField){ + S7SubscriptionField event = (S7SubscriptionField) subsRequest.getField(fieldName); + subsevent = (byte) (subsevent | event.getEventtype().getCode()); + } + } + + CpuServicesParameter cpuservice = new CpuServicesRequestParameter(CpuServicesParameterFunctionGroup.CPU_FUNCTIONS, + CpuServicesParameterSubFunctionGroup.MESSAGE_SERVICE, (byte) 0x00); + + parameterItems.add(cpuservice); + + + S7Payload Data = new CpuMessageSubscriptionServicePayload(DataTransportErrorCode.OK, + DataTransportSize.OCTET_STRING, + subsevent, + new String("HmiRtm "), + AlarmType.ALARM_S_INITIATE); + payloadItems.add(Data); + + + S7RequestMessage s7ReadRequest = new S7RequestMessage(MessageType.USER_DATA, + (short) tpduGenerator.getAndIncrement(), + parameterItems, + payloadItems, + msg); + + requests.put(s7ReadRequest.getTpduReference(), msg); + + out.add(s7ReadRequest); + } + + //TODO: Check for ALARM_D and ALARM_8 + private void encodeAlarmAckRequest(PlcRequestContainer msg, List out) throws PlcException { + byte subsevent = 0; + List parameterItems = new LinkedList<>(); + List payloadItems = new LinkedList<>(); + + PlcSubscriptionRequest subsRequest = (PlcSubscriptionRequest) msg.getRequest(); + S7SubscriptionField event = (S7SubscriptionField) subsRequest.getFields().get(0); + + + CpuServicesParameter cpuservice = new CpuServicesRequestParameter(CpuServicesParameterFunctionGroup.CPU_FUNCTIONS, + CpuServicesParameterSubFunctionGroup.ALARM_ACK, (byte) 0x00); + + parameterItems.add(cpuservice); + + + ArrayList items = new ArrayList<>(); + for(Integer eventid:event.getAckalarms()){ + items.add(new MessageObjectItem((byte) 0x12, + (byte) 0x08, + VariableAddressingMode.ALARM_ACK, + (byte) 0x00, + eventid, + (byte) 0x01, + (byte) 0x01)); //ONLY for Alarm_SQ + } + + AlarmMessageItem messageitem = new AlarmMessageItem((byte) 0x09, + (byte) items.size(), + items) ; + + S7Payload Data = new AlarmMessagePayload(DataTransportErrorCode.OK, + DataTransportSize.OCTET_STRING, + (2+items.size()*10), + messageitem); + payloadItems.add(Data); + + + S7RequestMessage s7ReadRequest = new S7RequestMessage(MessageType.USER_DATA, + (short) tpduGenerator.getAndIncrement(), + parameterItems, + payloadItems, + msg); + + requests.put(s7ReadRequest.getTpduReference(), msg); + + out.add(s7ReadRequest); + } + + //TODO: Check for ALARM_D and ALARM_8 + private void encodeAlarmQueryRequest(PlcRequestContainer msg, List out) throws PlcException { + + byte subsevent = 0; + List parameterItems = new LinkedList<>(); + List payloadItems = new LinkedList<>(); + + PlcSubscriptionRequest subsRequest = (PlcSubscriptionRequest) msg.getRequest(); + S7SubscriptionField event = (S7SubscriptionField) subsRequest.getFields().get(0); + + CpuServicesParameter cpuservice = new CpuServicesRequestParameter(CpuServicesParameterFunctionGroup.CPU_FUNCTIONS, + CpuServicesParameterSubFunctionGroup.ALARM_QUERY, (byte) 0x00); + + parameterItems.add(cpuservice); + + ArrayList items = new ArrayList<>(); + + //TODO: Multiple AlarmQueryType from the same request. + items.add(new MessageObjectItem((byte) 0x12, + (byte) 0x08, + VariableAddressingMode.ALARM_QUERYREQ, + QueryType.BYALARMTYPE, + event.getAlarmquerytype())); //ONLY for Alarm_S + + + AlarmMessageItem messageitem = new AlarmMessageItem((byte) 0x00, + (byte) items.size(), + items) ; + + S7Payload Data = new AlarmMessagePayload(DataTransportErrorCode.OK, + DataTransportSize.OCTET_STRING, + (2+items.size()*10), + messageitem); + payloadItems.add(Data); + + + S7RequestMessage s7ReadRequest = new S7RequestMessage(MessageType.USER_DATA, + (short) tpduGenerator.getAndIncrement(), + parameterItems, + payloadItems, + msg); + + requests.put(s7ReadRequest.getTpduReference(), msg); + + out.add(s7ReadRequest); + } + + private void encodeCycledSubscriptionRequest(PlcRequestContainer msg, List out) throws PlcException { + List parameterItems = new LinkedList<>(); + List payloads = new LinkedList<>(); + DefaultPlcSubscriptionRequest prueba = (DefaultPlcSubscriptionRequest) msg.getRequest(); + List fields = prueba.getSubscriptionFields(); + Optional optionalduration = prueba.getSubscriptionFields().get(0).getDuration(); + Duration duration = optionalduration.get(); + + List payloadItems = new LinkedList<>(); + + fields.forEach((action) ->{ + PlcField field = action.getPlcField(); + if (!(field instanceof S7SubscriptionField)) { + logger.info("The field should have been of type S7SubscriptionField"); + return; + } + S7SubscriptionField subsS7Field = (S7SubscriptionField) field; + S7Field s7Field = subsS7Field.getS7field(); + S7AnyVarPayloadItem varPayloadItem = new S7AnyVarPayloadItem( + SpecificationType.VARIABLE_SPECIFICATION, s7Field.getMemoryArea(), + s7Field.getDataType(), + s7Field.getNumElements(), s7Field.getBlockNumber(), s7Field.getByteOffset(), (byte) s7Field.getBitOffset()); + payloadItems.add(varPayloadItem); + }); + + //TODO: Play with Time factor. Actually only 1..9 + CpuCyclicServiceTimeBaseType timeBase = null; + byte timefactor = 0x00; + if (duration.getSeconds() == 0) { + timeBase = CpuCyclicServiceTimeBaseType.TB_100_MS; + timefactor = (byte) (duration.toMillis() / 100); + } else if (duration.getSeconds() <= 9) { + timeBase = CpuCyclicServiceTimeBaseType.TB_1_SEC; + timefactor = (byte) duration.getSeconds(); + } else if (duration.getSeconds() <= 90) { + timeBase = CpuCyclicServiceTimeBaseType.TB_10_SEC; + timefactor = (byte) (duration.getSeconds() / 10); + } + + CpuCyclicServicesRequestPayload payload = new CpuCyclicServicesRequestPayload(DataTransportErrorCode.OK, + DataTransportSize.OCTET_STRING, + (4+payloadItems.size()*12), + payloadItems.size(), + timeBase, + timefactor, + payloadItems); + + payloads.add(payload); + + CpuCyclicServicesRequestParameter parameter = new CpuCyclicServicesRequestParameter(CpuUserDataMethodType.REQUEST, + CpuServicesParameterFunctionGroup.CYCLIC_SERVICES, + CpuCyclicServicesParameterSubFunctionGroupType.CYCLIC_TRANSFER, + (byte) 0x00); + parameterItems.add(parameter); + + + + // Assemble the request. + S7RequestMessage s7ReadRequest = new S7RequestMessage(MessageType.USER_DATA, + (short) tpduGenerator.getAndIncrement(), parameterItems, + payloads, msg); + + requests.put(s7ReadRequest.getTpduReference(), msg); + + out.add(s7ReadRequest); } private void encodeUnsubcriptionRequest(PlcRequestContainer msg, List out) throws PlcException { @@ -227,6 +486,7 @@ private void encodeUnsubcriptionRequest(PlcRequestContainer msg, List ou } private void encodeReadRequest(PlcRequestContainer msg, List out) throws PlcException { + List parameterItems = new LinkedList<>(); PlcReadRequest readRequest = (PlcReadRequest) msg.getRequest(); @@ -491,15 +751,53 @@ protected void decode(ChannelHandlerContext ctx, S7Message msg, List out response = decodeWriteResponse(responseMessage, requestContainer); } else if (request instanceof PlcSubscriptionRequest) { response = decodeSubscriptionResponse(responseMessage, requestContainer); + + if (response == null){ //Fragmented message? Query again! + requests.put(tpduReference, requestContainer); + List parameterItems = new LinkedList<>(); + List payloadItems = new LinkedList<>(); + + AlarmMessagePayload payload = new AlarmMessagePayload(DataTransportErrorCode.NOT_FOUND, + DataTransportSize.NULL, + 0x0000, + null); + payloadItems.add(payload); + + //TODO: Check multiple parameters + CpuServicesParameter cpuservice = new CpuServicesResponseParameter(CpuServicesParameterFunctionGroup.CPU_FUNCTIONS, + CpuServicesParameterSubFunctionGroup.ALARM_QUERY, ((CpuServicesParameter) msg.getParameters().get(0)).getSequenceNumber()); + + parameterItems.add(cpuservice); + + S7RequestMessage s7ReadRequest = new S7RequestMessage(MessageType.USER_DATA, + msg.getTpduReference(), + parameterItems, + payloadItems, + null); + + try { + ChannelFuture future = ctx.writeAndFlush(s7ReadRequest); + future.addListener(new ChannelFutureListener() { + public void operationComplete(ChannelFuture future) { + logger.debug("Request fragment ALARM_QUERY done: " + future.isSuccess()); + } + }); + //out.add(s7ReadRequest); + //ctx.pipeline(). + } catch (Exception ex) { + java.util.logging.Logger.getLogger(Plc4XS7Protocol.class.getName()).log(Level.SEVERE, null, ex); + } + + } } else { - logger.info("There is the client's request, but it is not a valid response...."); + logger.debug("There is the client's request, but it is not a valid response...."); } // Confirm the response being handled. if (response != null) { requestContainer.getResponseFuture().complete(response); } else { - logger.info("The message could not be processed..."); + logger.debug("The message could not be processed..."); } } else { //PUSH Message @@ -513,7 +811,7 @@ protected void decode(ChannelHandlerContext ctx, S7Message msg, List out } List payloads = msg.getPayloads(); - //TODO: Use alarmsqueue.addAll() method + //TODO: Use alarmsqueue.addAll() method using streams for (S7Payload payload:payloads){ if (payload instanceof S7PushMessage){ if (!alarmsqueue.offer((S7PushMessage) payload)){ @@ -523,7 +821,8 @@ protected void decode(ChannelHandlerContext ctx, S7Message msg, List out } } } - // TODO: Check if it is a CPU service response and proceed as applicable. + + // TODO: Check if it is a CPU service response and proceed as applicable. @SuppressWarnings("unchecked") private PlcResponse decodeReadResponse(S7ResponseMessage responseMessage, PlcRequestContainer requestContainer) throws PlcProtocolException { InternalPlcReadRequest plcReadRequest = (InternalPlcReadRequest) requestContainer.getRequest(); @@ -839,16 +1138,83 @@ private PlcResponse decodeWriteResponse(S7ResponseMessage responseMessage, PlcRe return new DefaultPlcWriteResponse(plcWriteRequest, values); } + private PlcResponse decodeSubscriptionResponse(S7ResponseMessage responseMessage, PlcRequestContainer requestContainer) throws PlcProtocolException { - InternalPlcSubscriptionRequest subsRequest = (InternalPlcSubscriptionRequest) requestContainer.getRequest(); + InternalPlcSubscriptionRequest subsRequest = (InternalPlcSubscriptionRequest) requestContainer.getRequest(); + //TODO: Try multiple ALARM_ACK in the same request and multiple EVENT_ID. + S7SubscriptionField event = (S7SubscriptionField) subsRequest.getFields().get(0); + + //TODO: Multiple parameters. Try with S7400. At this point if we have embedded more parameter will be lost. + CpuServicesResponseParameter parameter = (CpuServicesResponseParameter) responseMessage.getParameters().get(0); + List payloads = responseMessage.getPayloads(); + + Map> values = new HashMap<>(); + + //May be only one iteration?: for (S7Payload payload:payloads){ - if(payload instanceof AlarmMessagePayload) { - logger.info("OK. Si pasa el mensaje como un Payload...: " + ((AlarmMessagePayload) payload).getReturnCode()); - //logger.info("Alarm Type...: " + ((AlarmMessagePayload) payload).getMsgtype()); - } + if (payload instanceof AlarmMessagePayload) { + AlarmMessagePayload payloadItem = (AlarmMessagePayload) payload; + switch(parameter.getSubFunctionGroup()){ + case ALARM_ACK:{ + List items = payloadItem.getMsg().getMsgItems(); + ArrayList eventids = event.getAckalarms(); + int index = 0; + for (Object item:items){ + // A ack response contains only the return code for every item. + // Is direct response for the ALARM_ACK, don't pass to + // push message handler. + //subsBuilder2.addEventField("MyAck", "ACK:16#60000001,16#60000002,16#60000003"); + values.put("16#"+Integer.toHexString(eventids.get(index)), new ImmutablePair(decodeResponseCode((DataTransportErrorCode) item),null)); + index++; + } + } + break; + case ALARM_QUERY:{ + if (payloadItem.getMsg() == null) { + return null; + } + + if (payloadItem instanceof S7PushMessage){ + if (payloadItem.getMsg().getMsgItems().size() > 0){ + if (!alarmsqueue.offer((S7PushMessage) payload)){ + logger.info("decodeSubscriptionResponse: Alarm queue buffer is full."); + }; + }; + } else { + logger.debug("Check for ALARM_QUERY not attended: " + payloadItem); + } + } + break; + default:; + } + } else if (payload instanceof CpuCyclicServicesResponsePayload) { + CpuCyclicServicesResponsePayload cyclicPayloadItem = (CpuCyclicServicesResponsePayload) payload; + // + // + logger.info("CpuCyclicServicesResponsePayload: " + subsRequest.getFieldNames().toString()); + List valueitems = cyclicPayloadItem.getItems(); + Map items = new LinkedHashMap(); + int i=0; + if (parameter.getError().getCode() == 0x0000){ + for (String fieldname:subsRequest.getFieldNames()){ + items.put(fieldname, valueitems.get(i)); + i++; + }; + }; + + S7CyclicServicesSubscriptionHandle handler = new S7CyclicServicesSubscriptionHandle("UNO", + parameter.getSequenceNumber(), + parameter.getError().getCode(), + items); + + for (String fieldname:subsRequest.getFieldNames()){ + logger.info("*****" + fieldname); + values.put(fieldname, new ImmutablePair(decodeResponseCode(items.get(fieldname).getReturnCode()), handler)); + } + } } - return new DefaultPlcSubscriptionResponse(subsRequest, null); + return new DefaultPlcSubscriptionResponse(subsRequest, values); } 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 914abe9f912..f3c8ed912ae 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 @@ -33,6 +33,8 @@ Licensed to the Apache Software Foundation (ASF) under one import java.time.temporal.ChronoUnit; import java.util.*; import org.apache.commons.lang3.reflect.FieldUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; import org.apache.plc4x.java.api.exceptions.PlcProtocolException; import org.apache.plc4x.java.api.exceptions.PlcProtocolPayloadTooBigException; import org.apache.plc4x.java.api.exceptions.PlcRuntimeException; @@ -49,6 +51,8 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.netty.model.params.items.S7AnyVarParameterItem; import org.apache.plc4x.java.s7.netty.model.params.items.VarParameterItem; import org.apache.plc4x.java.s7.netty.model.payloads.AlarmMessagePayload; +import org.apache.plc4x.java.s7.netty.model.payloads.CpuCyclicServicesRequestPayload; +import org.apache.plc4x.java.s7.netty.model.payloads.CpuCyclicServicesResponsePayload; import org.apache.plc4x.java.s7.netty.model.payloads.CpuDiagnosticMessagePayload; import org.apache.plc4x.java.s7.netty.model.payloads.CpuMessageSubscriptionServicePayload; import org.apache.plc4x.java.s7.netty.model.payloads.CpuServicesPayload; @@ -58,6 +62,7 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.netty.model.payloads.items.AssociatedValueItem; import org.apache.plc4x.java.s7.netty.model.payloads.items.CpuDiagnosticMessageItem; import org.apache.plc4x.java.s7.netty.model.payloads.items.MessageObjectItem; +import org.apache.plc4x.java.s7.netty.model.payloads.items.S7AnyVarPayloadItem; import org.apache.plc4x.java.s7.netty.model.payloads.items.VarPayloadItem; import org.apache.plc4x.java.s7.netty.model.payloads.ssls.SslDataRecord; import org.apache.plc4x.java.s7.netty.model.payloads.ssls.SslModuleIdentificationDataRecord; @@ -109,6 +114,8 @@ protected void decode(ChannelHandlerContext ctx, Object msg, List out) { // For being able to respect the max AMQ restrictions. private PendingWriteQueue queue; private Map sentButUnacknowledgedTpdus; + + private Map>> fragmentedData; public S7Protocol(short requestedMaxAmqCaller, short requestedMaxAmqCallee, short requestedPduSize, S7ControllerType controllerType, S7MessageProcessor messageProcessor) { @@ -118,6 +125,7 @@ public S7Protocol(short requestedMaxAmqCaller, short requestedMaxAmqCallee, shor this.controllerType = controllerType; this.messageProcessor = messageProcessor; sentButUnacknowledgedTpdus = new HashMap<>(); + fragmentedData = new HashMap<>(); } @Override @@ -225,8 +233,9 @@ private void writeS7Message(Channel channel, PromiseCombiner promiseCombiner, ChannelPromise subPromise = new DefaultChannelPromise(channel); // The tpduRef was 0x01 but had to be changed to 0x00 in order to support Siemens LOGO devices. queue.add(new DataTpdu(true, (byte) 0x00, Collections.emptyList(), buf, message), subPromise); + promiseCombiner.add((Future) subPromise); - logger.debug("S7 Message with id {} queued", message.getTpduReference()); + logger.debug("writeS7Message: S7 Message with id {} queued", message.getTpduReference()); } } @@ -239,11 +248,15 @@ private void encodePayloads(S7Message in, ByteBuf buf) throws PlcProtocolExcepti case WRITE_VAR: encodeWriteVarPayload((VarPayload) payload, buf, !payloadIterator.hasNext()); break; - case CPU_SERVICES: + case CPU_SERVICES: if (payload instanceof CpuServicesPayload) { encodeCpuServicesPayload((CpuServicesPayload) payload, buf); } else if (payload instanceof CpuMessageSubscriptionServicePayload) { encodeCpuMessageSubcriptionPayload((CpuMessageSubscriptionServicePayload) payload, buf); + } else if (payload instanceof AlarmMessagePayload) { + encodeAlarmMessagePayload((AlarmMessagePayload) payload, buf); + } else if (payload instanceof CpuCyclicServicesRequestPayload){ + encodeCpuCyclicSubscriptionPayload((CpuCyclicServicesRequestPayload) payload, buf); } break; default: @@ -268,23 +281,6 @@ private void encodeWriteVarPayload(VarPayload varPayload, ByteBuf buf, boolean l } } - private void encodeCpuMessageSubcriptionPayload(CpuMessageSubscriptionServicePayload cpuServicesPayload, ByteBuf buf) - throws PlcProtocolException { - buf.writeByte(cpuServicesPayload.getReturnCode().getCode()); - buf.writeByte(cpuServicesPayload.getDataTransportSize().getCode()); - if ((cpuServicesPayload.getSubscribedEvents() & 0x80) == 0){ - buf.writeShort(0x000A); - } else { - buf.writeShort(0x000C); - }; - buf.writeByte(cpuServicesPayload.getSubscribedEvents()); - buf.writeByte(0x00); - buf.writeBytes(cpuServicesPayload.getId().getBytes()); - if ((cpuServicesPayload.getSubscribedEvents() & 0x80) == 0x80){ - buf.writeByte(cpuServicesPayload.getAlarm().getCode()); - buf.writeByte(0x00); - } - } private void encodeCpuServicesPayload(CpuServicesPayload cpuServicesPayload, ByteBuf buf) throws PlcProtocolException { @@ -330,8 +326,112 @@ private void encodeCpuServicesPayload(CpuServicesPayload cpuServicesPayload, Byt } }*/ } - } + } + + private void encodeCpuMessageSubcriptionPayload(CpuMessageSubscriptionServicePayload cpuServicesPayload, ByteBuf buf) + throws PlcProtocolException { + buf.writeByte(cpuServicesPayload.getReturnCode().getCode()); + buf.writeByte(cpuServicesPayload.getDataTransportSize().getCode()); + if ((cpuServicesPayload.getSubscribedEvents() & 0x80) == 0){ + buf.writeShort(0x000A); + } else { + buf.writeShort(0x000C); + }; + buf.writeByte(cpuServicesPayload.getSubscribedEvents()); + buf.writeByte(0x00); + buf.writeBytes(cpuServicesPayload.getId().getBytes()); + if ((cpuServicesPayload.getSubscribedEvents() & 0x80) == 0x80){ + buf.writeByte(cpuServicesPayload.getAlarm().getCode()); + buf.writeByte(0x00); + } + } + + //TODO: Agregar ALARM_ACK + private void encodeAlarmMessagePayload(AlarmMessagePayload payload, ByteBuf buf) { + + AlarmMessageItem alarmitem = payload.getMsg(); + + buf.writeByte(payload.getReturnCode().getCode()); + buf.writeByte(payload.getDataTransportSize().getCode()); + buf.writeShort(payload.getLength()); + + //Response for fragmented PLC response + //Check Plc4XS7Protocol. decode method + if (alarmitem == null) { return; }; + List items = alarmitem.getMsgItems(); + + buf.writeByte(alarmitem.getFunction()); + buf.writeByte(alarmitem.getObjects()); + + for(Object thisitem:items){ + MessageObjectItem item = (MessageObjectItem) thisitem; + switch (item.getSyntaxID()) { + case S7ANY:; + logger.debug("encodeAlarmMessagePayload: S7ANY no supportesd"); + break; + case PBC_R_ID:; + logger.debug("encodeAlarmMessagePayload: PBC_R_ID no supportesd"); + break; + case ALARM_LOCKFREE:; + logger.debug("encodeAlarmMessagePayload: ALARM_LOCKFREE no supportesd"); + break; + case ALARM_IND:; + logger.debug("encodeAlarmMessagePayload: ALARM_IND no supportesd"); + break; + case ALARM_ACK:{ + logger.debug("encodeAlarmMessagePayload: ALARM_ACK"); + buf.writeByte(item.getVariableSpecification()); + buf.writeByte(item.getLength()); + buf.writeByte(item.getSyntaxID().getCode()); + buf.writeByte(item.getNumberOfValues()); + buf.writeInt(item.getEventID()); + buf.writeByte(item.getAckStateGoing()); + buf.writeByte(item.getAckStateComming()); + }; + break; + case ALARM_QUERYREQ:{ + logger.debug("encodeAlarmMessagePayload: ALARM_QUERYREQ"); + buf.writeByte(item.getVariableSpecification()); + buf.writeByte(item.getLength()); + buf.writeByte(item.getSyntaxID().getCode()); + buf.writeByte(0x00); //Unknown/Reserved + buf.writeByte(item.getQuerytype().getCode()); + buf.writeByte(0x34); //Unknown/Reserved + buf.writeInt(item.getAlarmtype().getCode()); + }; + break; + case NOTIFY_IND:; + logger.debug("encodeAlarmMessagePayload: NOTIFY_IND no supportesd"); + break; + case NIC:; + logger.debug("encodeAlarmMessagePayload: NIC no supportesd"); + break; + case DRIVEESANY:; + logger.debug("encodeAlarmMessagePayload: DRIVEESANY no supportesd"); + break; + case DBREAD:; + logger.debug("encodeAlarmMessagePayload: DBREAD no supportesd"); + break; + case SYM1200:; + logger.debug("encodeAlarmMessagePayload: SYM1200 no supportesd"); + break; + default:; + } + } + } + private void encodeCpuCyclicSubscriptionPayload(CpuCyclicServicesRequestPayload payload, ByteBuf buf) { + buf.writeByte(payload.getReturnCode().getCode()); + buf.writeByte(payload.getDataTransportSize().getCode()); + buf.writeShort(payload.getLength()); + buf.writeShort(payload.getItemCount()); + buf.writeByte(payload.getTimeBase().getCode()); + buf.writeByte(payload.getTimeFactor()); + payload.getItems().forEach((anyvar)->{ + encodeS7AnyPayloadItem(anyvar,buf); + }); + } + private void encodeParameters(S7Message in, ByteBuf buf) throws PlcProtocolException { for (S7Parameter s7Parameter : in.getParameters()) { buf.writeByte(s7Parameter.getType().getCode()); @@ -377,7 +477,7 @@ private void encodeParameterSetupCommunication(ByteBuf buf, SetupCommunicationPa buf.writeByte((byte) 0x00); buf.writeShort(s7Parameter.getMaxAmqCaller()); buf.writeShort(s7Parameter.getMaxAmqCallee()); - buf.writeShort(s7Parameter.getPduLength()); + buf.writeShort(s7Parameter.getPduLength()); } private void encodeParameterReadWriteVar(ByteBuf buf, VarParameter s7Parameter) throws PlcProtocolException { @@ -400,15 +500,26 @@ private void encodeCpuServicesParameter(ByteBuf buf, CpuServicesParameter parame buf.writeByte(0x01); buf.writeByte(0x12); // Length of the parameter. + buf.writeByte((parameter instanceof CpuServicesRequestParameter) ? 0x04 : 0x08); // Is this a request or a response? buf.writeByte((parameter instanceof CpuServicesRequestParameter) ? 0x11 : 0x12); // This is a mixture of request/response and function group . byte nextByte = (byte) (((parameter instanceof CpuServicesRequestParameter) ? (byte) 0x40 : (byte) 0x80) | parameter.getFunctionGroup().getCode()); - //TODO for ALARM_QUERY bypass the next byte + + //For fragmented response + if ((parameter instanceof CpuServicesResponseParameter) && + (parameter.getSequenceNumber() != 0)){ + nextByte = (byte) (0x40 + parameter.getFunctionGroup().getCode()); + } + buf.writeByte(nextByte); - buf.writeByte(parameter.getSubFunctionGroup().getCode()); + if (parameter instanceof CpuCyclicServicesRequestParameter) { + buf.writeByte(((CpuCyclicServicesRequestParameter) parameter).getCyclicSubFunction().getCode()); + } else { + buf.writeByte(parameter.getSubFunctionGroup().getCode()); + } buf.writeByte(parameter.getSequenceNumber()); // A response parameter has some more fields. @@ -419,8 +530,17 @@ private void encodeCpuServicesParameter(ByteBuf buf, CpuServicesParameter parame buf.writeByte(responseParameter.isLastDataUnit() ? 0x00 : 0x01); buf.writeShort(responseParameter.getError().getCode()); }*/ + //R: if parameter.getSequenceNumber() == 2 then is fragment message query + // from Plc4XS7Protocol decode method. + if (parameter.getSequenceNumber() != 0x00) { + buf.writeByte(0x00); //DataUnitReferenceNumber + buf.writeByte(0x00); //LastDataUnit + buf.writeShort(0x0000); //Error code + } + } + //TODO: Refactor S7AnyVarParameterItem to S7AnyVarItem private void encodeS7AnyParameterItem(ByteBuf buf, S7AnyVarParameterItem s7AnyRequestItem) { buf.writeByte(s7AnyRequestItem.getSpecificationType().getCode()); // Length of this item (excluding spec type and length) @@ -441,11 +561,34 @@ private void encodeS7AnyParameterItem(ByteBuf buf, S7AnyVarParameterItem s7AnyRe (s7AnyRequestItem.getByteOffset() & 0x1F) << 3) | (s7AnyRequestItem.getBitOffset() & 0x07))); } + + //TODO: Refactor S7AnyVarPayloadItem to S7AnyVarItem + private void encodeS7AnyPayloadItem(S7AnyVarPayloadItem s7AnyRequestItem, ByteBuf buf) { + buf.writeByte(s7AnyRequestItem.getSpecificationType().getCode()); + // Length of this item (excluding spec type and length) + buf.writeByte((byte) 0x0a); + buf.writeByte(s7AnyRequestItem.getAddressingMode().getCode()); + buf.writeByte(s7AnyRequestItem.getDataType().getTypeCode()); + buf.writeShort(encodeNumElements(s7AnyRequestItem)); + buf.writeShort(s7AnyRequestItem.getDataBlockNumber()); + buf.writeByte(s7AnyRequestItem.getMemoryArea().getCode()); + // A S7 address is 3 bytes long. Unfortunately the byte-offset is NOT located in + // byte 1 and byte 2 and the bit offset in byte 3. Siemens used the last 3 bits of + // byte 3 for the bit-offset and the remaining 5 bits of byte 3 to contain the lowest + // 5 bits of the byte-offset. The highest 5 bits of byte 1 are probably left unused + // for future extensions. + buf.writeShort((short) (s7AnyRequestItem.getByteOffset() >> 5)); + buf.writeByte((byte) (( + (s7AnyRequestItem.getByteOffset() & 0x1F) << 3) + | (s7AnyRequestItem.getBitOffset() & 0x07))); + } + /** * this is a workaround for the date and time types, as native requests with the datatypes are * @return */ + //TODO: Refactor S7AnyVarParameterItem to S7AnyVarItem private short encodeNumElements(S7AnyVarParameterItem s7AnyVarParameterItem){ switch (s7AnyVarParameterItem.getDataType()){ case DATE_AND_TIME: @@ -456,7 +599,24 @@ private short encodeNumElements(S7AnyVarParameterItem s7AnyVarParameterItem){ return (short) s7AnyVarParameterItem.getNumElements(); } - } + } + + /** + * this is a workaround for the date and time types, as native requests with the datatypes are + * @return + */ + //TODO: Refactor S7AnyVarPayloadItem to S7AnyVarItem + private short encodeNumElements(S7AnyVarPayloadItem s7AnyVarParameterItem){ + switch (s7AnyVarParameterItem.getDataType()){ + case DATE_AND_TIME: + case TIME_OF_DAY: + case DATE: + return (short) (s7AnyVarParameterItem.getNumElements()*s7AnyVarParameterItem.getDataType().getSizeInBytes()); + default: + return (short) s7AnyVarParameterItem.getNumElements(); + } + + } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Decoding @@ -486,6 +646,8 @@ protected void decode(ChannelHandlerContext ctx, IsoTPMessage in, List o } MessageType messageType = MessageType.valueOf(userData.readByte()); + //Some response maybe USER_DATA + //Header: Userdata. Parameter:(Response)->(CPU functions)->(ALARM ack) boolean isResponse = messageType == MessageType.ACK_DATA; userData.readShort(); // Reserved (is always constant 0x0000) short tpduReference = userData.readShort(); @@ -510,11 +672,20 @@ protected void decode(ChannelHandlerContext ctx, IsoTPMessage in, List o } i += S7SizeHelper.getParameterLength(parameter); } - //TODO: Se pierden dos bytes de la Data List s7Payloads = decodePayloads(userData, isResponse, userDataLength, s7Parameters); logger.debug("S7 Message with id {} received", tpduReference); + + //Case: USER_DATA + if (messageType == MessageType.USER_DATA){ + if (s7Parameters.get(0) instanceof CpuServicesResponseParameter){ + CpuServicesResponseParameter parameter = (CpuServicesResponseParameter) s7Parameters.get(0); + if (parameter.getSubFunctionGroup() == CpuServicesParameterSubFunctionGroup.ALARM_ACK){ + isResponse = true; + } + } + }; if (isResponse) { S7ResponseMessage responseMessage = new S7ResponseMessage( @@ -522,6 +693,7 @@ protected void decode(ChannelHandlerContext ctx, IsoTPMessage in, List o // Remove the current response from the list of unconfirmed messages. DataTpdu requestTpdu = sentButUnacknowledgedTpdus.remove(tpduReference); + logger.debug("decode: S7 Message with id {} remove", tpduReference); // Get the corresponding request message. S7RequestMessage requestMessage = (requestTpdu != null) ? (S7RequestMessage) requestTpdu.getParent() : null; @@ -567,13 +739,17 @@ protected void decode(ChannelHandlerContext ctx, IsoTPMessage in, List o if(s7Parameter instanceof CpuServicesResponseParameter) { for (S7Payload s7Payload : s7Payloads) { - if(s7Payload instanceof CpuServicesPayload) { + if((s7Payload instanceof CpuServicesPayload)) { CpuServicesPayload cpuServicesPayload = (CpuServicesPayload) s7Payload; // Remove the current response from the list of unconfirmed messages. - sentButUnacknowledgedTpdus.remove(tpduReference); - + logger.debug("CpuServicesPayload: S7 Message with id {} remove", tpduReference); + handleIdentifyRemote(ctx, cpuServicesPayload); + + } else { + sentButUnacknowledgedTpdus.remove(tpduReference); + logger.debug("CpuCyclicServicesResponsePayload: S7 Message with id {} remove", tpduReference); } } } else if (s7Parameter instanceof CpuServicesPushParameter){ @@ -707,57 +883,78 @@ else if ((readWriteVarParameter.getType() == ParameterType.READ_VAR) && isRespon private S7Payload decodeCpuServicesPayload(CpuServicesParameter parameter, ByteBuf userData) { - switch(parameter.getSubFunctionGroup()){ - case READ_SSL: { - CpuServicesPayload payload = decodeReadSslPayload(parameter, userData); - return payload; - } - case MESSAGE_SERVICE:{ - AlarmMessagePayload payload = decodeMessageServicePayload(parameter, userData); - return payload; - } - case DIAG_MESSAGE:{ - CpuDiagnosticMessagePayload payload = decodeCpuDiagnosticMessagePayload(parameter, userData); - return payload; - } - case ALARM8:; - break; - case NOTIFY:; - break; - case ALARM8_LOCK:; - break; - case ALARM8_UNLOCK:; - break; - case SCAN:; - break; - case ALARM_ACK:{ - AlarmMessagePayload payload = decodeMessageServiceAckPayload(parameter, userData); - return payload; - } - case ALARM_ACK_IND:; - break; - case ALARM8_LOCK_IND:; - break; - case ALARM8_UNLOCK_IND:; - break; - case ALARM_SQ_IND:{ - AlarmMessagePayload payload = decodeMessageServicePushPayload(parameter, userData); - return payload; - } - case ALARM_S_IND: { - AlarmMessagePayload payload = decodeMessageServicePushPayload(parameter, userData); - return payload; - } - case ALARM_QUERY:{ - AlarmMessagePayload payload = decodeMessageServiceQueryPayload(parameter, userData); - return payload; + if (parameter.getFunctionGroup() == CpuServicesParameterFunctionGroup.CPU_FUNCTIONS) { + switch(parameter.getSubFunctionGroup()){ + case READ_SSL: { + CpuServicesPayload payload = decodeReadSslPayload(parameter, userData); + return payload; + } + case MESSAGE_SERVICE:{ + AlarmMessagePayload payload = decodeMessageServicePayload(parameter, userData); + return payload; + } + case DIAG_MESSAGE:{ + CpuDiagnosticMessagePayload payload = decodeCpuDiagnosticMessagePayload(parameter, userData); + return payload; + } + case ALARM8:; + break; + case NOTIFY:; + break; + case ALARM8_LOCK:; + break; + case ALARM8_UNLOCK:; + break; + case SCAN:; + break; + case ALARM_ACK:{ + AlarmMessagePayload payload = decodeMessageServiceAckPayload(parameter, userData); + return payload; + } + case ALARM_ACK_IND:{ + AlarmMessagePayload payload = decodeMessageServicePushPayload(parameter, userData); + return payload; + } + case ALARM8_LOCK_IND:; + break; + case ALARM8_UNLOCK_IND:; + break; + case ALARM_SQ_IND:{ + AlarmMessagePayload payload = decodeMessageServicePushPayload(parameter, userData); + return payload; + } + case ALARM_S_IND: { + AlarmMessagePayload payload = decodeMessageServicePushPayload(parameter, userData); + return payload; + } + case ALARM_QUERY:{ + AlarmMessagePayload payload = decodeMessageServiceQueryPayload(parameter, userData); + return payload; + } + case NOTIFY8:; + break; + default:; + break; + } + + } else if (parameter.getFunctionGroup() == CpuServicesParameterFunctionGroup.CYCLIC_SERVICES) { + if (parameter instanceof CpuCyclicServicesResponseParameter){ + CpuCyclicServicesResponseParameter pushparameter = (CpuCyclicServicesResponseParameter) parameter; + switch(pushparameter.getSubCycFunctionGroup()){ + case CYCLIC_CHANGE:; + break; + case CYCLIC_CHANGE_MODIFY:; + break; + case CYCLIC_RDREC:; + break; + case CYCLIC_TRANSFER: + CpuCyclicServicesResponsePayload payload = decodeCyclicServiceResponsePayload(pushparameter, userData); + return payload; + case CYCLIC_UNSUBSCRIBE:; + break; + } } - case NOTIFY8:; - break; - default:; - break; } - return null; } @@ -799,7 +996,7 @@ private S7Parameter decodeParameter(ByteBuf in, boolean isResponse) { } private CpuServicesParameter decodeCpuServicesParameter(ByteBuf in) { - + //logger.info("decodeParameter... \r\n" + ByteBufUtil.prettyHexDump(in)); if(in.readShort() != 0x0112) { if (logger.isErrorEnabled()) { logger.error("Expecting 0x0112 for CPU_SERVICES parameter"); @@ -815,6 +1012,7 @@ private CpuServicesParameter decodeCpuServicesParameter(ByteBuf in) { return null; } // Skipping this as it sort of contains redundant information. + // TODO: We need check the next byte for push message (Request/Response) in.readByte(); byte typeAndFunctionGroup = in.readByte(); // If bit 7 is set, it's a request (if bit 8 is set it's a response). @@ -823,17 +1021,33 @@ private CpuServicesParameter decodeCpuServicesParameter(ByteBuf in) { boolean pushParameter = (typeAndFunctionGroup & 0xF0) == 0; boolean requestParameter = (typeAndFunctionGroup & 0x40) != 0; boolean responseParameter = (typeAndFunctionGroup & 0x80) != 0; + // The last 4 bits contain the function group value. typeAndFunctionGroup = (byte) (typeAndFunctionGroup & 0x0F); + CpuServicesParameterFunctionGroup functionGroup = CpuServicesParameterFunctionGroup.valueOf(typeAndFunctionGroup); + CpuServicesParameterSubFunctionGroup subFunctionGroup = CpuServicesParameterSubFunctionGroup.valueOf(in.readByte()); + byte sequenceNumber = in.readByte(); - if(pushParameter) { - return new CpuServicesPushParameter(functionGroup, subFunctionGroup, sequenceNumber); + + if(pushParameter || (responseParameter && functionGroup == CpuServicesParameterFunctionGroup.CYCLIC_SERVICES)) { + if (functionGroup == CpuServicesParameterFunctionGroup.CYCLIC_SERVICES ) { + CpuCyclicServicesParameterSubFunctionGroupType subCycFunctionGroup = + CpuCyclicServicesParameterSubFunctionGroupType.valueOf(subFunctionGroup.getCode()); + byte dataUnitReferenceNumber = in.readByte(); + boolean lastDataUnit = in.readByte() == 0x00; + ParameterError error = ParameterError.valueOf(in.readShort()); + + return new CpuCyclicServicesResponseParameter(functionGroup, subCycFunctionGroup, sequenceNumber, + dataUnitReferenceNumber, lastDataUnit, error); + } else { + return new CpuServicesPushParameter(functionGroup, subFunctionGroup, sequenceNumber); + } } else if (requestParameter) { - return new CpuServicesRequestParameter(functionGroup, subFunctionGroup, sequenceNumber); + return new CpuServicesRequestParameter(functionGroup, subFunctionGroup, sequenceNumber); } else { byte dataUnitReferenceNumber = in.readByte(); boolean lastDataUnit = in.readByte() == 0x00; @@ -866,8 +1080,7 @@ private CpuDiagnosticPushParameter decodePushModeTransitionParameter(ByteBuf in) CpuCurrentModeType cpumode = CpuCurrentModeType.valueOf(in.readByte()); byte sequencenumber = in.readByte(); return new CpuDiagnosticPushParameter(usermethodtype, userparamtype, userfunction, cpumode, sequencenumber); - } - + } private List decodeReadWriteVarParameter(ByteBuf in, byte numItems) { List items = new LinkedList<>(); @@ -1006,7 +1219,7 @@ private CpuDiagnosticMessagePayload decodeCpuDiagnosticMessagePayload(CpuService private AlarmMessagePayload decodeMessageServicePushPayload(CpuServicesParameter parameter, ByteBuf userData){ - List MessageObjects = new LinkedList<>(); + List MessageObjects = new LinkedList<>(); List values = new LinkedList<>(); int length; //Alarm message @@ -1032,11 +1245,18 @@ private AlarmMessagePayload decodeMessageServicePushPayload(CpuServicesParameter VariableAddressingMode SyntaxID = VariableAddressingMode.valueOf(userData.readByte()); byte NumberOfValues = userData.readByte(); int EventID = userData.readInt(); - byte EventState = userData.readByte(); - byte State = userData.readByte(); + + byte EventState = 0x00; + byte State = 0x00; + if (parameter.getSubFunctionGroup() != CpuServicesParameterSubFunctionGroup.ALARM_ACK_IND) { + EventState = userData.readByte(); + State = userData.readByte(); + } + byte AckStateGoing = userData.readByte(); byte AckStateComming = userData.readByte(); + //TODO: If NumberOfValues == 0 then AssociatedValues is null List AssociatedValues = new LinkedList<>(); for (int j = 0; j < NumberOfValues; j++){ @@ -1067,106 +1287,177 @@ private AlarmMessagePayload decodeMessageServicePushPayload(CpuServicesParameter AckStateComming, AssociatedValues)); - } - - return new AlarmMessagePayload(returnCode, - dataTransportSize, - parameter.getSubFunctionGroup(), - length, - new AlarmMessageItem(timestamp, - FunctionID, - NumberOfMessgaeObjects, - MessageObjects)); - + } } - - return null; + return new AlarmMessagePayload(returnCode, + dataTransportSize, + parameter.getSubFunctionGroup(), + length, + new AlarmMessageItem(timestamp, + FunctionID, + NumberOfMessgaeObjects, + MessageObjects)); }; private AlarmMessagePayload decodeMessageServiceQueryPayload(CpuServicesParameter parameter, ByteBuf userData){ - List MessageObjects = new LinkedList<>(); + + List MessageObjects = new LinkedList<>(); + CpuServicesResponseParameter thisparameter = null; int length; byte FunctionID; byte NumberOfMessageObjects; //Say 1, but I have 2 messages? Why? DataTransportErrorCode AlarmReturnCode; DataTransportSize AlarmTransportSize; int CompleteDataLength; + short dataUnitReferenceNumber = 0x0000; + boolean lastdataunit = true; //Data section DataTransportErrorCode returnCode = DataTransportErrorCode.valueOf(userData.readByte()); DataTransportSize dataTransportSize = DataTransportSize.valueOf(userData.readByte()); length = userData.readShort(); //Number of message objects? - //Alarm message information - FunctionID = userData.readByte(); - NumberOfMessageObjects = userData.readByte(); - AlarmReturnCode = DataTransportErrorCode.valueOf(userData.readByte()); - AlarmTransportSize = DataTransportSize.valueOf(userData.readByte()); - CompleteDataLength = userData.readShort(); + if (parameter instanceof CpuServicesResponseParameter){ + thisparameter = (CpuServicesResponseParameter) parameter; + dataUnitReferenceNumber = (short) thisparameter.getDataUnitReferenceNumber(); + lastdataunit = thisparameter.isLastDataUnit(); + } - //Message Object - for (int i = 0; i < NumberOfMessageObjects; i++){ - byte LengthOfDataSet = userData.readByte(); - int Unknown_1 = userData.readShort(); - Object AlarmType = CpuServicesParameterSubFunctionGroup.valueOf(userData.readByte()); - int EnentID = userData.readShort(); - int Unknown_2 = userData.readShort(); - byte EventState = userData.readByte(); - byte AckStateGoing = userData.readByte(); - byte AckStateComing = userData.readByte(); - LocalDateTime timestampComing; - - timestampComing = readDateAndTime(userData); - - List ComingValues = new LinkedList<>(); - - int NumberOfValues = 1; + //Fragmente code + //The next Level query again. + + if ((length > 2) && (!lastdataunit)){ - for (int j = 0; j < NumberOfValues; j++){ - DataTransportErrorCode valueCode = DataTransportErrorCode.valueOf(userData.readByte()); - DataTransportSize valueTransportSize = DataTransportSize.valueOf(userData.readByte()); - int valueLength = userData.readInt(); - ByteBuf Data = userData.readBytes(valueLength); - ComingValues.add(new AssociatedValueItem(valueCode, - valueTransportSize, - valueLength, - Data)); + //Is alway a CpuServicesResponseParameter instance? + //CpuServicesResponseParameter thisparameter = (CpuServicesResponseParameter) parameter; + Pair> fragments = fragmentedData.get(dataUnitReferenceNumber); + if (fragments != null) { + Queue bytebufqueue = fragments.getValue(); + bytebufqueue.add(userData); + } else { + Queue bytebufqueue = new ArrayDeque(); + bytebufqueue.add(userData); + Pair> firtsfragment = new ImmutablePair(LocalDateTime.now(), bytebufqueue); + fragmentedData.put(dataUnitReferenceNumber, firtsfragment); } - - LocalDateTime timestampGoing; - - timestampGoing = readDateAndTime(userData); - - List GoingValues = new LinkedList<>(); - for (int j = 0; j < NumberOfValues; j++){ - DataTransportErrorCode valueCode = DataTransportErrorCode.valueOf(userData.readByte()); - DataTransportSize valueTransportSize = DataTransportSize.valueOf(userData.readByte()); - int valueLength = userData.readInt(); - ByteBuf Data = userData.readBytes(valueLength); - GoingValues.add(new AssociatedValueItem(valueCode, - valueTransportSize, - valueLength, - Data)); - } - return new AlarmMessagePayload(returnCode, dataTransportSize, CpuServicesParameterSubFunctionGroup.ALARM_QUERY, length, - new AlarmMessageItem(FunctionID, - NumberOfMessageObjects, - AlarmReturnCode, - AlarmTransportSize, - CompleteDataLength, - MessageObjects)); + null); + } + + //Reemsable the fragments + if (dataUnitReferenceNumber != 0x0000){ + Pair> fragments = fragmentedData.get(dataUnitReferenceNumber); + if (fragments != null){ + Queue bytebufqueue = fragments.getValue(); + ByteBuf payload = bytebufqueue.remove(); + for(ByteBuf nextpayload:bytebufqueue){ + if (nextpayload != null) { + payload.writeBytes(nextpayload); + nextpayload.release(); + }; + } + payload.writeBytes(userData); + userData.clear(); + userData.writeBytes(payload); + payload.release(); + fragmentedData.remove(dataUnitReferenceNumber); + } } - return null; + + //Alarm message information + FunctionID = userData.readByte(); + NumberOfMessageObjects = userData.readByte(); + AlarmReturnCode = DataTransportErrorCode.valueOf(userData.readByte()); + AlarmTransportSize = DataTransportSize.valueOf(userData.readByte()); + CompleteDataLength = userData.readShort(); + + //Message Object + if (AlarmReturnCode == DataTransportErrorCode.OK){ + ///length = 1+2+1+4+2+1+1+1+8+1+1+2+8+1+1+2 = 35 + while (userData.isReadable(35)){ + byte LengthOfDataSet = userData.readByte(); + int Unknown = userData.readShort(); + AlarmQueryType AlarmType = AlarmQueryType.valueOf(userData.readByte()); + int EnentID = userData.readInt(); + Unknown = userData.readByte(); + byte EventState = userData.readByte(); + byte AckStateGoing = userData.readByte(); + byte AckStateComing = userData.readByte(); + + LocalDateTime timestampComing = null; + LocalDateTime timestampGoing = null; + + List ComingValues = new LinkedList<>(); + List GoingValues = new LinkedList<>(); + + switch(AlarmType){ + case ALARM_S:{ + //Coming data + timestampComing = readDateAndTime(userData); + DataTransportErrorCode valueCode = DataTransportErrorCode.valueOf(userData.readByte()); + DataTransportSize valueTransportSize = DataTransportSize.valueOf(userData.readByte()); + + int valueLength = userData.readShort() / 8; + + ByteBuf Data = userData.readBytes(valueLength); + ComingValues.add(new AssociatedValueItem(valueCode, + valueTransportSize, + valueLength, + Data)); + //Going data + timestampGoing = readDateAndTime(userData); + + valueCode = DataTransportErrorCode.valueOf(userData.readByte()); + valueTransportSize = DataTransportSize.valueOf(userData.readByte()); + + valueLength = userData.readShort() / 8;; + + Data = userData.readBytes(valueLength); + GoingValues.add(new AssociatedValueItem(valueCode, + valueTransportSize, + valueLength, + Data)); + } + break; + case ALARM_8: { + //TODO: Decode values for ALARM_8 + } + break; + default:; + } + MessageObjects.add(new MessageObjectItem(LengthOfDataSet, + AlarmType, + EnentID, + EventState, + AckStateGoing, + AckStateComing, + timestampComing, + ComingValues, + timestampGoing, + GoingValues)); + } + } + + return new AlarmMessagePayload(returnCode, + dataTransportSize, + CpuServicesParameterSubFunctionGroup.ALARM_QUERY, + length, + new AlarmMessageItem(FunctionID, + NumberOfMessageObjects, + AlarmReturnCode, + AlarmTransportSize, + CompleteDataLength, + MessageObjects)); + } private AlarmMessagePayload decodeMessageServiceAckPayload(CpuServicesParameter parameter, ByteBuf userData){ - List MessageObjects = new LinkedList<>(); + List MessageObjects = new LinkedList<>(); //Data section DataTransportErrorCode returnCode = DataTransportErrorCode.valueOf(userData.readByte()); DataTransportSize dataTransportSize = DataTransportSize.valueOf(userData.readByte()); @@ -1177,9 +1468,9 @@ private AlarmMessagePayload decodeMessageServiceAckPayload(CpuServicesParameter byte NumberOfMessageObjects = userData.readByte(); //In the next leve if is != null -> Success - if (userData.readByte() != 0xff) { - MessageObjects = null; - } + for(int i=0; i< NumberOfMessageObjects; i++) { + MessageObjects.add(DataTransportErrorCode.valueOf(userData.readByte())); + }; return new AlarmMessagePayload(returnCode, dataTransportSize, @@ -1187,43 +1478,93 @@ private AlarmMessagePayload decodeMessageServiceAckPayload(CpuServicesParameter length, new AlarmMessageItem(FunctionID, NumberOfMessageObjects, - null, - null, - 0, MessageObjects)); } + + private CpuCyclicServicesResponsePayload decodeCyclicServiceResponsePayload(CpuCyclicServicesResponseParameter parameter, ByteBuf userData){ + logger.info("decodeCyclicServiceResponsePayload :\r\n" + ByteBufUtil.prettyHexDump(userData)); + DataTransportErrorCode AlarmReturnCode; + DataTransportSize AlarmTransportSize; + int length; + int itemcount; + + //Data section + DataTransportErrorCode returnCode = DataTransportErrorCode.valueOf(userData.readByte()); + DataTransportSize dataTransportSize = DataTransportSize.valueOf(userData.readByte()); + length = userData.readShort(); //Number of bytes + userData.readByte(); //TODO: Sometimes is 0x00 another 0x01, Blinking when I have TIA running + itemcount = (length==0?0x0000:userData.readByte()); + List Values = new LinkedList<>(); + try { + for (int i=0; i < itemcount; i++ ){ + DataTransportErrorCode valueCode = DataTransportErrorCode.valueOf(userData.readByte()); + DataTransportSize valueTransportSize = DataTransportSize.valueOf(userData.readByte()); + + int valueLength = userData.readShort() / 8; + if ((valueLength % 2 != 0) && (userData.isReadable(valueLength+1))) { + + userData.readByte(); //Fill byte for odd number of bytes + } + + ByteBuf Data = userData.readBytes(valueLength); + + Values.add(new AssociatedValueItem(valueCode, + valueTransportSize, + valueLength, + Data)); + } + } catch (Exception e) { + logger.info(e.getMessage()); + return null; + } + + return new CpuCyclicServicesResponsePayload( + returnCode, + dataTransportSize, + parameter.getSequenceNumber(), + length, + itemcount, + Values); + + + } + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Helpers //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// private synchronized void trySendingMessages(ChannelHandlerContext ctx) { - while(sentButUnacknowledgedTpdus.size() < maxAmqCaller) { + //logger.info("trySendingMessages {} < {}",sentButUnacknowledgedTpdus.size(),maxAmqCaller); + while(sentButUnacknowledgedTpdus.size() <= maxAmqCaller) { // Get the TPDU that is up next in the queue. DataTpdu curTpdu = (DataTpdu) queue.current(); if (curTpdu != null) { // Send the TPDU. try { + //logger.info("trySendingMessages: Trata de enviar todos los mensajes..."); ChannelFuture channelFuture = queue.removeAndWrite(); ctx.flush(); if (channelFuture == null) { break; } } catch (Exception e) { - logger.error("Error sending more queues messages", e); + logger.debug("trySendingMessages: Error sending more queues messages", e); ctx.fireExceptionCaught(e); } if(curTpdu.getParent() != null) { + //logger.info("Tiene un pariente..."); // Add it to the list of sentButUnacknowledgedTpdus. // (It seems that the S7 drops the value of the COTP reference id, so we have to use the S7 one) S7RequestMessage s7RequestMessage = (S7RequestMessage) curTpdu.getParent(); + sentButUnacknowledgedTpdus.put(s7RequestMessage.getTpduReference(), curTpdu); - logger.debug("S7 Message with id {} sent", s7RequestMessage.getTpduReference()); + logger.debug("trySendingMessages: S7 Message with id {} sent", s7RequestMessage.getTpduReference()); } // TODO: Perhaps remove this. break; @@ -1262,9 +1603,9 @@ private S7ControllerType lookupControllerType(String articleNumber) { * +----------------+ * Byte n | Year 0 to 99 | * +----------------+ - * Byte n+1 | Month 0 to 12 | + * Byte n+1 | Month 1 to 12 | * +----------------+ - * Byte n+2 | Day 0 to 31 | + * Byte n+2 | Day 1 to 31 | * +----------------+ * Byte n+3 | Hour 0 to 23 | * +----------------+ @@ -1279,10 +1620,11 @@ private S7ControllerType lookupControllerType(String articleNumber) { */ private LocalDateTime readDateAndTime(ByteBuf data) { //from Plc4XS7Protocol - int year=convertByteToBcd(data.readByte()); - int month=convertByteToBcd(data.readByte()); - int day=convertByteToBcd(data.readByte()); + byte themonth = data.readByte(); + int month=convertByteToBcd(themonth==0x00?0x01:themonth); + byte theday = data.readByte(); + int day=convertByteToBcd(theday==0x00?0x01:theday); int hour=convertByteToBcd(data.readByte()); int minute=convertByteToBcd(data.readByte()); int second=convertByteToBcd(data.readByte()); @@ -1300,9 +1642,10 @@ private LocalDateTime readDateAndTime(ByteBuf data) { else{ year+=2000; } - + return LocalDateTime.of(year,month,day,hour,minute,second, nanoseconds); } + private LocalTime readTimeOfDay(ByteBuf data) { //per definition for Date_And_Time only the first 6 bytes are used @@ -1332,5 +1675,6 @@ private static int convertByteToBcd(byte incomingByte) { int dec = (incomingByte >> 4) * 10; return dec + (incomingByte & 0x0f); } + } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/events/S7Alarm.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/events/S7Alarm.java index 07b951e7778..3f429779c98 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/events/S7Alarm.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/events/S7Alarm.java @@ -27,6 +27,7 @@ Licensed to the Apache Software Foundation (ASF) under one import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; +import java.time.ZoneOffset; import java.util.Collection; import java.util.Hashtable; import org.apache.plc4x.java.api.messages.PlcReadRequest; @@ -87,8 +88,8 @@ public S7Alarm(MessageObjectItem s7alarm) { } @Override - public Instant getTimestamp() { - return s7alarm.getTimestampComing().toInstant(); + public Instant getTimestamp() { + return s7alarm.getTimestampComing().toInstant(ZoneOffset.UTC); } @Override diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuCyclicServicesRequestParameter.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuCyclicServicesRequestParameter.java new file mode 100644 index 00000000000..9c2dd231f5c --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuCyclicServicesRequestParameter.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.java.s7.netty.model.params; + +import org.apache.plc4x.java.s7.netty.model.types.CpuCyclicServicesParameterSubFunctionGroupType; +import org.apache.plc4x.java.s7.netty.model.types.CpuServicesParameterFunctionGroup; +import org.apache.plc4x.java.s7.netty.model.types.CpuUserDataMethodType; +import org.apache.plc4x.java.s7.netty.model.types.ParameterType; + +/** + * + * @author cgarcia + */ +public class CpuCyclicServicesRequestParameter extends CpuServicesRequestParameter { + private CpuUserDataMethodType Method; + private CpuCyclicServicesParameterSubFunctionGroupType cyclicSubFunction; + + public CpuCyclicServicesRequestParameter(CpuUserDataMethodType Method, + CpuServicesParameterFunctionGroup functionGroup, + CpuCyclicServicesParameterSubFunctionGroupType cyclicSubFunction, + byte sequenceNumber) { + super(functionGroup, null, sequenceNumber); + this.Method = Method; + this.cyclicSubFunction = cyclicSubFunction; + } + + public CpuUserDataMethodType getMethod() { + return Method; + } + + public CpuCyclicServicesParameterSubFunctionGroupType getCyclicSubFunction() { + return cyclicSubFunction; + } + + /* + * TODO: The parameter type is not consistent for all posible objects. Must be evaluated. + */ + @Override + public ParameterType getType() { + return ParameterType.CPU_SERVICES; + } + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuCyclicServicesResponseParameter.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuCyclicServicesResponseParameter.java new file mode 100644 index 00000000000..9208ca04fd5 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuCyclicServicesResponseParameter.java @@ -0,0 +1,50 @@ +/* +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.netty.model.params; + +import org.apache.plc4x.java.s7.netty.model.types.CpuCyclicServicesParameterSubFunctionGroupType; +import org.apache.plc4x.java.s7.netty.model.types.CpuServicesParameterFunctionGroup; +import org.apache.plc4x.java.s7.netty.model.types.ParameterError; +import org.apache.plc4x.java.s7.netty.model.types.ParameterType; + +public class CpuCyclicServicesResponseParameter extends CpuServicesResponseParameter { + + private CpuCyclicServicesParameterSubFunctionGroupType subCycFunctionGroup; + + public CpuCyclicServicesResponseParameter( + CpuServicesParameterFunctionGroup functionGroup, + CpuCyclicServicesParameterSubFunctionGroupType subCycFunctionGroup, + byte sequenceNumber, + byte dataUnitReferenceNumber, + boolean lastDataUnit, + ParameterError error) { + super(functionGroup, null, sequenceNumber, dataUnitReferenceNumber, lastDataUnit, error); + this.subCycFunctionGroup = subCycFunctionGroup; + } + + public CpuCyclicServicesParameterSubFunctionGroupType getSubCycFunctionGroup() { + return subCycFunctionGroup; + } + + @Override + public ParameterType getType() { + return ParameterType.CPU_SERVICES; + } + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuServicesResponseParameter.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuServicesResponseParameter.java index 35182022f9b..e46a54c74cc 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuServicesResponseParameter.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/params/CpuServicesResponseParameter.java @@ -28,6 +28,16 @@ public class CpuServicesResponseParameter extends CpuServicesParameter { private boolean lastDataUnit; private ParameterError error; + public CpuServicesResponseParameter(CpuServicesParameterFunctionGroup functionGroup, + CpuServicesParameterSubFunctionGroup subFunctionGroup, + byte sequenceNumber) { + + super(functionGroup, subFunctionGroup, sequenceNumber); + this.dataUnitReferenceNumber = 0x00; + this.lastDataUnit = false; + this.error = null; + } + public CpuServicesResponseParameter(CpuServicesParameterFunctionGroup functionGroup, CpuServicesParameterSubFunctionGroup subFunctionGroup, byte sequenceNumber, diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/AlarmMessagePayload.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/AlarmMessagePayload.java index 1689b705c4d..5416aa8b877 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/AlarmMessagePayload.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/AlarmMessagePayload.java @@ -37,6 +37,17 @@ public class AlarmMessagePayload implements S7Payload, S7PushMessage { private final Integer length; private final AlarmMessageItem msg; + public AlarmMessagePayload(DataTransportErrorCode returnCode, + DataTransportSize dataTransportSize, + Integer length, + AlarmMessageItem msg) { + this.returnCode = returnCode; + this.dataTransportSize = dataTransportSize; + this.msgtype = null; + this.length = length; + this.msg = msg; + } + public AlarmMessagePayload(DataTransportErrorCode returnCode, DataTransportSize dataTransportSize, Object msgtype, diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuCyclicServicesRequestPayload.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuCyclicServicesRequestPayload.java new file mode 100644 index 00000000000..1d1eeacb735 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuCyclicServicesRequestPayload.java @@ -0,0 +1,91 @@ +/* +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.netty.model.payloads; + +import java.util.List; +import org.apache.plc4x.java.s7.netty.model.payloads.items.S7AnyVarPayloadItem; +import org.apache.plc4x.java.s7.netty.model.types.CpuCyclicServiceTimeBaseType; +import org.apache.plc4x.java.s7.netty.model.types.DataTransportErrorCode; +import org.apache.plc4x.java.s7.netty.model.types.DataTransportSize; +import org.apache.plc4x.java.s7.netty.model.types.ParameterType; + +/** + * + * @author cgarcia + */ +public class CpuCyclicServicesRequestPayload implements S7Payload { + private final DataTransportErrorCode returnCode; + private final DataTransportSize dataTransportSize; + private final int length; + private final int itemCount; + private final CpuCyclicServiceTimeBaseType timeBase; + private final byte timeFactor; + private final List items; + + public CpuCyclicServicesRequestPayload(DataTransportErrorCode returnCode, + DataTransportSize dataTransportSize, + int length, + int itemCount, + CpuCyclicServiceTimeBaseType timeBase, + byte timeFactor, + List items) { + this.returnCode = returnCode; + this.dataTransportSize = dataTransportSize; + this.length = length; + this.itemCount = itemCount; + this.timeBase = timeBase; + this.timeFactor = timeFactor; + this.items = items; + } + + public DataTransportErrorCode getReturnCode() { + return returnCode; + } + + public DataTransportSize getDataTransportSize() { + return dataTransportSize; + } + + public int getLength() { + return length; + } + + public int getItemCount() { + return itemCount; + } + + public CpuCyclicServiceTimeBaseType getTimeBase() { + return timeBase; + } + + public byte getTimeFactor() { + return timeFactor; + } + + public List getItems() { + return items; + } + + @Override + public ParameterType getType() { + return ParameterType.CPU_SERVICES; + } + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuCyclicServicesResponsePayload.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuCyclicServicesResponsePayload.java new file mode 100644 index 00000000000..a7cf4e8ed7e --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuCyclicServicesResponsePayload.java @@ -0,0 +1,84 @@ +/* +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.netty.model.payloads; + +import java.util.List; +import org.apache.plc4x.java.s7.netty.model.messages.S7PushMessage; +import org.apache.plc4x.java.s7.netty.model.payloads.items.AssociatedValueItem; +import org.apache.plc4x.java.s7.netty.model.types.DataTransportErrorCode; +import org.apache.plc4x.java.s7.netty.model.types.DataTransportSize; +import org.apache.plc4x.java.s7.netty.model.types.ParameterType; + +/** + * + * @author cgarcia + */ +public class CpuCyclicServicesResponsePayload implements S7Payload, S7PushMessage { + private final DataTransportErrorCode returnCode; + private final DataTransportSize dataTransportSize; + private final byte jobId; + private final int length; + private final int itemCount; + private final List items; + + public CpuCyclicServicesResponsePayload(DataTransportErrorCode returnCode, + DataTransportSize dataTransportSize, + byte jobId, + int length, + int itemCount, + List items) { + this.returnCode = returnCode; + this.dataTransportSize = dataTransportSize; + this.jobId = jobId; + this.length = length; + this.itemCount = itemCount; + this.items = items; + } + + public DataTransportErrorCode getReturnCode() { + return returnCode; + } + + public DataTransportSize getDataTransportSize() { + return dataTransportSize; + } + + public int getLength() { + return length; + } + + public byte getJobId() { + return jobId; + } + + public int getItemCount() { + return itemCount; + } + + public List getItems() { + return items; + } + + @Override + public ParameterType getType() { + return ParameterType.CPU_SERVICES; + } + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuCyclicServicesUnsubscribePayload.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuCyclicServicesUnsubscribePayload.java new file mode 100644 index 00000000000..fa1cdd74dc6 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuCyclicServicesUnsubscribePayload.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.netty.model.payloads; + +import org.apache.plc4x.java.s7.netty.model.types.DataTransportErrorCode; +import org.apache.plc4x.java.s7.netty.model.types.DataTransportSize; +import org.apache.plc4x.java.s7.netty.model.types.ParameterType; + +/** + * + * @author cgarcia + */ +public class CpuCyclicServicesUnsubscribePayload implements S7Payload { + private final DataTransportErrorCode returnCode; + private final DataTransportSize dataTransportSize; + private final int length; + private final byte function; + private final byte jobId; + + public CpuCyclicServicesUnsubscribePayload(DataTransportErrorCode returnCode, + DataTransportSize dataTransportSize, + int length, + byte function, + byte jobId) { + this.returnCode = returnCode; + this.dataTransportSize = dataTransportSize; + this.length = length; + this.function = function; + this.jobId = jobId; + } + + public DataTransportErrorCode getReturnCode() { + return returnCode; + } + + public DataTransportSize getDataTransportSize() { + return dataTransportSize; + } + + public int getLength() { + return length; + } + + public byte getFunction() { + return function; + } + + public byte getJobId() { + return jobId; + } + + + + + + + @Override + public ParameterType getType() { + return ParameterType.CPU_SERVICES; + } + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/VarPayload.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/VarPayload.java index 0167fb75e08..9c094d35348 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/VarPayload.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/VarPayload.java @@ -18,11 +18,10 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.s7.netty.model.payloads; -import org.apache.plc4x.java.s7.netty.model.payloads.items.VarPayloadItem; -import org.apache.plc4x.java.s7.netty.model.types.ParameterType; - import java.util.ArrayList; import java.util.List; +import org.apache.plc4x.java.s7.netty.model.payloads.items.VarPayloadItem; +import org.apache.plc4x.java.s7.netty.model.types.ParameterType; /** * Used for writes to S7 as part of a Valid {@link org.apache.plc4x.java.s7.netty.model.messages.S7RequestMessage} together diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/AlarmMessageItem.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/AlarmMessageItem.java index 50afe30be52..d5dfc56fdb2 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/AlarmMessageItem.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/AlarmMessageItem.java @@ -35,12 +35,26 @@ public class AlarmMessageItem { private final byte function; private final byte objects; private final int Length; - private final List msgItems; - + private final List msgItems; + + + public AlarmMessageItem(byte function, + byte objects, + List msgItems) { + + this.timestamp = null; + this.function = function; + this.objects = objects; + this.msgItems = msgItems; + this.returnCode = null; + this.dataTransportSize = null; + this.Length = 0; + } + public AlarmMessageItem(LocalDateTime timestamp, byte function, byte objects, - List msgItems) { + List msgItems) { this.timestamp = timestamp; this.function = function; @@ -56,7 +70,7 @@ public AlarmMessageItem(byte function, DataTransportErrorCode returnCode, DataTransportSize dataTransportSize, int Length, - List msgItems){ + List msgItems){ this.function = function; this.objects = objects; this.returnCode = returnCode; @@ -92,7 +106,7 @@ public int getLength() { return Length; } - public List getMsgItems() { + public List getMsgItems() { return msgItems; } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/MessageObjectItem.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/MessageObjectItem.java index 081b3460619..752e5ddacea 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/MessageObjectItem.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/MessageObjectItem.java @@ -19,9 +19,11 @@ Licensed to the Apache Software Foundation (ASF) under one package org.apache.plc4x.java.s7.netty.model.payloads.items; -import java.time.format.DateTimeFormatter; -import java.util.Calendar; +import java.time.LocalDateTime; import java.util.List; +import org.apache.plc4x.java.s7.netty.model.types.AlarmQueryType; +import org.apache.plc4x.java.s7.netty.model.types.QueryType; +import org.apache.plc4x.java.s7.netty.model.types.VariableAddressingMode; /** * @@ -31,21 +33,102 @@ public class MessageObjectItem { private final byte VariableSpecification; private final byte Length; - private final Object SyntaxID; + private final VariableAddressingMode SyntaxID; private final byte NumberOfValues; private final int EventID; private final byte EventState; private final byte State; private final byte AckStateGoing; private final byte AckStateComming; - private final Calendar TimestampComing; - private final Calendar TimestampGoing; + private final LocalDateTime TimestampComing; + private final LocalDateTime TimestampGoing; private final List ComingValues; - private final List GoingValues; + private final List GoingValues; + //For Query alarms. + private final QueryType querytype; + private final AlarmQueryType alarmtype; + + //For Query request + public MessageObjectItem(byte VariableSpecification, + byte Length, + VariableAddressingMode SyntaxID, + QueryType querytype, + AlarmQueryType alarmtype) { + + this.VariableSpecification = VariableSpecification; + this.Length = Length; + this.SyntaxID = SyntaxID; + this.NumberOfValues = 0x00; + this.EventID = 0x0000; + this.EventState = 0x00; + this.State = 0x00; + this.AckStateGoing = 0x00; + this.AckStateComming = 0x00; + this.TimestampComing = null; + this.ComingValues = null; + this.TimestampGoing = null; + this.GoingValues = null; + this.querytype = querytype; + this.alarmtype = alarmtype; + } + + //For Query reply + public MessageObjectItem(byte Length, + AlarmQueryType alarmtype, + int EventID, + byte EventState, + byte AckStateGoing, + byte AckStateComming, + LocalDateTime TimestampComing, + List ComingValues, + LocalDateTime TimestampGoing, + List GoingValues) { + + this.VariableSpecification = 0x00; + this.Length = Length; + this.SyntaxID = null; + this.NumberOfValues = 0x00; + this.EventID = EventID; + this.EventState = EventState; + this.State = 0x00; + this.AckStateGoing = AckStateGoing; + this.AckStateComming = AckStateComming; + this.TimestampComing = TimestampComing; + this.ComingValues = ComingValues; + this.TimestampGoing = TimestampGoing; + this.GoingValues = GoingValues; + this.querytype = null; + this.alarmtype = alarmtype; + } public MessageObjectItem(byte VariableSpecification, byte Length, - Object SyntaxID, + VariableAddressingMode SyntaxID, + byte NumberOfValues, + int EventID, + byte AckStateGoing, + byte AckStateComming) { + + this.VariableSpecification = VariableSpecification; + this.Length = Length; + this.SyntaxID = SyntaxID; + this.NumberOfValues = NumberOfValues; + this.EventID = EventID; + this.EventState = 0x00; + this.State = 0x00; + this.AckStateGoing = AckStateGoing; + this.AckStateComming = AckStateComming; + this.TimestampComing = null; + this.ComingValues = null; + this.TimestampGoing = null; + this.GoingValues = null; + this.querytype = null; + this.alarmtype = null; + } + + public MessageObjectItem(byte VariableSpecification, + byte Length, + VariableAddressingMode SyntaxID, byte NumberOfValues, int EventID, byte EventState, @@ -67,20 +150,22 @@ public MessageObjectItem(byte VariableSpecification, this.ComingValues = Values; this.TimestampGoing = null; this.GoingValues = null; + this.querytype = null; + this.alarmtype = null; } public MessageObjectItem(byte VariableSpecification, byte Length, - Object SyntaxID, + VariableAddressingMode SyntaxID, byte NumberOfValues, int EventID, byte EventState, byte State, byte AckStateGoing, byte AckStateComming, - Calendar TimestampComing, + LocalDateTime TimestampComing, List ComingValues, - Calendar TimestampGoing, + LocalDateTime TimestampGoing, List GoingValues) { this.VariableSpecification = VariableSpecification; @@ -96,8 +181,10 @@ public MessageObjectItem(byte VariableSpecification, this.ComingValues = ComingValues; this.TimestampGoing = TimestampGoing; this.GoingValues = GoingValues; + this.querytype = null; + this.alarmtype = null; } - + public byte getVariableSpecification() { return VariableSpecification; } @@ -106,7 +193,7 @@ public byte getLength() { return Length; } - public Object getSyntaxID() { + public VariableAddressingMode getSyntaxID() { return SyntaxID; } @@ -134,11 +221,11 @@ public byte getAckStateComming() { return AckStateComming; } - public Calendar getTimestampComing() { + public LocalDateTime getTimestampComing() { return TimestampComing; } - public Calendar getTimestampGoing() { + public LocalDateTime getTimestampGoing() { return TimestampGoing; } @@ -150,29 +237,34 @@ public List getGoingValues() { return GoingValues; } + public QueryType getQuerytype() { + return querytype; + } + + public AlarmQueryType getAlarmtype() { + return alarmtype; + } + @Override public String toString() { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss.SSS"); - return "MessageObjectItem{" + "VariableSpecification=" + VariableSpecification - + ", Length=" + Length - + ", SyntaxID=" + SyntaxID - + ", NumberOfValues=" + NumberOfValues - + ", EventID=" + EventID - + ", EventState=" + EventState - + ", State=" + State - + ", AckStateGoing=" + AckStateGoing - + ", AckStateComming=" + AckStateComming - + ", TimestampComing=" + TimestampComing - + ", TimestampGoing=" + TimestampGoing - + ", ComingValues=" + ComingValues - + ", GoingValues=" + GoingValues - + '}'; + return "MessageObjectItem{" + "VariableSpecification=" + VariableSpecification + + ", Length=" + Length + + ", SyntaxID=" + SyntaxID + + ", NumberOfValues=" + NumberOfValues + + ", EventID=" + EventID + + ", EventState=" + EventState + + ", State=" + State + + ", AckStateGoing=" + AckStateGoing + + ", AckStateComming=" + AckStateComming + + ", TimestampComing=" + TimestampComing + + ", TimestampGoing=" + TimestampGoing + + ", ComingValues=" + ComingValues + + ", GoingValues=" + GoingValues + + ", querytype=" + querytype + + ", alarmtype=" + alarmtype + '}'; } + - - - - } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/S7AnyVarPayloadItem.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/S7AnyVarPayloadItem.java new file mode 100644 index 00000000000..512cbced5a9 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/S7AnyVarPayloadItem.java @@ -0,0 +1,95 @@ +/* +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.netty.model.payloads.items; + +import org.apache.plc4x.java.s7.netty.model.params.items.*; +import org.apache.plc4x.java.s7.netty.model.types.MemoryArea; +import org.apache.plc4x.java.s7.netty.model.types.SpecificationType; +import org.apache.plc4x.java.s7.netty.model.types.TransportSize; +import org.apache.plc4x.java.s7.netty.model.types.VariableAddressingMode; + +/** + * "Low-level" description of S7 Address range and the necessary size for transportation of values. + * Is used as Arguments of {@link org.apache.plc4x.java.s7.netty.model.params.VarParameter} object. + * + * Contains the information to read one or more sequential values of the same datatype starting from given offset in a memory region + * and also contains the transportation size of the datatype read. + * + * In detail: + *
    + *
  • transportSize - {@link TransportSize} of the datatype
  • + *
  • numElements - number of consecutive elements to be read
  • + *
  • dataBlockNumber - number of the datablock
  • + *
  • bit / byteOffset where the adress starts
  • + *
+ */ +public class S7AnyVarPayloadItem implements VarParameterItem { + + private final SpecificationType specificationType; + private final MemoryArea memoryArea; + private final TransportSize dataType; + private final int numElements; + private final int dataBlockNumber; + private final int byteOffset; + private final byte bitOffset; + + public S7AnyVarPayloadItem(SpecificationType specificationType, MemoryArea memoryArea, TransportSize dataType, int numElements, int dataBlockNumber, int byteOffset, byte bitOffset) { + this.specificationType = specificationType; + this.memoryArea = memoryArea; + this.dataType = dataType; + this.numElements = numElements; + this.dataBlockNumber = dataBlockNumber; + this.byteOffset = byteOffset; + this.bitOffset = bitOffset; + } + + @Override + public VariableAddressingMode getAddressingMode() { + return VariableAddressingMode.S7ANY; + } + + public SpecificationType getSpecificationType() { + return specificationType; + } + + public MemoryArea getMemoryArea() { + return memoryArea; + } + + public TransportSize getDataType() { + return dataType; + } + + public int getNumElements() { + return numElements; + } + + public int getDataBlockNumber() { + return dataBlockNumber; + } + + public int getByteOffset() { + return byteOffset; + } + + public byte getBitOffset() { + return bitOffset; + } + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuCyclicServiceTimeBaseType.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuCyclicServiceTimeBaseType.java new file mode 100644 index 00000000000..add0100ae72 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuCyclicServiceTimeBaseType.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.java.s7.netty.model.types; + +import java.util.HashMap; +import java.util.Map; +import org.apache.plc4x.java.api.model.PlcField; + +/** + * + * @author cgarcia + */ +public enum CpuCyclicServiceTimeBaseType implements PlcField { + + TB_100_MS("100 MS", (byte) 0x00), + TB_1_SEC("1 SECOND", (byte) 0x01), + TB_10_SEC("10 SECONDS", (byte) 0x02); + + + private static final Map map; + + static { + map = new HashMap<>(); + for (CpuCyclicServiceTimeBaseType subevent : CpuCyclicServiceTimeBaseType.values()) { + map.put(subevent.code, subevent); + } + } + + private final String event; + private final byte code; + + CpuCyclicServiceTimeBaseType(String event, byte code){ + this.event = event; + this.code = code; + } + + public String getEvent(){ + return event; + } + + public byte getCode() { + return code; + } + + public static CpuCyclicServiceTimeBaseType valueOfEvent(String event) { + for (CpuCyclicServiceTimeBaseType value : CpuCyclicServiceTimeBaseType.values()) { + if(value.getEvent().equals(event)) { + return value; + } + } + return null; + } + + public static CpuCyclicServiceTimeBaseType valueOf(byte code) { + return map.get(code); + } + + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuServicesParameterFunctionGroup.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuServicesParameterFunctionGroup.java index 25f5ac07e78..e01f91dced1 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuServicesParameterFunctionGroup.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuServicesParameterFunctionGroup.java @@ -18,15 +18,22 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.s7.netty.model.types; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.HashMap; import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public enum CpuServicesParameterFunctionGroup { - CPU_FUNCTIONS((byte) 0x04); + MODE_TRANSITION((byte) 0x00), + PROGRAMMER_COMMANDS((byte) 0x01), + CYCLIC_SERVICES((byte) 0x02), + BLOCK_FUNCTIONS((byte) 0x03), + CPU_FUNCTIONS((byte) 0x04), + SECURITY((byte) 0x05), + PCB_BSEND_BRECV((byte) 0x06), + TIMER_FUNCTIONS((byte) 0x07), + NC_PROGRAMMING((byte) 0x0f); private static final Logger logger = LoggerFactory.getLogger(CpuServicesParameterFunctionGroup.class); diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/ParameterType.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/ParameterType.java index ed7da61b4a3..629124f73e9 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/ParameterType.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/ParameterType.java @@ -31,6 +31,7 @@ public enum ParameterType { MODE_TRANSITION((byte) 0x01), READ_VAR((byte) 0x04), WRITE_VAR((byte) 0x05), + ALARM_ACK((byte) 0x0b), REQUEST_DOWNLOAD((byte) 0x1A), DOWNLOAD_BLOCK((byte) 0x1B), DOWNLOAD_ENDED((byte) 0x1C), diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/QueryType.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/QueryType.java new file mode 100644 index 00000000000..9ee92e22c7b --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/QueryType.java @@ -0,0 +1,73 @@ +/* + 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.netty.model.types; + +import java.util.HashMap; +import java.util.Map; + +/** + * + * @author cgarcia + */ +public enum QueryType { + + BYALARMTYPE("BYALARMTYPE", (byte) 0x01), + BYEVENTID("BYEVENTID", (byte) 0x02), + NONE("NONE", (byte) 0x00); + + + private static final Map map; + + static { + map = new HashMap<>(); + for (QueryType subevent : QueryType .values()) { + map.put(subevent.code, subevent); + } + } + + private final String event; + private final byte code; + + QueryType(String event, byte code){ + this.event = event; + this.code = code; + } + + public String getEvent(){ + return event; + } + + public byte getCode() { + return code; + } + + public static QueryType valueOfEvent(String event) { + for (QueryType value : QueryType .values()) { + if(value.getEvent().equals(event)) { + return value; + } + } + return null; + } + + public static QueryType valueOf(byte code) { + return map.get(code); + } +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/VariableAddressingMode.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/VariableAddressingMode.java index 5a2af697272..0e5b241ab61 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/VariableAddressingMode.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/VariableAddressingMode.java @@ -24,6 +24,8 @@ Licensed to the Apache Software Foundation (ASF) under one /** * (Values determined by evaluating generated ".pcap" files) * Renamed from "SyntaxId". + * + * Is the same DataItemSyntaxIdType */ public enum VariableAddressingMode { S7ANY((byte) 0x10), diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7PlcEventHandler.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7PlcFieldEventHandler.java similarity index 78% rename from plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7PlcEventHandler.java rename to plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7PlcFieldEventHandler.java index c009caee8fa..560944aef22 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7PlcEventHandler.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7PlcFieldEventHandler.java @@ -22,17 +22,20 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; import org.apache.plc4x.java.api.model.PlcField; import org.apache.plc4x.java.base.connection.DefaultPlcFieldHandler; -import org.apache.plc4x.java.s7.netty.model.types.SubscribedEventType; +import org.apache.plc4x.java.s7.model.S7SubscriptionField; /** * * */ -public class S7PlcEventHandler extends DefaultPlcFieldHandler { +public class S7PlcFieldEventHandler extends DefaultPlcFieldHandler { @Override public PlcField createField(String fieldQuery) throws PlcInvalidFieldException { - return SubscribedEventType.valueOfEvent(fieldQuery); + if (S7SubscriptionField.matches(fieldQuery)) { + return S7SubscriptionField.of(fieldQuery); + } + throw new PlcInvalidFieldException(fieldQuery); } } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7SizeHelper.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7SizeHelper.java index 0010d7871c1..45076458a5b 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7SizeHelper.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7SizeHelper.java @@ -19,11 +19,14 @@ Licensed to the Apache Software Foundation (ASF) under one package org.apache.plc4x.java.s7.netty.util; import java.util.List; +import org.apache.plc4x.java.s7.netty.model.params.CpuCyclicServicesRequestParameter; import org.apache.plc4x.java.s7.netty.model.params.CpuServicesRequestParameter; import org.apache.plc4x.java.s7.netty.model.params.S7Parameter; import org.apache.plc4x.java.s7.netty.model.params.VarParameter; import org.apache.plc4x.java.s7.netty.model.params.items.S7AnyVarParameterItem; import org.apache.plc4x.java.s7.netty.model.params.items.VarParameterItem; +import org.apache.plc4x.java.s7.netty.model.payloads.AlarmMessagePayload; +import org.apache.plc4x.java.s7.netty.model.payloads.CpuCyclicServicesRequestPayload; import org.apache.plc4x.java.s7.netty.model.payloads.CpuMessageSubscriptionServicePayload; import org.apache.plc4x.java.s7.netty.model.payloads.CpuServicesPayload; import org.apache.plc4x.java.s7.netty.model.payloads.S7Payload; @@ -83,6 +86,16 @@ public static short getPayloadsLength(List payloads) { return 16; } + } else if(payload instanceof AlarmMessagePayload) { + AlarmMessagePayload data = (AlarmMessagePayload) payload; + l += data.getLength(); + l += 0x04; //TODO: Check for other combinations + return l; + } else if(payload instanceof CpuCyclicServicesRequestPayload) { + CpuCyclicServicesRequestPayload data = (CpuCyclicServicesRequestPayload) payload; + l += data.getLength(); + l += 0x04; //TODO: Check for other combinations + return l; } } return l; @@ -104,6 +117,8 @@ public static short getParameterLength(S7Parameter parameter) { case CPU_SERVICES: if(parameter instanceof CpuServicesRequestParameter) { return 8; + } else if(parameter instanceof CpuCyclicServicesRequestParameter) { + return 8; } else { return 12; } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7CyclicServicesSubscriptionHandle.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7CyclicServicesSubscriptionHandle.java new file mode 100644 index 00000000000..81d20ff8915 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7CyclicServicesSubscriptionHandle.java @@ -0,0 +1,83 @@ +/* + 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.protocol; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; +import org.apache.plc4x.java.api.messages.PlcSubscriptionEvent; +import org.apache.plc4x.java.api.model.PlcConsumerRegistration; +import org.apache.plc4x.java.api.model.PlcSubscriptionHandle; +import org.apache.plc4x.java.s7.netty.model.payloads.items.AssociatedValueItem; + +/** + * + * @author cgarcia + */ +public class S7CyclicServicesSubscriptionHandle implements PlcSubscriptionHandle { + Set> consumers = new HashSet<>(); + + //CyClic Services information hanler + private final String fieldName; //Subscription id from the request + private final byte jobId; //Job-Id from cyclic subscriotion + private final short error; //Register the error from the suscription. + private Map items; + + public S7CyclicServicesSubscriptionHandle(String fieldName, + byte jobId, + short error, + Map items) { + this.fieldName = fieldName; + this.jobId = jobId; + this.error = error; + this.items = items; + } + + public Set> getConsumers() { + return consumers; + } + + public String getFieldName() { + return fieldName; + } + + public byte getJobId() { + return jobId; + } + + public short getError() { + return error; + } + + public AssociatedValueItem getValueItem(String index){ + return items.get(index); + } + + public Map getItems() { + return items; + } + + @Override + public PlcConsumerRegistration register(Consumer consumer) { + consumers.add(consumer); + return () -> {consumers.remove(consumer);}; + } + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7DiagnosticSubscriptionHandle.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7DiagnosticSubscriptionHandle.java new file mode 100644 index 00000000000..139242a2288 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7DiagnosticSubscriptionHandle.java @@ -0,0 +1,46 @@ +/* + 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.protocol; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; +import org.apache.plc4x.java.api.messages.PlcSubscriptionEvent; +import org.apache.plc4x.java.api.model.PlcConsumerRegistration; +import org.apache.plc4x.java.api.model.PlcSubscriptionHandle; +import org.apache.plc4x.java.s7.netty.model.types.SubscribedEventType; + +/** + * + * @author cgarcia + */ +public class S7DiagnosticSubscriptionHandle implements PlcSubscriptionHandle { + Set> consumers = new HashSet<>(); + + //Diagnostic events + List subscribedevents; + + @Override + public PlcConsumerRegistration register(Consumer consumer) { + consumers.add(consumer); + return () -> {consumers.remove(consumer);}; + } + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/types/S7SubscriptionFieldType.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/types/S7SubscriptionFieldType.java new file mode 100644 index 00000000000..60afd253fad --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/types/S7SubscriptionFieldType.java @@ -0,0 +1,34 @@ +/* +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.types; + +/** + * + * @author cgarcia + */ +public enum S7SubscriptionFieldType { + + EVENT_SUBSCRIPTION, + EVENT_UNSUBSCRIPTION, + ALARM_ACK, + ALARM_QUERY, + CYCLIC_SUBSCRIPTION, + CYCLIC_UNSUBSCRIPTION; + +} From 5671bf9cdfd3161a5342be800e445343ff7d33b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Mon, 3 Feb 2020 02:35:22 -0400 Subject: [PATCH 07/17] Working in the user Event system. --- .../java/s7/connection/S7PlcConnection.java | 92 +++- .../base/messages/DefaultPlcReadResponse.java | 13 +- .../apache/plc4x/java/s7/model/S7Field.java | 4 +- .../plc4x/java/s7/model/S7SslField.java | 72 +++ .../plc4x/java/s7/netty/Plc4XS7Protocol.java | 321 +++++++++--- .../plc4x/java/s7/netty/S7Protocol.java | 147 ++++-- .../CpuCyclicServicesRequestPayload.java | 34 +- .../model/payloads/CpuServicesPayload.java | 16 + .../java/s7/netty/model/types/SslId.java | 13 +- .../java/s7/netty/util/S7PlcFieldHandler.java | 17 +- .../java/s7/protocol/S7ByteReadResponse.java | 480 +++++++++++++++++ .../S7CyclicServicesSubscriptionHandle.java | 4 +- .../S7DiagnosticSubscriptionHandle.java | 44 +- .../java/s7/protocol/event/S7Alarm8Event.java | 28 + .../s7/protocol/event/S7Alarm8pEvent.java | 28 + .../java/s7/protocol/event/S7AlarmDEvent.java | 28 + .../s7/protocol/event/S7AlarmDQEvent.java | 28 + .../java/s7/protocol/event/S7AlarmEvent.java | 14 + .../java/s7/protocol/event/S7AlarmSEvent.java | 434 ++++++++++++++++ .../s7/protocol/event/S7AlarmSQEvent.java | 28 + .../plc4x/java/s7/protocol/event/S7Event.java | 30 ++ .../java/s7/protocol/event/S7ModeEvent.java | 487 ++++++++++++++++++ .../s7/protocol/event/S7Notify8pEvent.java | 28 + .../java/s7/protocol/event/S7NotifyEvent.java | 14 + .../java/s7/protocol/event/S7SysEvent.java | 477 +++++++++++++++++ .../java/s7/protocol/event/S7UserEvent.java | 28 + .../java/s7/utils/S7DiagnosticEventId.java | 215 +++++++- .../plc4x/java/s7/utils/S7SslHelper.java | 28 + 28 files changed, 2972 insertions(+), 180 deletions(-) create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7SslField.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7ByteReadResponse.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Alarm8Event.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Alarm8pEvent.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmDEvent.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmDQEvent.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmEvent.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmSEvent.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmSQEvent.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Event.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7ModeEvent.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Notify8pEvent.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7NotifyEvent.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7SysEvent.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7UserEvent.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7SslHelper.java diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java index b4cc4499790..a8cec59e299 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java @@ -22,6 +22,7 @@ Licensed to the Apache Software Foundation (ASF) under one import io.netty.buffer.Unpooled; import io.netty.channel.*; import java.net.InetAddress; +import java.time.Instant; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -75,10 +76,14 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.netty.model.payloads.CpuDiagnosticMessagePayload; import org.apache.plc4x.java.s7.netty.model.payloads.items.AssociatedValueItem; import org.apache.plc4x.java.s7.netty.model.types.MemoryArea; +import org.apache.plc4x.java.s7.netty.model.types.SubscribedEventType; import org.apache.plc4x.java.s7.netty.strategies.DefaultS7MessageProcessor; import org.apache.plc4x.java.s7.netty.util.S7PlcFieldEventHandler; import org.apache.plc4x.java.s7.netty.util.S7PlcFieldHandler; import org.apache.plc4x.java.s7.protocol.S7CyclicServicesSubscriptionHandle; +import org.apache.plc4x.java.s7.protocol.S7DiagnosticSubscriptionHandle; +import org.apache.plc4x.java.s7.protocol.event.S7ModeEvent; +import org.apache.plc4x.java.s7.protocol.event.S7SysEvent; import org.apache.plc4x.java.s7.types.S7ControllerType; import org.apache.plc4x.java.s7.utils.S7TsapIdEncoder; import org.apache.plc4x.java.tcp.connection.TcpSocketChannelFactory; @@ -125,7 +130,8 @@ public class S7PlcConnection extends NettyPlcConnection implements PlcReader, Pl Map> cyclicServicesSubscriptions = new HashMap(); - Map cyclicServicesHandles = new HashMap(); + Map> pushEventHandles = new HashMap(); + Map cyclicServicesHandles = new HashMap(); private EventLoop alarmsloopthread; @@ -200,9 +206,20 @@ public S7PlcConnection(ChannelFactory channelFactory, int rack, int slot, String */ this.alarmsqueue = new ArrayBlockingQueue<>(1024); + Map usrEventHandle = new HashMap(); + Map sysEventHandle = new HashMap(); + Map modeEventHandle = new HashMap(); + Map almEventHandle = new HashMap(); + + pushEventHandles.put(SubscribedEventType.USR, usrEventHandle); + pushEventHandles.put(SubscribedEventType.SYS, usrEventHandle); + pushEventHandles.put(SubscribedEventType.MODE, modeEventHandle); + pushEventHandles.put(SubscribedEventType.ALM, almEventHandle); + alarmsloopthread = new EventLoop(channel, this.alarmsqueue, cyclicServicesSubscriptions, + pushEventHandles, cyclicServicesHandles); } @@ -427,9 +444,19 @@ public PlcConsumerRegistration register(Consumer consumer, if (handle instanceof S7CyclicServicesSubscriptionHandle) { S7CyclicServicesSubscriptionHandle s7handle = (S7CyclicServicesSubscriptionHandle) handle; if (!cyclicServicesHandles.containsKey(s7handle.getJobId())){ - cyclicServicesHandles.put(s7handle.getJobId(), s7handle); + cyclicServicesHandles.put((short) s7handle.getJobId(), s7handle); } } + + if (handle instanceof S7DiagnosticSubscriptionHandle) { + S7DiagnosticSubscriptionHandle s7handle = (S7DiagnosticSubscriptionHandle) handle; + s7handle.getConsumers().add(consumer); + s7handle.getSubscribedevents().forEach((event)->{ + pushEventHandles.get(event).put(s7handle.getJobId(), s7handle); + logger.info("Suscripcion: " + s7handle.getSubscribedevents().toString()); + }); + + } }); if (!cyclicServicesSubscriptions.containsKey(consumer)){ @@ -449,17 +476,20 @@ private class EventLoop extends Thread { private final Channel channel; private boolean alarmquery; private int delay; - private final Map> cyclicServicesSubscriptions; - private final Map cyclicServicesHandles; + private final Map> cyclicServicesSubscriptions; + private final Map> pushEventHandles; + private final Map cyclicServicesHandles; private final BlockingQueue alarmsqueue; EventLoop(Channel channel, BlockingQueue alarmsqueue, Map> cyclicServicesSubscriptions, - Map cyclicServicesHandles) { + Map> pushEventHandles, + Map cyclicServicesHandles) { this.channel = channel; this.alarmsqueue = alarmsqueue; this.cyclicServicesSubscriptions = cyclicServicesSubscriptions; + this.pushEventHandles = pushEventHandles; this.cyclicServicesHandles = cyclicServicesHandles; this.alarmquery = true; this.delay = 1000; @@ -475,15 +505,22 @@ public void run() { if (msg instanceof AlarmMessagePayload){ AlarmMessagePayload themsg = (AlarmMessagePayload) msg; logger.info("AlarmMessagePayload: " + themsg); - } else if (msg instanceof CpuDiagnosticPushParameter) { + dispathAlmEvents(pushEventHandles.get(SubscribedEventType.ALM), themsg); + + } else if (msg instanceof CpuDiagnosticPushParameter) { CpuDiagnosticPushParameter themsg = (CpuDiagnosticPushParameter) msg; - logger.info("CpuDiagnosticPushParameter: " + themsg);; + logger.info("CpuDiagnosticPushParameter: " + themsg); + dispathModeEvents(pushEventHandles.get(SubscribedEventType.MODE), themsg); + } else if (msg instanceof CpuDiagnosticMessagePayload) { CpuDiagnosticMessagePayload themsg = (CpuDiagnosticMessagePayload) msg; logger.info("CpuDiagnosticMessagePayload: " + themsg); + dispathSysEvents(pushEventHandles.get(SubscribedEventType.SYS), themsg); + } else if (msg instanceof CpuServicesPushParameter) { CpuServicesPushParameter themsg = (CpuServicesPushParameter) msg; logger.info("CpuServicesPushParameter: " + themsg); + } else if (msg instanceof CpuCyclicServicesResponsePayload) { CpuCyclicServicesResponsePayload themsg = (CpuCyclicServicesResponsePayload) msg; logger.debug("CpuCyclicServicesResponsePayload: " + themsg + " JobId:" + themsg.getJobId()); @@ -504,9 +541,7 @@ public void run() { } } - - - + } catch (InterruptedException ex) { logger.info(ex.getLocalizedMessage()); } @@ -514,6 +549,39 @@ public void run() { logger.info("Closing the alarm loop."); } + private void dispathSysEvents(Map handles, CpuDiagnosticMessagePayload payload) + { + handles.forEach((index,handle)->{ + S7DiagnosticSubscriptionHandle thehandle = (S7DiagnosticSubscriptionHandle) handle; + thehandle.getConsumers().forEach((consumer)->{ + S7SysEvent event = new S7SysEvent(payload.getMsg()); + consumer.accept(event); + }); + }); + } + + private void dispathModeEvents(Map handles, CpuDiagnosticPushParameter parameter) + { + handles.forEach((index,handle)->{ + S7DiagnosticSubscriptionHandle thehandle = (S7DiagnosticSubscriptionHandle) handle; + thehandle.getConsumers().forEach((consumer)->{ + S7ModeEvent event = new S7ModeEvent(Instant.now(), parameter); + consumer.accept(event); + }); + }); + } + + private void dispathAlmEvents(Map handles, AlarmMessagePayload payload) + { + handles.forEach((index,handle)->{ + S7DiagnosticSubscriptionHandle thehandle = (S7DiagnosticSubscriptionHandle) handle; + thehandle.getConsumers().forEach((consumer)->{ + consumer.accept(null); + }); + }); + } + + private void UpdateCyclicServicesData(S7CyclicServicesSubscriptionHandle handle,CpuCyclicServicesResponsePayload themsg){ Map items = handle.getItems(); @@ -538,7 +606,9 @@ private void UpdateCyclicServicesData(S7CyclicServicesSubscriptionHandle handle, //PlcSubscriptionEvent event = new DefaultPlcSubscriptionEvent(Instant.now(), fields); values2consumer.forEach((index, itemvalue)->{ - consumer.accept(null); + if (consumer != null) { + consumer.accept(null); + }; //logger.info("Procesando valores : " + index + "\r\n" + ByteBufUtil.prettyHexDump(itemvalue.getData())); }); //Pair newPair = new ImmutablePair<>(PlcResponseCode, stringItem); diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcReadResponse.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcReadResponse.java index bb7675988bf..42dacf137b8 100644 --- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcReadResponse.java +++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcReadResponse.java @@ -18,19 +18,18 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.base.messages; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; -import org.apache.plc4x.java.api.exceptions.PlcRuntimeException; -import org.apache.plc4x.java.api.model.PlcField; -import org.apache.plc4x.java.api.types.PlcResponseCode; -import org.apache.plc4x.java.base.messages.items.BaseDefaultFieldItem; - import java.math.BigDecimal; import java.math.BigInteger; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.*; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; +import org.apache.plc4x.java.api.exceptions.PlcRuntimeException; +import org.apache.plc4x.java.api.model.PlcField; +import org.apache.plc4x.java.api.types.PlcResponseCode; +import org.apache.plc4x.java.base.messages.items.BaseDefaultFieldItem; public class DefaultPlcReadResponse implements InternalPlcReadResponse { diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java index 3e55238677c..f3a3de06da1 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java @@ -38,9 +38,7 @@ public class S7Field implements PlcField { //blockNumber usually has its max hat around 64000 --> 5digits private static final Pattern DATA_BLOCK_ADDRESS_PATTERN = Pattern.compile("^%DB(?\\d{1,5}).DB(?[XBWD]?)(?\\d{1,7})(.(?[0-7]))?:(?[a-zA-Z_]+)(\\[(?\\d+)])?"); - - - + private static final String DATA_TYPE = "dataType"; private static final String TRANSFER_SIZE_CODE = "transferSizeCode"; private static final String BLOCK_NUMBER = "blockNumber"; diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7SslField.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7SslField.java new file mode 100644 index 00000000000..75d58ec295d --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7SslField.java @@ -0,0 +1,72 @@ +/* +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.model; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; +import org.apache.plc4x.java.api.model.PlcField; + +/** + * + * @author cgarcia + */ +public class S7SslField implements PlcField { + + //SZL_ID=0xYYYY;INDEX=0xZZZZ + private static final Pattern SSL_ADDRESS_PATTERN = + Pattern.compile("^SSL_ID=(?16#[0-9a-fA-F]{4});INDEX=(?16#[0-9a-fA-F]{4})"); + + private static final String SSL_ID = "sslId"; + private static final String INDEX = "index"; + + private final int szlId; + private final int index; + + public S7SslField(int sslId, int index) { + this.szlId = sslId; + this.index = index; + } + + public int getSslId() { + return szlId; + } + + public int getIndex() { + return index; + } + + public static boolean matches(String fieldString) { + System.out.println("fieldString: " + fieldString); + return SSL_ADDRESS_PATTERN.matcher(fieldString).matches(); + } + + public static S7SslField of(String fieldString) { + Matcher matcher = SSL_ADDRESS_PATTERN.matcher(fieldString); + if (matcher.matches()){ + String strSxlId = matcher.group(SSL_ID); + String strIndex = matcher.group(INDEX); + strSxlId = strSxlId.replaceAll("16#", ""); + strIndex = strIndex.replaceAll("16#", ""); + return new S7SslField(Integer.parseInt(strSxlId, 16),Integer.parseInt(strIndex, 16)); + } + throw new PlcInvalidFieldException("Unable to parse address: " + fieldString); + } +} 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 35a426a6e86..a49ee84882e 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 @@ -56,8 +56,10 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.base.events.ConnectedEvent; import org.apache.plc4x.java.base.messages.*; import org.apache.plc4x.java.base.messages.items.*; +import org.apache.plc4x.java.base.model.InternalPlcSubscriptionHandle; import org.apache.plc4x.java.base.model.SubscriptionPlcField; import org.apache.plc4x.java.s7.model.S7Field; +import org.apache.plc4x.java.s7.model.S7SslField; import org.apache.plc4x.java.s7.model.S7SubscriptionField; import org.apache.plc4x.java.s7.netty.events.S7ConnectedEvent; import org.apache.plc4x.java.s7.netty.model.messages.S7Message; @@ -76,6 +78,7 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.netty.model.payloads.CpuCyclicServicesRequestPayload; import org.apache.plc4x.java.s7.netty.model.payloads.CpuCyclicServicesResponsePayload; import org.apache.plc4x.java.s7.netty.model.payloads.CpuMessageSubscriptionServicePayload; +import org.apache.plc4x.java.s7.netty.model.payloads.CpuServicesPayload; import org.apache.plc4x.java.s7.netty.model.payloads.S7Payload; import org.apache.plc4x.java.s7.netty.model.payloads.VarPayload; import org.apache.plc4x.java.s7.netty.model.payloads.items.AlarmMessageItem; @@ -84,7 +87,9 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.netty.model.payloads.items.S7AnyVarPayloadItem; import org.apache.plc4x.java.s7.netty.model.payloads.items.VarPayloadItem; import org.apache.plc4x.java.s7.netty.model.types.*; +import org.apache.plc4x.java.s7.protocol.S7ByteReadResponse; import org.apache.plc4x.java.s7.protocol.S7CyclicServicesSubscriptionHandle; +import org.apache.plc4x.java.s7.protocol.S7DiagnosticSubscriptionHandle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -195,7 +200,7 @@ protected void encode(ChannelHandlerContext ctx, PlcRequestContainer msg, List out) encodeCycledSubscriptionRequest(msg, out); break; case CYCLIC_UNSUBSCRIPTION:; + encodeCycledUnSubscriptionRequest(msg, out); break; default:; }; @@ -279,45 +285,7 @@ private void encodeEventSubcriptionRequest(PlcRequestContainer msg, List out.add(s7ReadRequest); } - private void encodeEventUnSubcriptionRequest(PlcRequestContainer msg, List out) throws PlcException { - byte subsevent = 0; - List parameterItems = new LinkedList<>(); - List payloadItems = new LinkedList<>(); - - PlcSubscriptionRequest subsRequest = (PlcSubscriptionRequest) msg.getRequest(); - - for (String fieldName : subsRequest.getFieldNames()) { - if ( subsRequest.getField(fieldName) instanceof S7SubscriptionField){ - S7SubscriptionField event = (S7SubscriptionField) subsRequest.getField(fieldName); - subsevent = (byte) (subsevent | event.getEventtype().getCode()); - } - } - - CpuServicesParameter cpuservice = new CpuServicesRequestParameter(CpuServicesParameterFunctionGroup.CPU_FUNCTIONS, - CpuServicesParameterSubFunctionGroup.MESSAGE_SERVICE, (byte) 0x00); - - parameterItems.add(cpuservice); - - - S7Payload Data = new CpuMessageSubscriptionServicePayload(DataTransportErrorCode.OK, - DataTransportSize.OCTET_STRING, - subsevent, - new String("HmiRtm "), - AlarmType.ALARM_S_INITIATE); - payloadItems.add(Data); - - - S7RequestMessage s7ReadRequest = new S7RequestMessage(MessageType.USER_DATA, - (short) tpduGenerator.getAndIncrement(), - parameterItems, - payloadItems, - msg); - - requests.put(s7ReadRequest.getTpduReference(), msg); - - out.add(s7ReadRequest); - } - + //TODO: Check for ALARM_D and ALARM_8 private void encodeAlarmAckRequest(PlcRequestContainer msg, List out) throws PlcException { byte subsevent = 0; @@ -481,27 +449,131 @@ private void encodeCycledSubscriptionRequest(PlcRequestContainer msg, List out) throws PlcException { - //TODO : Perform subscription termination - } + private void encodeUnSubcriptionRequest(PlcRequestContainer msg, List out) throws PlcException { + //Chequear el campo prueba que ya incluyte la información del tipo + InternalPlcUnsubscriptionRequest subsRequest = (InternalPlcUnsubscriptionRequest) msg.getRequest(); + Collection handles = subsRequest.getInternalPlcSubscriptionHandles(); + handles.forEach((handle)->{ + if (handle instanceof S7CyclicServicesSubscriptionHandle) { + try { + encodeCycledUnSubscriptionRequest(msg,out); + } catch (PlcException ex) { + logger.info(ex.toString()); + } + } + }); + + } + private void encodeEventUnSubcriptionRequest(PlcRequestContainer msg, List out) throws PlcException { + byte subsevent = 0; + List parameterItems = new LinkedList<>(); + List payloadItems = new LinkedList<>(); + + PlcSubscriptionRequest subsRequest = (PlcSubscriptionRequest) msg.getRequest(); + + for (String fieldName : subsRequest.getFieldNames()) { + if ( subsRequest.getField(fieldName) instanceof S7SubscriptionField){ + S7SubscriptionField event = (S7SubscriptionField) subsRequest.getField(fieldName); + subsevent = (byte) (subsevent | event.getEventtype().getCode()); + } + } + + CpuServicesParameter cpuservice = new CpuServicesRequestParameter(CpuServicesParameterFunctionGroup.CPU_FUNCTIONS, + CpuServicesParameterSubFunctionGroup.MESSAGE_SERVICE, (byte) 0x00); + + parameterItems.add(cpuservice); + + + S7Payload Data = new CpuMessageSubscriptionServicePayload(DataTransportErrorCode.OK, + DataTransportSize.OCTET_STRING, + subsevent, + new String("HmiRtm "), + AlarmType.ALARM_S_INITIATE); + payloadItems.add(Data); + + + S7RequestMessage s7ReadRequest = new S7RequestMessage(MessageType.USER_DATA, + (short) tpduGenerator.getAndIncrement(), + parameterItems, + payloadItems, + msg); + + requests.put(s7ReadRequest.getTpduReference(), msg); + + out.add(s7ReadRequest); + } + + private void encodeCycledUnSubscriptionRequest(PlcRequestContainer msg, List out) throws PlcException { + + List parameterItems = new LinkedList<>(); + List payloads = new LinkedList<>(); + byte jobId = 0x00; + + DefaultPlcUnsubscriptionRequest prueba = (DefaultPlcUnsubscriptionRequest) msg.getRequest(); + + Collection handles = prueba.getInternalPlcSubscriptionHandles(); + + for(InternalPlcSubscriptionHandle ihandle:handles){ + S7CyclicServicesSubscriptionHandle s7handle = (S7CyclicServicesSubscriptionHandle) ihandle; + jobId = s7handle.getJobId(); + break; + } + + + CpuCyclicServicesRequestPayload payload = new CpuCyclicServicesRequestPayload(DataTransportErrorCode.OK, + DataTransportSize.OCTET_STRING, + (byte) 0x02, + (byte) 0x05, + jobId); + + payloads.add(payload); + + CpuCyclicServicesRequestParameter parameter = new CpuCyclicServicesRequestParameter(CpuUserDataMethodType.REQUEST, + CpuServicesParameterFunctionGroup.CYCLIC_SERVICES, + CpuCyclicServicesParameterSubFunctionGroupType.CYCLIC_UNSUBSCRIBE, + (byte) 0x00); + parameterItems.add(parameter); + + + + // Assemble the request. + S7RequestMessage s7ReadRequest = new S7RequestMessage(MessageType.USER_DATA, + (short) tpduGenerator.getAndIncrement(), parameterItems, + payloads, msg); + + requests.put(s7ReadRequest.getTpduReference(), msg); + + out.add(s7ReadRequest); + + } + private void encodeReadRequest(PlcRequestContainer msg, List out) throws PlcException { List parameterItems = new LinkedList<>(); PlcReadRequest readRequest = (PlcReadRequest) msg.getRequest(); + for (String fieldName : readRequest.getFieldNames()) { PlcField field = readRequest.getField(fieldName); - if (!(field instanceof S7Field)) { - throw new PlcProtocolException("The field should have been of type S7Field"); - } - S7Field s7Field = (S7Field) field; + + if ((field instanceof S7SslField)) { + S7SslField szlfield = (S7SslField) field; + encodeSslReadRequest(msg,szlfield,out); + return; + } else { + if (!(field instanceof S7Field)) { + throw new PlcProtocolException("The field should have been of type S7Field"); + } - VarParameterItem varParameterItem = new S7AnyVarParameterItem( - SpecificationType.VARIABLE_SPECIFICATION, s7Field.getMemoryArea(), - s7Field.getDataType(), - s7Field.getNumElements(), s7Field.getBlockNumber(), s7Field.getByteOffset(), (byte) s7Field.getBitOffset()); - parameterItems.add(varParameterItem); + S7Field s7Field = (S7Field) field; + + VarParameterItem varParameterItem = new S7AnyVarParameterItem( + SpecificationType.VARIABLE_SPECIFICATION, s7Field.getMemoryArea(), + s7Field.getDataType(), + s7Field.getNumElements(), s7Field.getBlockNumber(), s7Field.getByteOffset(), (byte) s7Field.getBitOffset()); + parameterItems.add(varParameterItem); + } } VarParameter readVarParameter = new VarParameter(ParameterType.READ_VAR, parameterItems); @@ -515,6 +587,22 @@ private void encodeReadRequest(PlcRequestContainer msg, List out) throws out.add(s7ReadRequest); } + private void encodeSslReadRequest(PlcRequestContainer msg, S7SslField sslfield, List out) throws PlcException { + + S7RequestMessage szlRequestMessage = new S7RequestMessage(MessageType.USER_DATA, + (short) tpduGenerator.getAndIncrement(), + Collections.singletonList(new CpuServicesRequestParameter( + CpuServicesParameterFunctionGroup.CPU_FUNCTIONS, + CpuServicesParameterSubFunctionGroup.READ_SSL, (byte) 0)), + Collections.singletonList(new CpuServicesPayload(DataTransportErrorCode.OK, SslId.valueOf((short) (sslfield.getSslId() & 0x01FF)), + (short) sslfield.getIndex())), null); + + requests.put(szlRequestMessage.getTpduReference(), msg); + + out.add(szlRequestMessage); + } + + private void encodeWriteRequest(PlcRequestContainer msg, List out) throws PlcException { List parameterItems = new LinkedList<>(); List payloadItems = new LinkedList<>(); @@ -743,7 +831,6 @@ protected void decode(ChannelHandlerContext ctx, S7Message msg, List out PlcRequestContainer requestContainer = requests.remove(tpduReference); PlcRequest request = requestContainer.getRequest(); - // Handle the response. PlcResponse response = null; if (request instanceof PlcReadRequest) { response = decodeReadResponse(responseMessage, requestContainer); @@ -789,15 +876,17 @@ public void operationComplete(ChannelFuture future) { } } + } else if (request instanceof PlcUnsubscriptionRequest) { + response = decodeUnSubscriptionResponse(responseMessage, requestContainer); } else { - logger.debug("There is the client's request, but it is not a valid response...."); + logger.info("There is the client's request, but it is not a valid response...."); } // Confirm the response being handled. if (response != null) { requestContainer.getResponseFuture().complete(response); } else { - logger.debug("The message could not be processed..."); + logger.info("The message could not be processed..."); } } else { //PUSH Message @@ -805,7 +894,7 @@ public void operationComplete(ChannelFuture future) { for (S7Parameter parameter:parameters){ if (parameter instanceof S7PushMessage){ if (!alarmsqueue.offer((S7PushMessage) parameter)){ - logger.info("Alarm queue buffer is full."); + logger.info("Event queue buffer is full."); }; } } @@ -815,7 +904,7 @@ public void operationComplete(ChannelFuture future) { for (S7Payload payload:payloads){ if (payload instanceof S7PushMessage){ if (!alarmsqueue.offer((S7PushMessage) payload)){ - logger.info("Alarm queue buffer is full."); + logger.info("Event queue buffer is full."); }; } } @@ -826,7 +915,11 @@ public void operationComplete(ChannelFuture future) { @SuppressWarnings("unchecked") private PlcResponse decodeReadResponse(S7ResponseMessage responseMessage, PlcRequestContainer requestContainer) throws PlcProtocolException { InternalPlcReadRequest plcReadRequest = (InternalPlcReadRequest) requestContainer.getRequest(); - + + if (responseMessage.getPayloads().get(0) instanceof CpuServicesPayload){ + return decodeSslReadResponse(responseMessage, requestContainer); + } + VarPayload payload = responseMessage.getPayload(VarPayload.class) .orElseThrow(() -> new PlcProtocolException("No VarPayload supplied")); @@ -836,6 +929,7 @@ private PlcResponse decodeReadResponse(S7ResponseMessage responseMessage, PlcReq // way to know how to interpret the responses is by aligning them with the // items from the request as this information is not returned by the PLC. if (plcReadRequest.getNumberOfFields() != payload.getItems().size()) { + logger.info("Excepcion: " + plcReadRequest.getFieldNames().toString()); throw new PlcProtocolException( "The number of requested items doesn't match the number of returned items"); } @@ -959,6 +1053,32 @@ private PlcResponse decodeReadResponse(S7ResponseMessage responseMessage, PlcReq return new DefaultPlcReadResponse(plcReadRequest, values); } + + private PlcResponse decodeSslReadResponse(S7ResponseMessage responseMessage, PlcRequestContainer requestContainer) throws PlcProtocolException { + InternalPlcReadRequest plcReadRequest = (InternalPlcReadRequest) requestContainer.getRequest(); + + Map> values = new HashMap<>(); + + List payloads = responseMessage.getPayloads(); + payloads.forEach((payload)->{ + CpuServicesPayload s7payload = (CpuServicesPayload) payload;}); + + int index = 0; + for (String requestName : plcReadRequest.getFieldNames()) { + + CpuServicesPayload payload = (CpuServicesPayload) payloads.get(index); + + Pair result = new ImmutablePair<>( + decodeResponseCode(payload.getReturnCode()), + payload.getSslPayload()); + + values.put(requestName, result); + + index++; + } + + return new S7ByteReadResponse(plcReadRequest, values); + } BaseDefaultFieldItem decodeReadResponseBitField(S7Field field, ByteBuf data) { Boolean[] booleans = readAllValues(Boolean.class, field, i -> data.readByte() != 0x00); @@ -1140,6 +1260,7 @@ private PlcResponse decodeWriteResponse(S7ResponseMessage responseMessage, PlcRe private PlcResponse decodeSubscriptionResponse(S7ResponseMessage responseMessage, PlcRequestContainer requestContainer) throws PlcProtocolException { + InternalPlcSubscriptionRequest subsRequest = (InternalPlcSubscriptionRequest) requestContainer.getRequest(); //TODO: Try multiple ALARM_ACK in the same request and multiple EVENT_ID. S7SubscriptionField event = (S7SubscriptionField) subsRequest.getFields().get(0); @@ -1153,9 +1274,35 @@ private PlcResponse decodeSubscriptionResponse(S7ResponseMessage responseMessage //May be only one iteration?: for (S7Payload payload:payloads){ + if (payload instanceof AlarmMessagePayload) { AlarmMessagePayload payloadItem = (AlarmMessagePayload) payload; switch(parameter.getSubFunctionGroup()){ + case MESSAGE_SERVICE:{ + List items = new ArrayList(); + PlcResponseCode responseCode = decodeResponseCode(((AlarmMessagePayload) payload).getReturnCode()); + + if (responseCode == PlcResponseCode.OK) { + subsRequest.getFields().forEach((field)->{ + S7SubscriptionField s7field = (S7SubscriptionField) field; + items.add(s7field.getEventtype()); + }); + }; + + S7DiagnosticSubscriptionHandle handler = new S7DiagnosticSubscriptionHandle( + "MS", + responseMessage.getTpduReference(), + responseCode, + items); + + LinkedHashSet fieldnames = subsRequest.getFieldNames(); + + fieldnames.forEach((fieldname)->{ + values.put(fieldname, new ImmutablePair(responseCode, handler)); + }); + + } + break; case ALARM_ACK:{ List items = payloadItem.getMsg().getMsgItems(); ArrayList eventids = event.getAckalarms(); @@ -1189,35 +1336,53 @@ private PlcResponse decodeSubscriptionResponse(S7ResponseMessage responseMessage default:; } } else if (payload instanceof CpuCyclicServicesResponsePayload) { + CpuCyclicServicesResponsePayload cyclicPayloadItem = (CpuCyclicServicesResponsePayload) payload; // // - logger.info("CpuCyclicServicesResponsePayload: " + subsRequest.getFieldNames().toString()); - List valueitems = cyclicPayloadItem.getItems(); - Map items = new LinkedHashMap(); - int i=0; - if (parameter.getError().getCode() == 0x0000){ - for (String fieldname:subsRequest.getFieldNames()){ - items.put(fieldname, valueitems.get(i)); - i++; + if (cyclicPayloadItem.getItems().size() != 0) { + + List valueitems = cyclicPayloadItem.getItems(); + Map items = new LinkedHashMap(); + int i=0; + if (parameter.getError().getCode() == 0x0000){ + for (String fieldname:subsRequest.getFieldNames()){ + items.put(fieldname, valueitems.get(i)); + i++; + }; }; - }; - - S7CyclicServicesSubscriptionHandle handler = new S7CyclicServicesSubscriptionHandle("UNO", - parameter.getSequenceNumber(), - parameter.getError().getCode(), - items); - - for (String fieldname:subsRequest.getFieldNames()){ - logger.info("*****" + fieldname); - values.put(fieldname, new ImmutablePair(decodeResponseCode(items.get(fieldname).getReturnCode()), handler)); - } - } + + S7CyclicServicesSubscriptionHandle handler = new S7CyclicServicesSubscriptionHandle("UNO", + parameter.getSequenceNumber(), + parameter.getError().getCode(), + items); + // Return quality code for alarm + for (String fieldname:subsRequest.getFieldNames()){ + values.put(fieldname, new ImmutablePair(decodeResponseCode(items.get(fieldname).getReturnCode()), handler)); + } + + + } else { + logger.info("Must return values...?"); + } + + } else { + logger.info("Payload not defined..."); + } } return new DefaultPlcSubscriptionResponse(subsRequest, values); } + private PlcResponse decodeUnSubscriptionResponse(S7ResponseMessage responseMessage, PlcRequestContainer requestContainer) throws PlcProtocolException { + DefaultPlcUnsubscriptionRequest unSubsRequest = (DefaultPlcUnsubscriptionRequest) requestContainer.getRequest(); + //TODO: Multiple parameters. Try with S7400. At this point if we have embedded more parameter will be lost. + CpuServicesResponseParameter parameter = (CpuServicesResponseParameter) responseMessage.getParameters().get(0); + InternalPlcUnsubscriptionRequest request = (InternalPlcUnsubscriptionRequest) requestContainer.getRequest(); + + return new DefaultPlcUnsubscriptionResponse(request); + } + private PlcResponseCode decodeResponseCode(DataTransportErrorCode dataTransportErrorCode) { if (dataTransportErrorCode == null) { return PlcResponseCode.INTERNAL_ERROR; 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 f3c8ed912ae..064858ffa78 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 @@ -26,7 +26,7 @@ Licensed to the Apache Software Foundation (ASF) under one import io.netty.util.concurrent.Future; import io.netty.util.concurrent.PromiseCombiner; import java.lang.reflect.Field; -import java.nio.charset.StandardCharsets; +import java.nio.charset.Charset; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; @@ -64,8 +64,6 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.netty.model.payloads.items.MessageObjectItem; import org.apache.plc4x.java.s7.netty.model.payloads.items.S7AnyVarPayloadItem; import org.apache.plc4x.java.s7.netty.model.payloads.items.VarPayloadItem; -import org.apache.plc4x.java.s7.netty.model.payloads.ssls.SslDataRecord; -import org.apache.plc4x.java.s7.netty.model.payloads.ssls.SslModuleIdentificationDataRecord; import org.apache.plc4x.java.s7.netty.model.types.*; import org.apache.plc4x.java.s7.netty.strategies.S7MessageProcessor; import org.apache.plc4x.java.s7.netty.util.S7SizeHelper; @@ -420,16 +418,23 @@ private void encodeAlarmMessagePayload(AlarmMessagePayload payload, ByteBuf buf) } } - private void encodeCpuCyclicSubscriptionPayload(CpuCyclicServicesRequestPayload payload, ByteBuf buf) { - buf.writeByte(payload.getReturnCode().getCode()); - buf.writeByte(payload.getDataTransportSize().getCode()); - buf.writeShort(payload.getLength()); - buf.writeShort(payload.getItemCount()); - buf.writeByte(payload.getTimeBase().getCode()); - buf.writeByte(payload.getTimeFactor()); - payload.getItems().forEach((anyvar)->{ - encodeS7AnyPayloadItem(anyvar,buf); - }); + private void encodeCpuCyclicSubscriptionPayload(CpuCyclicServicesRequestPayload payload, ByteBuf buf) { + buf.writeByte(payload.getReturnCode().getCode()); + buf.writeByte(payload.getDataTransportSize().getCode()); + buf.writeShort(payload.getLength()); + //Unsuscription + if (payload.getLength() == 2) { + buf.writeByte(payload.getFunction()); + buf.writeByte(payload.getJobId()); + } else { + //Suscription message + buf.writeShort(payload.getItemCount()); + buf.writeByte(payload.getTimeBase().getCode()); + buf.writeByte(payload.getTimeFactor()); + payload.getItems().forEach((anyvar)->{ + encodeS7AnyPayloadItem(anyvar,buf); + }); + }; } private void encodeParameters(S7Message in, ByteBuf buf) throws PlcProtocolException { @@ -655,7 +660,7 @@ protected void decode(ChannelHandlerContext ctx, IsoTPMessage in, List o short userDataLength = userData.readShort(); byte errorClass = 0; byte errorCode = 0; - + if (isResponse) { errorClass = userData.readByte(); errorCode = userData.readByte(); @@ -672,14 +677,21 @@ protected void decode(ChannelHandlerContext ctx, IsoTPMessage in, List o } i += S7SizeHelper.getParameterLength(parameter); } - + List s7Payloads = decodePayloads(userData, isResponse, userDataLength, s7Parameters); - logger.debug("S7 Message with id {} received", tpduReference); - //Case: USER_DATA + //Case: USER_DATA CpuCyclicServicesResponseParameter if (messageType == MessageType.USER_DATA){ - if (s7Parameters.get(0) instanceof CpuServicesResponseParameter){ + if (s7Parameters.get(0) instanceof CpuCyclicServicesResponseParameter){ + CpuCyclicServicesResponseParameter parameter = (CpuCyclicServicesResponseParameter) s7Parameters.get(0); + if (parameter.getSubCycFunctionGroup() == CpuCyclicServicesParameterSubFunctionGroupType.CYCLIC_UNSUBSCRIBE){ + isResponse = true; + } + } + + //TODO: Check for other combinations + if (s7Parameters.get(0) instanceof CpuServicesResponseParameter){ CpuServicesResponseParameter parameter = (CpuServicesResponseParameter) s7Parameters.get(0); if (parameter.getSubFunctionGroup() == CpuServicesParameterSubFunctionGroup.ALARM_ACK){ isResponse = true; @@ -715,7 +727,6 @@ protected void decode(ChannelHandlerContext ctx, IsoTPMessage in, List o if(responseMessage != null) { out.add(responseMessage); - // If this is a USER_DATA packet the probability is high that this is // a response to the identification request, we have to handle that. if(responseMessage.getMessageType() == MessageType.USER_DATA) { @@ -802,6 +813,7 @@ private void handleSetupCommunications(ChannelHandlerContext ctx, SetupCommunica private void handleIdentifyRemote(ChannelHandlerContext ctx, CpuServicesPayload cpuServicesPayload) { controllerType = S7ControllerType.ANY; + /* for (SslDataRecord sslDataRecord : cpuServicesPayload.getSslDataRecords()) { if(sslDataRecord instanceof SslModuleIdentificationDataRecord) { SslModuleIdentificationDataRecord sslModuleIdentificationDataRecord = @@ -810,6 +822,13 @@ private void handleIdentifyRemote(ChannelHandlerContext ctx, CpuServicesPayload controllerType = lookupControllerType(sslModuleIdentificationDataRecord.getArticleNumber()); } } + */ + if (cpuServicesPayload.getSslId() == SslId.MODULE_IDENTIFICATION) { + if ((cpuServicesPayload.getSslIndex() == 0x0000) || (cpuServicesPayload.getSslIndex() == 0x0001)){ + ByteBuf payload = cpuServicesPayload.getSslPayload(); + CharSequence MlfB = payload.getCharSequence(6, 20, Charset.defaultCharset()); + controllerType = lookupControllerType(MlfB.toString()); + } } if(logger.isDebugEnabled()) { logger.debug("Successfully connected to S7: {}", controllerType.name()); @@ -837,7 +856,7 @@ private List decodePayloads(ByteBuf userData, boolean isResponse, sho s7Payloads.add(cpuServicesPayload); } else if (s7Parameter instanceof CpuServicesPushParameter){ S7Payload cpuServicesPayload = decodeCpuServicesPayload((CpuServicesParameter)s7Parameter, userData); - s7Payloads.add(cpuServicesPayload); + s7Payloads.add(cpuServicesPayload); } } return s7Payloads; @@ -947,11 +966,15 @@ private S7Payload decodeCpuServicesPayload(CpuServicesParameter parameter, ByteB break; case CYCLIC_RDREC:; break; - case CYCLIC_TRANSFER: + case CYCLIC_TRANSFER: { + CpuCyclicServicesResponsePayload payload = decodeCyclicServiceResponsePayload(pushparameter, userData); + return payload; + } + case CYCLIC_UNSUBSCRIBE:{ CpuCyclicServicesResponsePayload payload = decodeCyclicServiceResponsePayload(pushparameter, userData); return payload; - case CYCLIC_UNSUBSCRIBE:; - break; + } + default: logger.info("decodeCpuServicesPayload: No Sub Cyc Function Group."); } } } @@ -1124,10 +1147,21 @@ private List decodeReadWriteVarParameter(ByteBuf in, byte numI private CpuServicesPayload decodeReadSslPayload(CpuServicesParameter parameter, ByteBuf userData){ DataTransportErrorCode returnCode = DataTransportErrorCode.valueOf(userData.readByte()); DataTransportSize dataTransportSize = DataTransportSize.valueOf(userData.readByte()); + short length; + if(dataTransportSize != DataTransportSize.OCTET_STRING) { - // TODO: Output an error. + if(dataTransportSize == DataTransportSize.NULL) { + length = userData.readShort(); + if (length == 0x0000) { + return new CpuServicesPayload(returnCode, SslId.NULL, (short) 0x0000); + } else { + // TODO: Output an error. + } + + } } - short length = userData.readShort(); + + length = userData.readShort(); SslId sslId = SslId.valueOf(userData.readShort()); short sslIndex = userData.readShort(); // If the length is 4 there is no `partial list length in bytes` and `partial list count` parameters. @@ -1136,8 +1170,11 @@ private CpuServicesPayload decodeReadSslPayload(CpuServicesParameter parameter, } // If the length is not 4, then it has to be at least 8. else if(length >= 8) { + // TODO: We should probably ensure we don't read more than this. // Skip the partial list length in words. + // TODO: Transfer all Payload to the client app. Use helper class. + /* userData.skipBytes(2); short partialListCount = userData.readShort(); List sslDataRecords = new LinkedList<>(); @@ -1152,12 +1189,16 @@ else if(length >= 8) { sslDataRecords.add(new SslModuleIdentificationDataRecord( index, articleNumber, bgType, moduleOrOsVersion, pgDescriptionFileVersion)); } - return new CpuServicesPayload(returnCode, sslId, sslIndex, sslDataRecords); + */ + ByteBuf payload = Unpooled.copiedBuffer(userData); + + return new CpuServicesPayload(returnCode, sslId, sslIndex, payload); } // In all other cases, it's probably an error. else { // TODO: Output an error. } + return null; } @@ -1484,42 +1525,46 @@ private AlarmMessagePayload decodeMessageServiceAckPayload(CpuServicesParameter private CpuCyclicServicesResponsePayload decodeCyclicServiceResponsePayload(CpuCyclicServicesResponseParameter parameter, ByteBuf userData){ - logger.info("decodeCyclicServiceResponsePayload :\r\n" + ByteBufUtil.prettyHexDump(userData)); + //logger.info("decodeCyclicServiceResponsePayload :\r\n" + ByteBufUtil.prettyHexDump(userData)); DataTransportErrorCode AlarmReturnCode; DataTransportSize AlarmTransportSize; int length; - int itemcount; + int itemcount = 0; + List Values = new LinkedList<>(); //Data section DataTransportErrorCode returnCode = DataTransportErrorCode.valueOf(userData.readByte()); DataTransportSize dataTransportSize = DataTransportSize.valueOf(userData.readByte()); length = userData.readShort(); //Number of bytes - userData.readByte(); //TODO: Sometimes is 0x00 another 0x01, Blinking when I have TIA running - itemcount = (length==0?0x0000:userData.readByte()); - List Values = new LinkedList<>(); - try { - for (int i=0; i < itemcount; i++ ){ - DataTransportErrorCode valueCode = DataTransportErrorCode.valueOf(userData.readByte()); - DataTransportSize valueTransportSize = DataTransportSize.valueOf(userData.readByte()); - - int valueLength = userData.readShort() / 8; - if ((valueLength % 2 != 0) && (userData.isReadable(valueLength+1))) { + + //Check for Unsubscribe + if (length != 0x0000) { + userData.readByte(); //TODO: Sometimes is 0x00 another 0x01, Blinking when I have TIA running + itemcount = (length==0?0x0000:userData.readByte()); + try { + for (int i=0; i < itemcount; i++ ){ + DataTransportErrorCode valueCode = DataTransportErrorCode.valueOf(userData.readByte()); + DataTransportSize valueTransportSize = DataTransportSize.valueOf(userData.readByte()); + + int valueLength = userData.readShort() / 8; + if ((valueLength % 2 != 0) && (userData.isReadable(valueLength+1))) { + + userData.readByte(); //Fill byte for odd number of bytes + } - userData.readByte(); //Fill byte for odd number of bytes - } + ByteBuf Data = userData.readBytes(valueLength); - ByteBuf Data = userData.readBytes(valueLength); - - Values.add(new AssociatedValueItem(valueCode, - valueTransportSize, - valueLength, - Data)); - } - } catch (Exception e) { - logger.info(e.getMessage()); - return null; + Values.add(new AssociatedValueItem(valueCode, + valueTransportSize, + valueLength, + Data)); + } + } catch (Exception e) { + logger.info(e.getMessage()); + return null; + } } - + return new CpuCyclicServicesResponsePayload( returnCode, dataTransportSize, diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuCyclicServicesRequestPayload.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuCyclicServicesRequestPayload.java index 1d1eeacb735..aeffe15cd10 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuCyclicServicesRequestPayload.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuCyclicServicesRequestPayload.java @@ -37,8 +37,11 @@ public class CpuCyclicServicesRequestPayload implements S7Payload { private final int itemCount; private final CpuCyclicServiceTimeBaseType timeBase; private final byte timeFactor; - private final List items; - + private final List items; + //For Cancel Subcription + private final byte function; + private final byte jobId; + public CpuCyclicServicesRequestPayload(DataTransportErrorCode returnCode, DataTransportSize dataTransportSize, int length, @@ -53,8 +56,27 @@ public CpuCyclicServicesRequestPayload(DataTransportErrorCode returnCode, this.timeBase = timeBase; this.timeFactor = timeFactor; this.items = items; + this.function = 0x00; + this.jobId = 0x00; } + + public CpuCyclicServicesRequestPayload(DataTransportErrorCode returnCode, + DataTransportSize dataTransportSize, + int length, + byte function, + byte jobId) { + this.returnCode = returnCode; + this.dataTransportSize = dataTransportSize; + this.length = length; + this.itemCount = 0x00; + this.timeBase = null; + this.timeFactor = 0x00; + this.items = null; + this.function = function; + this.jobId = jobId; + } + public DataTransportErrorCode getReturnCode() { return returnCode; } @@ -83,6 +105,14 @@ public List getItems() { return items; } + public byte getFunction() { + return function; + } + + public byte getJobId() { + return jobId; + } + @Override public ParameterType getType() { return ParameterType.CPU_SERVICES; diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuServicesPayload.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuServicesPayload.java index 43a33abfe97..8f1e1b1a608 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuServicesPayload.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/CpuServicesPayload.java @@ -18,6 +18,7 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.s7.netty.model.payloads; +import io.netty.buffer.ByteBuf; import java.util.Collections; import java.util.List; import org.apache.plc4x.java.s7.netty.model.payloads.ssls.SslDataRecord; @@ -31,12 +32,14 @@ public class CpuServicesPayload implements S7Payload { private SslId sslId; private short sslIndex; private List sslDataRecords; + private ByteBuf sslPayload; public CpuServicesPayload(DataTransportErrorCode returnCode, SslId sslId, short sslIndex) { this.returnCode = returnCode; this.sslId = sslId; this.sslIndex = sslIndex; this.sslDataRecords = Collections.emptyList(); + this.sslPayload = null; } public CpuServicesPayload(DataTransportErrorCode returnCode, SslId sslId, short sslIndex, List sslDataRecords) { @@ -44,7 +47,16 @@ public CpuServicesPayload(DataTransportErrorCode returnCode, SslId sslId, short this.sslId = sslId; this.sslIndex = sslIndex; this.sslDataRecords = sslDataRecords; + this.sslPayload = null; } + + public CpuServicesPayload(DataTransportErrorCode returnCode, SslId sslId, short sslIndex, ByteBuf sslPayload) { + this.returnCode = returnCode; + this.sslId = sslId; + this.sslIndex = sslIndex; + this.sslDataRecords = null; + this.sslPayload = sslPayload; + } @Override public ParameterType getType() { @@ -67,4 +79,8 @@ public List getSslDataRecords() { return sslDataRecords; } + public ByteBuf getSslPayload() { + return sslPayload; + } + } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/SslId.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/SslId.java index f8fc6c30512..9dbf00a9bcb 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/SslId.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/SslId.java @@ -18,11 +18,10 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.s7.netty.model.types; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.HashMap; import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * An SSL ID is a short value build up the following way: @@ -44,12 +43,14 @@ public enum SslId { USER_MEMORY_AREAS((short) 0x0013), SYSTEM_AREAS((short) 0x0014), BLOCK_TYPES((short) 0x0015), + COMPONENT_IDENTIFICATION((short) 0x001c), INTERRUPT_STATUS((short) 0x0022), ASSIGNMENT_BETWEEN_PROCESS_IMAGE_PARTITIONS_AND_OBS((short) 0x0025), COMPUTATION_STATUS_DATA((short) 0x0032), H_CPU_GROUP_INFORMATION((short) 0x0071), STATUS_OF_THE_MODULE_LEDS((short) 0x0074), SWITCHED_DP_SLAVES_IN_THE_H_SYSTEM((short) 0x0075), + DP_MASTER_SYSTEM_INFORMATION((short) 0x0090), MODULE_STATUS_INFORMATION((short) 0x0091), RACK_STATION_STATUS_INFORMATION_1((short) 0x0092), RACK_STATION_STATUS_INFORMATION_2((short) 0x0094), @@ -60,11 +61,11 @@ public enum SslId { MODULE_DIAGNOSTIC_INFORMATION_DATA_RECORD_0((short) 0x00B1), MODULE_DIAGNOSTIC_INFORMATION_DATA_RECORD_1_GEOGRAPHICAL_ADDRESS((short) 0x00B2), MODULE_DIAGNOSTIC_INFORMATION_DATA_RECORD_1_LOGICAL_ADDRESS((short) 0x00B3), - DIAGNOSTIC_DATA_OF_A_DP_SLAVE((short) 0x00B4), - + DIAGNOSTIC_DATA_OF_A_DP_SLAVE((short) 0x00B4), IDENTIFICATION_OF_ALL_COMPONENTS((short) 0x001c), INFORMATION_ABOUT_COMMUNICATION_UNIT((short) 0x0131), - CURRENT_MODE_TRANSITION((short) 0x0424); + CURRENT_MODE_TRANSITION((short) 0x0424), + NULL((short) 0x0000); private static final Logger logger = LoggerFactory.getLogger(SslId.class); diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7PlcFieldHandler.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7PlcFieldHandler.java index dd65567c259..2799e49ce6f 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7PlcFieldHandler.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7PlcFieldHandler.java @@ -18,19 +18,19 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.s7.netty.util; -import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; -import org.apache.plc4x.java.api.exceptions.PlcRuntimeException; -import org.apache.plc4x.java.api.model.PlcField; -import org.apache.plc4x.java.base.connection.DefaultPlcFieldHandler; -import org.apache.plc4x.java.base.messages.items.*; -import org.apache.plc4x.java.s7.model.S7Field; - import java.lang.reflect.InvocationTargetException; import java.math.BigInteger; import java.nio.charset.StandardCharsets; import java.util.BitSet; import java.util.LinkedList; import java.util.List; +import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; +import org.apache.plc4x.java.api.exceptions.PlcRuntimeException; +import org.apache.plc4x.java.api.model.PlcField; +import org.apache.plc4x.java.base.connection.DefaultPlcFieldHandler; +import org.apache.plc4x.java.base.messages.items.*; +import org.apache.plc4x.java.s7.model.S7Field; +import org.apache.plc4x.java.s7.model.S7SslField; public class S7PlcFieldHandler extends DefaultPlcFieldHandler { @@ -39,6 +39,9 @@ public PlcField createField(String fieldQuery) { if (S7Field.matches(fieldQuery)) { return S7Field.of(fieldQuery); } + if (S7SslField.matches(fieldQuery)) { + return S7SslField.of(fieldQuery); + } throw new PlcInvalidFieldException(fieldQuery); } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7ByteReadResponse.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7ByteReadResponse.java new file mode 100644 index 00000000000..27f27c966d2 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7ByteReadResponse.java @@ -0,0 +1,480 @@ +/* +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.protocol; + +import io.netty.buffer.ByteBuf; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.Collection; +import java.util.Map; +import java.util.Objects; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; +import org.apache.plc4x.java.api.exceptions.PlcRuntimeException; +import org.apache.plc4x.java.api.model.PlcField; +import org.apache.plc4x.java.api.types.PlcResponseCode; +import org.apache.plc4x.java.base.messages.InternalPlcReadRequest; +import org.apache.plc4x.java.base.messages.InternalPlcReadResponse; +import org.apache.plc4x.java.base.messages.items.BaseDefaultFieldItem; + +/** + * + * @author cgarcia + */ +public class S7ByteReadResponse implements InternalPlcReadResponse{ + + private final InternalPlcReadRequest request; + private final Map> values; + + public S7ByteReadResponse(InternalPlcReadRequest request, Map> values) { + this.request = request; + this.values = values; + } + + /** + * + * @return + */ + @Override + public Map> getValues() { + return null; + } + + public Map> getByteBufValues() { + return values; + } + + public ByteBuf getByteBufValues(String name) { + ByteBuf bytebuf = getByteBufInternal(name); + return bytebuf; + } + + @Override + public InternalPlcReadRequest getRequest() { + return request; + } + + @Override + public int getNumberOfValues(String name) { + ByteBuf bytebuf = getByteBufInternal(name); + return bytebuf.capacity(); + } + + @Override + public Object getObject(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Object getObject(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllObjects(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBoolean(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBoolean(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Boolean getBoolean(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Boolean getBoolean(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllBooleans(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidByte(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidByte(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Byte getByte(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Byte getByte(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllBytes(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidShort(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidShort(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Short getShort(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Short getShort(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllShorts(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Integer getInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Integer getInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllIntegers(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBigInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBigInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BigInteger getBigInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BigInteger getBigInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllBigIntegers(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidLong(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidLong(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Long getLong(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Long getLong(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllLongs(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidFloat(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidFloat(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Float getFloat(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Float getFloat(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllFloats(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDouble(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDouble(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Double getDouble(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Double getDouble(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllDoubles(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBigDecimal(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBigDecimal(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BigDecimal getBigDecimal(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BigDecimal getBigDecimal(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllBigDecimals(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidString(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidString(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getString(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getString(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllStrings(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalTime getTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalTime getTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllTimes(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDate(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDate(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalDate getDate(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalDate getDate(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllDates(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDateTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDateTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalDateTime getDateTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalDateTime getDateTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllDateTimes(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidByteArray(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidByteArray(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Byte[] getByteArray(String name) { + ByteBuf bytebuf = getByteBufInternal(name); + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Byte[] getByteArray(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllByteArrays(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getFieldNames() { + return request.getFieldNames(); + } + + @Override + public PlcField getField(String name) { + return request.getField(name); + } + + @Override + public PlcResponseCode getResponseCode(String name) { + if (values.get(name) == null) { + throw new PlcInvalidFieldException(name); + } + return values.get(name).getKey(); + } + + protected ByteBuf getByteBufInternal(String name) { + Objects.requireNonNull(name, "Name argument required"); + // If this field doesn't exist, ignore it. + if (values.get(name) == null) { + throw new PlcInvalidFieldException(name); + } + if (values.get(name).getKey() != PlcResponseCode.OK) { + throw new PlcRuntimeException("Field '" + name + "' could not be fetched, response was " + values.get(name).getKey()); + } + // No need to check for "null" as this is already captured by the constructors. + return values.get(name).getValue(); + } + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7CyclicServicesSubscriptionHandle.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7CyclicServicesSubscriptionHandle.java index 81d20ff8915..c0137eb577d 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7CyclicServicesSubscriptionHandle.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7CyclicServicesSubscriptionHandle.java @@ -24,14 +24,14 @@ Licensed to the Apache Software Foundation (ASF) under one import java.util.function.Consumer; import org.apache.plc4x.java.api.messages.PlcSubscriptionEvent; import org.apache.plc4x.java.api.model.PlcConsumerRegistration; -import org.apache.plc4x.java.api.model.PlcSubscriptionHandle; +import org.apache.plc4x.java.base.model.InternalPlcSubscriptionHandle; import org.apache.plc4x.java.s7.netty.model.payloads.items.AssociatedValueItem; /** * * @author cgarcia */ -public class S7CyclicServicesSubscriptionHandle implements PlcSubscriptionHandle { +public class S7CyclicServicesSubscriptionHandle implements InternalPlcSubscriptionHandle { Set> consumers = new HashSet<>(); //CyClic Services information hanler diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7DiagnosticSubscriptionHandle.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7DiagnosticSubscriptionHandle.java index 139242a2288..e681537d9b8 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7DiagnosticSubscriptionHandle.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7DiagnosticSubscriptionHandle.java @@ -24,19 +24,53 @@ Licensed to the Apache Software Foundation (ASF) under one import java.util.function.Consumer; import org.apache.plc4x.java.api.messages.PlcSubscriptionEvent; import org.apache.plc4x.java.api.model.PlcConsumerRegistration; -import org.apache.plc4x.java.api.model.PlcSubscriptionHandle; +import org.apache.plc4x.java.api.types.PlcResponseCode; +import org.apache.plc4x.java.base.model.InternalPlcSubscriptionHandle; import org.apache.plc4x.java.s7.netty.model.types.SubscribedEventType; /** * * @author cgarcia */ -public class S7DiagnosticSubscriptionHandle implements PlcSubscriptionHandle { +public class S7DiagnosticSubscriptionHandle implements InternalPlcSubscriptionHandle{ Set> consumers = new HashSet<>(); - //Diagnostic events - List subscribedevents; - + //CyClic Services information hanler + private final String fieldName; //Subscription id from the request + private final short jobId; //Job-Id from cyclic subscriotion + private final PlcResponseCode error; //Register the error from the suscription. + private final List subscribedevents; //Diagnostic events + + public S7DiagnosticSubscriptionHandle(String fieldName, + short jobId, + PlcResponseCode error, + List subscribedevents) { + this.fieldName = fieldName; + this.jobId = jobId; + this.error = error; + this.subscribedevents = subscribedevents; + } + + public String getFieldName() { + return fieldName; + } + + public short getJobId() { + return jobId; + } + + public PlcResponseCode getError() { + return error; + } + + public List getSubscribedevents() { + return subscribedevents; + } + + public Set> getConsumers() { + return consumers; + } + @Override public PlcConsumerRegistration register(Consumer consumer) { consumers.add(consumer); diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Alarm8Event.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Alarm8Event.java new file mode 100644 index 00000000000..d6664a37e94 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Alarm8Event.java @@ -0,0 +1,28 @@ +/* +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.protocol.event; + +/** + * + * @author cgarcia + */ +public class S7Alarm8Event { + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Alarm8pEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Alarm8pEvent.java new file mode 100644 index 00000000000..e4aaec2aad8 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Alarm8pEvent.java @@ -0,0 +1,28 @@ +/* +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.protocol.event; + +/** + * + * @author cgarcia + */ +public class S7Alarm8pEvent { + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmDEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmDEvent.java new file mode 100644 index 00000000000..f8e57d26b7a --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmDEvent.java @@ -0,0 +1,28 @@ +/* +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.protocol.event; + +/** + * + * @author cgarcia + */ +public class S7AlarmDEvent { + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmDQEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmDQEvent.java new file mode 100644 index 00000000000..a8dc38654e8 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmDQEvent.java @@ -0,0 +1,28 @@ +/* +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.protocol.event; + +/** + * + * @author cgarcia + */ +public class S7AlarmDQEvent { + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmEvent.java new file mode 100644 index 00000000000..a98d7465aa2 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmEvent.java @@ -0,0 +1,14 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.apache.plc4x.java.s7.protocol.event; + +/** + * + * @author cgarcia + */ +public class S7AlarmEvent { + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmSEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmSEvent.java new file mode 100644 index 00000000000..0c2542ac1f2 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmSEvent.java @@ -0,0 +1,434 @@ +/* +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.protocol.event; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.Collection; +import org.apache.plc4x.java.api.messages.PlcReadRequest; +import org.apache.plc4x.java.api.model.PlcField; +import org.apache.plc4x.java.api.types.PlcResponseCode; + +/** + * + * @author cgarcia + */ +public class S7AlarmSEvent implements S7Event { + + @Override + public Instant getTimestamp() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public PlcReadRequest getRequest() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public int getNumberOfValues(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Object getObject(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Object getObject(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllObjects(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidBoolean(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidBoolean(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Boolean getBoolean(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Boolean getBoolean(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllBooleans(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidByte(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidByte(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Byte getByte(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Byte getByte(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllBytes(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidShort(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidShort(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Short getShort(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Short getShort(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllShorts(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Integer getInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Integer getInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllIntegers(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidBigInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidBigInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public BigInteger getBigInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public BigInteger getBigInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllBigIntegers(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidLong(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidLong(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Long getLong(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Long getLong(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllLongs(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidFloat(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidFloat(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Float getFloat(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Float getFloat(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllFloats(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidDouble(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidDouble(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Double getDouble(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Double getDouble(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllDoubles(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidBigDecimal(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidBigDecimal(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public BigDecimal getBigDecimal(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public BigDecimal getBigDecimal(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllBigDecimals(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidString(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidString(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String getString(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String getString(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllStrings(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public LocalTime getTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public LocalTime getTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllTimes(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidDate(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidDate(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public LocalDate getDate(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public LocalDate getDate(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllDates(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidDateTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidDateTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public LocalDateTime getDateTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public LocalDateTime getDateTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllDateTimes(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidByteArray(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidByteArray(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Byte[] getByteArray(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Byte[] getByteArray(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllByteArrays(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getFieldNames() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public PlcField getField(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public PlcResponseCode getResponseCode(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmSQEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmSQEvent.java new file mode 100644 index 00000000000..f87189d3f00 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmSQEvent.java @@ -0,0 +1,28 @@ +/* +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.protocol.event; + +/** + * + * @author cgarcia + */ +public class S7AlarmSQEvent { + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Event.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Event.java new file mode 100644 index 00000000000..7a509ef22b0 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Event.java @@ -0,0 +1,30 @@ +/* +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.protocol.event; + +import org.apache.plc4x.java.api.messages.PlcSubscriptionEvent; + +/** + * + * @author cgarcia + */ +public interface S7Event extends PlcSubscriptionEvent{ + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7ModeEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7ModeEvent.java new file mode 100644 index 00000000000..869faf4f826 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7ModeEvent.java @@ -0,0 +1,487 @@ +/* +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.protocol.event; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import org.apache.plc4x.java.api.messages.PlcReadRequest; +import org.apache.plc4x.java.api.model.PlcField; +import org.apache.plc4x.java.api.types.PlcResponseCode; +import org.apache.plc4x.java.s7.netty.model.params.CpuDiagnosticPushParameter; +import org.apache.plc4x.java.s7.netty.model.types.CpuCurrentModeType; +import org.apache.plc4x.java.s7.netty.model.types.CpuUserDataMethodType; +import org.apache.plc4x.java.s7.netty.model.types.CpuUserDataParameterFunctionGroupType; +import org.apache.plc4x.java.s7.netty.model.types.CpuUserDataParameterType; + +/** + * + * @author cgarcia + */ +public class S7ModeEvent implements S7Event { + + public static final String METHOD = "METHOD"; + public static final String TYPE = "TYPE"; + public static final String FUNCTION = "FUNCTION"; + public static final String CURRENT_MODE = "CURRENT_MODE"; + + private final Instant timeStamp; + private Map map = new HashMap(); + + public S7ModeEvent(Instant timeStamp, CpuDiagnosticPushParameter parameter) { + map.put(METHOD, parameter.getMethod()); + map.put(TYPE, parameter.getParameterType()); + map.put(FUNCTION, parameter.getParameterFunction()); + map.put(CURRENT_MODE, parameter.getCurrentMode()); + this.timeStamp = timeStamp; + } + + @Override + public Instant getTimestamp() { + return timeStamp; + } + + @Override + public PlcReadRequest getRequest() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getNumberOfValues(String name) { + return 0x01; + } + + @Override + public Object getObject(String name) { + Object object = map.get(name); + return object; + } + + @Override + public Object getObject(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllObjects(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBoolean(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBoolean(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Boolean getBoolean(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Boolean getBoolean(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllBooleans(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidByte(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidByte(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Byte getByte(String name) { + Object object = map.get(name); + if (object != null) { + if (object instanceof CpuUserDataMethodType){ + return ((CpuUserDataMethodType) object).getCode(); + } else if (object instanceof CpuUserDataParameterType) { + return ((CpuUserDataParameterType) object).getCode(); + } else if (object instanceof CpuUserDataParameterFunctionGroupType) { + return ((CpuUserDataParameterFunctionGroupType) object).getCode(); + } else if (object instanceof CpuCurrentModeType) { + return ((CpuCurrentModeType) object).getCode(); + } + } + return 0x00; + } + + @Override + public Byte getByte(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllBytes(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidShort(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidShort(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Short getShort(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Short getShort(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllShorts(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Integer getInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Integer getInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllIntegers(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBigInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBigInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BigInteger getBigInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BigInteger getBigInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllBigIntegers(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidLong(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidLong(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Long getLong(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Long getLong(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllLongs(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidFloat(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidFloat(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Float getFloat(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Float getFloat(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllFloats(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDouble(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDouble(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Double getDouble(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Double getDouble(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllDoubles(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBigDecimal(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBigDecimal(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BigDecimal getBigDecimal(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BigDecimal getBigDecimal(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllBigDecimals(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidString(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidString(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getString(String name) { + Object object = map.get(name); + if (object != null) { + if (object instanceof CpuUserDataMethodType){ + return ((CpuUserDataMethodType) object).getEvent(); + } else if (object instanceof CpuUserDataParameterType) { + return ((CpuUserDataParameterType) object).getEvent(); + } else if (object instanceof CpuUserDataParameterFunctionGroupType) { + return ((CpuUserDataParameterFunctionGroupType) object).getEvent(); + } else if (object instanceof CpuCurrentModeType) { + return ((CpuCurrentModeType) object).getEvent(); + } + } + return null; + } + + @Override + public String getString(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllStrings(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalTime getTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalTime getTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllTimes(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDate(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDate(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalDate getDate(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalDate getDate(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllDates(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDateTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDateTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalDateTime getDateTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalDateTime getDateTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllDateTimes(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidByteArray(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidByteArray(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Byte[] getByteArray(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Byte[] getByteArray(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllByteArrays(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getFieldNames() { + return map.keySet(); + } + + @Override + public PlcField getField(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public PlcResponseCode getResponseCode(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String toString() { + return "S7ModeEvent{" + "timeStamp=" + timeStamp + ", map=" + map + '}'; + } + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Notify8pEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Notify8pEvent.java new file mode 100644 index 00000000000..9afcf2fa86e --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Notify8pEvent.java @@ -0,0 +1,28 @@ +/* +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.protocol.event; + +/** + * + * @author cgarcia + */ +public class S7Notify8pEvent { + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7NotifyEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7NotifyEvent.java new file mode 100644 index 00000000000..56e27c15e73 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7NotifyEvent.java @@ -0,0 +1,14 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.apache.plc4x.java.s7.protocol.event; + +/** + * + * @author cgarcia + */ +public class S7NotifyEvent { + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7SysEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7SysEvent.java new file mode 100644 index 00000000000..c24a18aa223 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7SysEvent.java @@ -0,0 +1,477 @@ +/* +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.protocol.event; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneOffset; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import org.apache.plc4x.java.api.messages.PlcReadRequest; +import org.apache.plc4x.java.api.model.PlcField; +import org.apache.plc4x.java.api.types.PlcResponseCode; +import org.apache.plc4x.java.s7.netty.model.payloads.items.CpuDiagnosticMessageItem; + +/** + * + * @author cgarcia + */ +public class S7SysEvent implements S7Event{ + + public static final String EVENT_ID = "EVENT_ID"; + public static final String PRIORITY_CLASS = "PRIORITY_CLASS"; + public static final String OB_NUMBER = "OB_NUMBER"; + public static final String DAT_ID = "DAT_ID"; + public static final String INFO1 = "INFO1"; + public static final String INFO2 = "INFO2"; + + private final Instant timeStamp; + private Map map = new HashMap(); + + public S7SysEvent(CpuDiagnosticMessageItem item) { + map.put(EVENT_ID, item.getEventID()); + map.put(PRIORITY_CLASS, item.getPriorityClass()); + map.put(OB_NUMBER, item.getObNumber()); + map.put(DAT_ID, item.getDatID()); + map.put(INFO1, item.getInfo1()); + map.put(INFO2, item.getInfo2()); + this.timeStamp = item.getTimeStamp().toInstant(ZoneOffset.UTC); + } + + @Override + public Instant getTimestamp() { + return timeStamp; + } + + @Override + public PlcReadRequest getRequest() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getNumberOfValues(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Object getObject(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Object getObject(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllObjects(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBoolean(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBoolean(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Boolean getBoolean(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Boolean getBoolean(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllBooleans(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidByte(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidByte(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Byte getByte(String name) { + Object object = map.get(name); + if (object instanceof Byte){ + return (Byte) object; + } + return null; + } + + @Override + public Byte getByte(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllBytes(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidShort(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidShort(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Short getShort(String name) { + Object object = map.get(name); + if (object instanceof Short){ + return (Short) object; + } + return null; + } + + @Override + public Short getShort(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllShorts(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Integer getInteger(String name) { + Object object = map.get(name); + if (object instanceof Integer){ + return (Integer) object; + } + return null; + } + + @Override + public Integer getInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllIntegers(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBigInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBigInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BigInteger getBigInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BigInteger getBigInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllBigIntegers(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidLong(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidLong(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Long getLong(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Long getLong(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllLongs(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidFloat(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidFloat(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Float getFloat(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Float getFloat(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllFloats(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDouble(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDouble(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Double getDouble(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Double getDouble(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllDoubles(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBigDecimal(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBigDecimal(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BigDecimal getBigDecimal(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BigDecimal getBigDecimal(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllBigDecimals(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidString(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidString(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getString(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getString(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllStrings(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalTime getTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalTime getTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllTimes(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDate(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDate(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalDate getDate(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalDate getDate(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllDates(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDateTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDateTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalDateTime getDateTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalDateTime getDateTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllDateTimes(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidByteArray(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidByteArray(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Byte[] getByteArray(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Byte[] getByteArray(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllByteArrays(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getFieldNames() { + return map.keySet(); + } + + @Override + public PlcField getField(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public PlcResponseCode getResponseCode(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String toString() { + return "S7SysEvent{" + "timeStamp=" + timeStamp + ", map=" + map + '}'; + } + + + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7UserEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7UserEvent.java new file mode 100644 index 00000000000..ed5ffbe9801 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7UserEvent.java @@ -0,0 +1,28 @@ +/* +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.protocol.event; + +/** + * + * @author cgarcia + */ +public class S7UserEvent { + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7DiagnosticEventId.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7DiagnosticEventId.java index 087ae85d53b..741ac4417e6 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7DiagnosticEventId.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7DiagnosticEventId.java @@ -23,7 +23,32 @@ Licensed to the Apache Software Foundation (ASF) under one import java.util.Map; /** - * + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * |15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * \__________/\__________/\____________________/ + * Event class IDs Event number + * + * Event Class: + * 1 Standard OB Events + * 2 Synchronous errors + * 3 Asynchronous errors + * 4 Mode transition + * 5 Run-time events + * 6 Communications events + * 7 Events for fail-safe and fault tolerant systems + * 8 Standardized diagnostic data on modules + * 9 Predefined user events + * A,B Freely definable events + * C,D,E Reserved + * F Events for modules other than CPUs (for example, CPs, FMs) + * + * IDs (Bit) + * 8 0:Event leaving state, 1:Event entering state + * 9 1:Entry in diagnostic buffer + * 10 1:Internal error + * 11 1:External error + * * @author cgarcia */ public enum S7DiagnosticEventId { @@ -37,6 +62,8 @@ public enum S7DiagnosticEventId { EVENTID_0x115A((short) 0x115A, "Manufacturer interrupt for PROFINET IO"), EVENTID_0x115B((short) 0x115B, "IO: Profile-specific interrupt"), EVENTID_0x116A((short) 0x116A, "Technology synchronization interrupt"), + + //Event Class 1 - Standard OB Events EVENTID_0x1381((short) 0x1381, "Request for manual warm restart"), EVENTID_0x1382((short) 0x1382, "Request for automatic warm restart"), EVENTID_0x1383((short) 0x1383, "Request for manual hot restart"), @@ -49,6 +76,8 @@ public enum S7DiagnosticEventId { EVENTID_0x138B((short) 0x138B, "Master CPU: request for automatic warm restart"), EVENTID_0x138C((short) 0x138C, "Standby CPU: request for manual hot restart"), EVENTID_0x138D((short) 0x138D, "Standby CPU: request for automatic hot restart"), + + //Event Class 2 - Synchronous Errors EVENTID_0x2521((short) 0x2521, "BCD conversion error"), EVENTID_0x2522((short) 0x2522, "Area length error when reading"), EVENTID_0x2523((short) 0x2523, "Area length error when writing"), @@ -71,9 +100,9 @@ public enum S7DiagnosticEventId { EVENTID_0x253F((short) 0x253F, "SFB not loaded"), EVENTID_0x2942((short) 0x2942, "I/O access error, reading"), EVENTID_0x2943((short) 0x2943, "I/O access error, writing"), - EVENTID_0x3267((short) 0x3267, "End of module reconfiguration"), - EVENTID_0x3367((short) 0x3367, "Start of module reconfiguration"), - EVENTID_0x34A4((short) 0x34A4, "PROFInet Interface DB can be addressed again"), + + + //Event Class 3 - Asynchronous Errors EVENTID_0x3501((short) 0x3501, "Cycle time exceeded"), EVENTID_0x3502((short) 0x3502, "User interface (OB or FRB) request error"), EVENTID_0x3503((short) 0x3503, "Delay too long processing a priority class"), @@ -174,7 +203,9 @@ public enum S7DiagnosticEventId { EVENTID_0x39CD((short) 0x39CD, "PROFINET IO station operational again, but expected configuration does not match actual configuration"), EVENTID_0x39CE((short) 0x39CE, "PROFINET IO station operational again, but error(s) in module parameter assignment"), EVENTID_0x42F3((short) 0x42F3, "Checksum error detected and corrected by the operating system"), - EVENTID_0x42F4((short) 0x42F4, "Standby CPU: connection/update via SFC90 is locked in the master CPU"), + + + //Event Class 4 - Stop Events and Other Mode Changes EVENTID_0x4300((short) 0x4300, "Backed-up power on"), EVENTID_0x4301((short) 0x4301, "Mode transition from STOP to STARTUP"), EVENTID_0x4302((short) 0x4302, "Mode transition from STARTUP to RUN"), @@ -295,15 +326,17 @@ public enum S7DiagnosticEventId { EVENTID_0x49D2((short) 0x49D2, "Standby CPU changed to STOP due to STOP on the master CPU during link-up"), EVENTID_0x49D4((short) 0x49D4, "STOP on a master, since partner CPU is also a master (link-up error)"), EVENTID_0x49D7((short) 0x49D7, "LINK-UP rejected due to change in user program or in configuration"), - EVENTID_0x510F((short) 0x510F, "A problem as occurred with WinLC. This problem has caused the CPU to go into STOP mode or has caused a fault in the CPU"), + EVENTID_0x42F4((short) 0x42F4, "Standby CPU: connection/update via SFC90 is locked in the master CPU"), + + //Event Class 5 - Mode Run-time Events EVENTID_0x530D((short) 0x530D, "New startup information in the STOP mode"), + EVENTID_0x510F((short) 0x510F, "A problem as occurred with WinLC. This problem has caused the CPU to go into STOP mode or has caused a fault in the CPU"), EVENTID_0x5311((short) 0x5311, "Startup despite Not Ready message from module(s)"), EVENTID_0x5371((short) 0x5371, "Distributed I/Os: end of the synchronization with a DP master"), EVENTID_0x5380((short) 0x5380, "Diagnostic buffer entries of interrupt and asynchronous errors disabled"), EVENTID_0x5395((short) 0x5395, "Distributed I/Os: reset of a DP master"), EVENTID_0x53A2((short) 0x53A2, "Download of technology firmware successful"), EVENTID_0x53A4((short) 0x53A4, "Download of technology DB not successful"), - EVENTID_0x53FF((short) 0x53FF, "Reset to factory setting"), EVENTID_0x5445((short) 0x5445, "Start of System reconfiguration in RUN mode"), EVENTID_0x5481((short) 0x5481, "All licenses for runtime software are complete again"), EVENTID_0x5498((short) 0x5498, "No more inconsistency with DP master systems due to CiR"), @@ -331,7 +364,11 @@ public enum S7DiagnosticEventId { EVENTID_0x59A0((short) 0x59A0, "The interrupt can not be associated in the CPU"), EVENTID_0x59A1((short) 0x59A1, "Configuration error in the integrated technology"), EVENTID_0x59A3((short) 0x59A3, "Error when downloading the integrated technology"), - EVENTID_0x6253((short) 0x6253, "Firmware update: End of firmware download over the network"), + EVENTID_0x53FF((short) 0x53FF, "Reset to factory setting"), + + + + //Event Class 6 - Communication Events EVENTID_0x6316((short) 0x6316, "Interface error when starting programmable controller"), EVENTID_0x6353((short) 0x6353, "Firmware update: Start of firmware download over the network"), EVENTID_0x6390((short) 0x6390, "Formatting of Micro Memory Card complete"), @@ -370,11 +407,14 @@ public enum S7DiagnosticEventId { EVENTID_0x6549((short) 0x6549, "Structure error in block"), EVENTID_0x6550((short) 0x6550, "A block has an error in the CRC"), EVENTID_0x6551((short) 0x6551, "A block has no CRC"), + EVENTID_0x6253((short) 0x6253, "Firmware update: End of firmware download over the network"), EVENTID_0x6560((short) 0x6560, "SCAN overflow"), EVENTID_0x6805((short) 0x6805, "Resource problem on configured connections, eliminated"), EVENTID_0x6881((short) 0x6881, "Interface error leaving state"), EVENTID_0x6905((short) 0x6905, "Resource problem on configured connections"), EVENTID_0x6981((short) 0x6981, "Interface error entering state"), + + //Event Class 7 - H/F Events EVENTID_0x72A2((short) 0x72A2, "Failure of a DP master or a DP master system"), EVENTID_0x72A3((short) 0x72A3, "Redundancy restored on the DP slave"), EVENTID_0x72DB((short) 0x72DB, "Safety program: safety mode disabled"), @@ -448,17 +488,168 @@ public enum S7DiagnosticEventId { EVENTID_0x79E5((short) 0x79E5, "F-I/O device passivated"), EVENTID_0x79E6((short) 0x79E6, "Inconsistent safety program"), EVENTID_0x79E7((short) 0x79E7, "Simulation block (F system block) loaded"), + EVENTID_0x73E8((short) 0x73E8, "Consistency of the safety program verified by testing"), + EVENTID_0x73E9((short) 0x73E9, "Consistency of the safety program cannot be checked"), + + //Event Class 8 - Diagnostic Events for Modules + EVENTID_0x8x00((short) 0x8000, "Module fault/OK"), + EVENTID_0x8x01((short) 0x8001, "Internal error"), + EVENTID_0x8x02((short) 0x8002, "External error"), + EVENTID_0x8x03((short) 0x8003, "Channel error"), + EVENTID_0x8x04((short) 0x8004, "External error"), + EVENTID_0x8x05((short) 0x8005, "No front connector"), + EVENTID_0x8x06((short) 0x8006, "No parameter assignment"), + EVENTID_0x8x07((short) 0x8007, "Incorrect parameters in module"), + EVENTID_0x8x30((short) 0x8030, "User submodule incorrect/not found"), + EVENTID_0x8x31((short) 0x8031, "Communication problem"), + EVENTID_0x8x32((short) 0x8032, "Operating mode: RUN/STOP (STOP: entering state, RUN: leaving state)"), + EVENTID_0x8x33((short) 0x8033, "Time monitoring responded (watchdog)"), + EVENTID_0x8x34((short) 0x8034, "Internal module power failure"), + EVENTID_0x8x35((short) 0x8035, "BATTF: battery exhausted"), + EVENTID_0x8x36((short) 0x8036, "Total backup failed"), + EVENTID_0x8x40((short) 0x8040, "Expansion rack failed"), + EVENTID_0x8x41((short) 0x8041, "Processor failure"), + EVENTID_0x8x42((short) 0x8042, "EPROM error"), + EVENTID_0x8x43((short) 0x8043, "RAM error"), + EVENTID_0x8x44((short) 0x8044, "ADC/DAC error"), + EVENTID_0x8x45((short) 0x8045, "Fuse blown"), + EVENTID_0x8x46((short) 0x8046, "Hardware interrupt lost"), + EVENTID_0x8x50((short) 0x8050, "Configuration/parameter assignment error. Analog input"), + EVENTID_0x8x51((short) 0x8051, "Common mode error"), + EVENTID_0x8x52((short) 0x8052, "Short circuit to phase"), + EVENTID_0x8x53((short) 0x8053, "Short circuit to ground"), + EVENTID_0x8x54((short) 0x8054, "Wire break"), + EVENTID_0x8x55((short) 0x8055, "Reference channel error"), + EVENTID_0x8x56((short) 0x8056, "Below measuring range"), + EVENTID_0x8x57((short) 0x8057, "Above measuring range"), + EVENTID_0x8x60((short) 0x8060, "Configuration/parameter assignment error. Analog output"), + EVENTID_0x8x61((short) 0x8061, "Common mode error"), + EVENTID_0x8x62((short) 0x8062, "Short circuit to phase"), + EVENTID_0x8x63((short) 0x8063, "Short circuit to ground"), + EVENTID_0x8x64((short) 0x8064, "Wire break"), + EVENTID_0x8x66((short) 0x8066, "No load voltage"), + EVENTID_0x8x70((short) 0x8070, "Configuration/parameter assignment error. Digital input"), + EVENTID_0x8x71((short) 0x8071, "Chassis ground fault"), + EVENTID_0x8x72((short) 0x8072, "Short circuit to phase (sensor)"), + EVENTID_0x8x73((short) 0x8073, "Short circuit to ground (sensor)"), + EVENTID_0x8x74((short) 0x8074, "Wire break"), + EVENTID_0x8x75((short) 0x8075, "No sensor power supply"), + EVENTID_0x8x80((short) 0x8080, "Configuration/parameter assignment error. Digital output"), + EVENTID_0x8x81((short) 0x8081, "Chassis ground fault"), + EVENTID_0x8x82((short) 0x8082, "Short circuit to phase"), + EVENTID_0x8x83((short) 0x8083, "Short circuit to ground"), + EVENTID_0x8x84((short) 0x8084, "Wire break"), + EVENTID_0x8x85((short) 0x8085, "Fuse tripped"), + EVENTID_0x8x86((short) 0x8086, "No load voltage"), + EVENTID_0x8x87((short) 0x8087, "Excess temperature"), + EVENTID_0x8xB0((short) 0x80B0, "Counter module, signal A faulty. FM"), + EVENTID_0x8xB1((short) 0x80B1, "Counter module, signal B faulty"), + EVENTID_0x8xB2((short) 0x80B2, "Counter module, signal N faulty"), + EVENTID_0x8xB3((short) 0x80B3, "Counter module, incorrect value passed between the channels"), + EVENTID_0x8xB4((short) 0x80B4, "Counter module, 5.2 V sensor supply faulty"), + EVENTID_0x8xB5((short) 0x80B5, "Counter module, 24 V sensor supply faulty"), + + //Event Class 9 - Standard User Events + EVENTID_0x9001((short) 0x9001, "Automatic mode"), + EVENTID_0x9101((short) 0x9101, "Manual mode"), + EVENTID_0x9x02((short) 0x9002, "OPEN/CLOSED, ON/OFF"), + EVENTID_0x9x03((short) 0x9003, "Manual command enable"), + EVENTID_0x9x04((short) 0x9004, "Unit protective command (OPEN/CLOSED)"), + EVENTID_0x9x05((short) 0x9005, "Process enable"), + EVENTID_0x9x06((short) 0x9006, "System protection command"), + EVENTID_0x9x07((short) 0x9007, "Process value monitoring responded"), + EVENTID_0x9x08((short) 0x9008, "Manipulated variable monitoring responded"), + EVENTID_0x9x09((short) 0x9009, "System deviation greater than permitted"), + EVENTID_0x9x0A((short) 0x900A, "Limit position error"), + EVENTID_0x9x0B((short) 0x900B, "Runtime error"), + EVENTID_0x9x0C((short) 0x900C, "Command execution error (sequencer)"), + EVENTID_0x9x0D((short) 0x900D, "Operating status running > OPEN"), + EVENTID_0x9x0E((short) 0x900E, "Operating status running > CLOSED"), + EVENTID_0x9x0F((short) 0x900F, "Command blocking"), + EVENTID_0x9x11((short) 0x9011, "Process status OPEN/ON"), + EVENTID_0x9x12((short) 0x9012, "Process status CLOSED/OFF"), + EVENTID_0x9x13((short) 0x9013, "Process status intermediate position"), + EVENTID_0x9x14((short) 0x9014, "Process status ON via AUTO"), + EVENTID_0x9x15((short) 0x9015, "Process status ON via manual"), + EVENTID_0x9x16((short) 0x9016, "Process status ON via protective command"), + EVENTID_0x9x17((short) 0x9017, "Process status OFF via AUTO"), + EVENTID_0x9x18((short) 0x9018, "Process status OFF via manual"), + EVENTID_0x9x19((short) 0x9019, "Process status OFF via protective command"), + EVENTID_0x9x21((short) 0x9021, "Function error on approach"), + EVENTID_0x9x22((short) 0x9022, "Function error on leaving"), + EVENTID_0x9x31((short) 0x9031, "Actuator (DE/WE) limit position OPEN"), + EVENTID_0x9x32((short) 0x9032, "Actuator (DE/WE) limit position not OPEN"), + EVENTID_0x9x33((short) 0x9033, "Actuator (DE/WE) limit position CLOSED"), + EVENTID_0x9x34((short) 0x9034, "Actuator (DE/WE) limit position not CLOSED"), + EVENTID_0x9x41((short) 0x9041, "Illegal status, tolerance time elapsed"), + EVENTID_0x9x42((short) 0x9042, "Illegal status, tolerance time not elapsed"), + EVENTID_0x9x43((short) 0x9043, "Interlock error, tolerance time = 0"), + EVENTID_0x9x44((short) 0x9044, "Interlock error, tolerance time > 0"), + EVENTID_0x9x45((short) 0x9045, "No reaction"), + EVENTID_0x9x46((short) 0x9046, "Final status exited illegally, tolerance time = 0"), + EVENTID_0x9x47((short) 0x9047, "Final status exited illegally, tolerance time > 0"), + EVENTID_0x9x50((short) 0x9050, "Upper limit of signal range USR"), + EVENTID_0x9x51((short) 0x9051, "Upper limit of measuring range UMR"), + EVENTID_0x9x52((short) 0x9052, "Lower limit of signal range LSR"), + EVENTID_0x9x53((short) 0x9053, "Lower limit of measuring range LMR"), + EVENTID_0x9x54((short) 0x9054, "Upper alarm limit UAL"), + EVENTID_0x9x55((short) 0x9055, "Upper warning limit UWL"), + EVENTID_0x9x56((short) 0x9056, "Upper tolerance limit UTL"), + EVENTID_0x9x57((short) 0x9057, "Lower tolerance limit LTL"), + EVENTID_0x9x58((short) 0x9058, "Lower warning limit LWL"), + EVENTID_0x9x59((short) 0x9059, "Lower alarm limit LAL"), + EVENTID_0x9x60((short) 0x9060, "GRAPH7 step entering/leaving"), + EVENTID_0x9x61((short) 0x9061, "GRAPH7 interlock error"), + EVENTID_0x9x62((short) 0x9062, "GRAPH7 execution error"), + EVENTID_0x9x63((short) 0x9063, "GRAPH7 error noted"), + EVENTID_0x9x64((short) 0x9064, "GRAPH7 error acknowledged"), + EVENTID_0x9x70((short) 0x9070, "Trend exceeded in positive direction"), + EVENTID_0x9x71((short) 0x9071, "Trend exceeded in negative direction"), + EVENTID_0x9x72((short) 0x9072, "No reaction"), + EVENTID_0x9x73((short) 0x9073, "Final state exited illegally"), + EVENTID_0x9x80((short) 0x9080, "Limit value exceeded, tolerance time = 0"), + EVENTID_0x9x81((short) 0x9081, "Limit value exceeded, tolerance time > 0"), + EVENTID_0x9x82((short) 0x9082, "Below limit value, tolerance time = 0"), + EVENTID_0x9x83((short) 0x9083, "Below limit value, tolerance time > 0"), + EVENTID_0x9x84((short) 0x9084, "Gradient exceeded, tolerance time = 0"), + EVENTID_0x9x85((short) 0x9085, "Gradient exceeded, tolerance time > 0"), + EVENTID_0x9x86((short) 0x9086, "Below gradient, tolerance time = 0"), + EVENTID_0x9x87((short) 0x9087, "Below gradient, tolerance time > 0"), + EVENTID_0x9090((short) 0x9090, "User parameter assignment error entering/leaving"), + EVENTID_0x9190((short) 0x9190, "User parameter assignment error entering/leaving"), + EVENTID_0x91F0((short) 0x91F0, "Overflow"), + EVENTID_0x91F1((short) 0x91F1, "Underflow"), + EVENTID_0x91F2((short) 0x91F2, "Division by 0"), + EVENTID_0x91F3((short) 0x91F3, "Illegal calculation operation"), + + //Event Classes A and B - Free User Events + + + //Event Classes C,D & E - Reserved Event Classes + + //Event Classes F - Reserved for modules not in central + // rack (for example, CPs or FMs) + EVENTID_0x0000((short) 0x0000, "NULL"),; private static final Map map; + private static final Map idstr; + static { map = new HashMap<>(); + idstr = new HashMap<>(); for (S7DiagnosticEventId subevent : S7DiagnosticEventId .values()) { map.put(subevent.code, subevent); } + + idstr.put((short) 0x0000, "Event leaving state. "); + idstr.put((short) 0x0100, "Event entering state. "); + idstr.put((short) 0x0200, "Entry in diagnostic buffer. "); + idstr.put((short) 0x0400, "Internal error. "); + idstr.put((short) 0x0800, "External error. "); } private final String event; @@ -470,6 +661,7 @@ public enum S7DiagnosticEventId { } public String getEvent(){ + short id = (short) (code & 0x0F00); return event; } @@ -487,6 +679,13 @@ public static S7DiagnosticEventId valueOfEvent(String event) { } public static S7DiagnosticEventId valueOf(short code) { + + if ((code > 0x8000) & (code < 0xA000)){ + if ((code != 0x9101) & (code != 0x9190) & (code != 0x91F0) + & (code != 0x91F1) & (code != 0x91F2) + & (code != 0x91F3)) + code = (short) (code & 0xF0FF); + } return map.get(code); } } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7SslHelper.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7SslHelper.java new file mode 100644 index 00000000000..61965a3507a --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7SslHelper.java @@ -0,0 +1,28 @@ +/* + 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.utils; + +/** + * + * @author cgarcia + */ +public class S7SslHelper { + +} From f269e26210ee1ad4d1fffc62a4bce03872148a8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Tue, 4 Feb 2020 23:34:14 -0400 Subject: [PATCH 08/17] Asynchronous events are working. --- .../java/s7/connection/S7PlcConnection.java | 60 +- .../java/s7/model/S7SubscriptionField.java | 2 +- .../plc4x/java/s7/netty/Plc4XS7Protocol.java | 42 +- .../plc4x/java/s7/netty/S7Protocol.java | 66 +- .../model/payloads/AlarmMessagePayload.java | 2 +- .../payloads/items/MessageObjectItem.java | 64 ++ .../CpuServicesParameterSubFunctionGroup.java | 3 +- .../model/types/SubscribedEventType.java | 3 +- .../java/s7/protocol/event/S7Alarm8Event.java | 28 - .../s7/protocol/event/S7Alarm8pEvent.java | 28 - .../java/s7/protocol/event/S7AlarmDEvent.java | 28 - .../s7/protocol/event/S7AlarmDQEvent.java | 28 - .../java/s7/protocol/event/S7AlarmEvent.java | 638 +++++++++++++++++- .../java/s7/protocol/event/S7AlarmSEvent.java | 434 ------------ .../s7/protocol/event/S7AlarmSQEvent.java | 28 - .../plc4x/java/s7/protocol/event/S7Event.java | 27 +- .../java/s7/protocol/event/S7ModeEvent.java | 35 +- .../s7/protocol/event/S7Notify8pEvent.java | 28 - .../java/s7/protocol/event/S7NotifyEvent.java | 14 - .../java/s7/protocol/event/S7SysEvent.java | 45 +- 20 files changed, 904 insertions(+), 699 deletions(-) delete mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Alarm8Event.java delete mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Alarm8pEvent.java delete mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmDEvent.java delete mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmDQEvent.java delete mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmSEvent.java delete mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmSQEvent.java delete mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Notify8pEvent.java delete mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7NotifyEvent.java diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java index a8cec59e299..0a214df8187 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java @@ -75,6 +75,7 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.netty.model.payloads.CpuCyclicServicesResponsePayload; import org.apache.plc4x.java.s7.netty.model.payloads.CpuDiagnosticMessagePayload; import org.apache.plc4x.java.s7.netty.model.payloads.items.AssociatedValueItem; +import org.apache.plc4x.java.s7.netty.model.types.CpuServicesParameterSubFunctionGroup; import org.apache.plc4x.java.s7.netty.model.types.MemoryArea; import org.apache.plc4x.java.s7.netty.model.types.SubscribedEventType; import org.apache.plc4x.java.s7.netty.strategies.DefaultS7MessageProcessor; @@ -82,6 +83,8 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.netty.util.S7PlcFieldHandler; import org.apache.plc4x.java.s7.protocol.S7CyclicServicesSubscriptionHandle; import org.apache.plc4x.java.s7.protocol.S7DiagnosticSubscriptionHandle; +import org.apache.plc4x.java.s7.protocol.event.S7AlarmEvent; +import org.apache.plc4x.java.s7.protocol.event.S7Event; import org.apache.plc4x.java.s7.protocol.event.S7ModeEvent; import org.apache.plc4x.java.s7.protocol.event.S7SysEvent; import org.apache.plc4x.java.s7.types.S7ControllerType; @@ -212,9 +215,10 @@ public S7PlcConnection(ChannelFactory channelFactory, int rack, int slot, String Map almEventHandle = new HashMap(); pushEventHandles.put(SubscribedEventType.USR, usrEventHandle); - pushEventHandles.put(SubscribedEventType.SYS, usrEventHandle); + pushEventHandles.put(SubscribedEventType.SYS, sysEventHandle); pushEventHandles.put(SubscribedEventType.MODE, modeEventHandle); - pushEventHandles.put(SubscribedEventType.ALM, almEventHandle); + pushEventHandles.put(SubscribedEventType.ALM_S, almEventHandle); + pushEventHandles.put(SubscribedEventType.ALM_8, almEventHandle); alarmsloopthread = new EventLoop(channel, this.alarmsqueue, @@ -453,7 +457,6 @@ public PlcConsumerRegistration register(Consumer consumer, s7handle.getConsumers().add(consumer); s7handle.getSubscribedevents().forEach((event)->{ pushEventHandles.get(event).put(s7handle.getJobId(), s7handle); - logger.info("Suscripcion: " + s7handle.getSubscribedevents().toString()); }); } @@ -504,18 +507,23 @@ public void run() { if (msg != null){ if (msg instanceof AlarmMessagePayload){ AlarmMessagePayload themsg = (AlarmMessagePayload) msg; - logger.info("AlarmMessagePayload: " + themsg); - dispathAlmEvents(pushEventHandles.get(SubscribedEventType.ALM), themsg); + logger.debug("AlarmMessagePayload: " + themsg); + dispathAlmEvents(pushEventHandles.get(SubscribedEventType.ALM_8), themsg); } else if (msg instanceof CpuDiagnosticPushParameter) { CpuDiagnosticPushParameter themsg = (CpuDiagnosticPushParameter) msg; - logger.info("CpuDiagnosticPushParameter: " + themsg); + logger.debug("CpuDiagnosticPushParameter: " + themsg); dispathModeEvents(pushEventHandles.get(SubscribedEventType.MODE), themsg); } else if (msg instanceof CpuDiagnosticMessagePayload) { CpuDiagnosticMessagePayload themsg = (CpuDiagnosticMessagePayload) msg; - logger.info("CpuDiagnosticMessagePayload: " + themsg); - dispathSysEvents(pushEventHandles.get(SubscribedEventType.SYS), themsg); + logger.debug("CpuDiagnosticMessagePayload: " + themsg); + int EventID = Short.toUnsignedInt(themsg.getMsg().getEventID()); + if ((EventID >= 0x0A000) & (EventID <= 0x0BFFF)) { + dispathSysEvents(pushEventHandles.get(SubscribedEventType.USR), themsg); + } else { + dispathSysEvents(pushEventHandles.get(SubscribedEventType.SYS), themsg); + } } else if (msg instanceof CpuServicesPushParameter) { CpuServicesPushParameter themsg = (CpuServicesPushParameter) msg; @@ -549,6 +557,29 @@ public void run() { logger.info("Closing the alarm loop."); } + private void dispathAlmEvents(Map handles, AlarmMessagePayload payload) + { + List alarmsEvent = null; + Object object = payload.getMsgtype(); + if (object != null) { + if (object instanceof CpuServicesParameterSubFunctionGroup) { + CpuServicesParameterSubFunctionGroup subFunction = (CpuServicesParameterSubFunctionGroup) object; + alarmsEvent = S7AlarmEvent.getAlarmsEvents(subFunction, payload); + } + } + + for (PlcSubscriptionHandle handle:handles.values()){ + S7DiagnosticSubscriptionHandle s7handle = (S7DiagnosticSubscriptionHandle) handle; + for (Consumer consumer:s7handle.getConsumers()){ + if (alarmsEvent != null) { + for (S7Event event:alarmsEvent) { + consumer.accept(event); + } + } + }; + }; + } + private void dispathSysEvents(Map handles, CpuDiagnosticMessagePayload payload) { handles.forEach((index,handle)->{ @@ -569,18 +600,7 @@ private void dispathModeEvents(Map handles, CpuDia consumer.accept(event); }); }); - } - - private void dispathAlmEvents(Map handles, AlarmMessagePayload payload) - { - handles.forEach((index,handle)->{ - S7DiagnosticSubscriptionHandle thehandle = (S7DiagnosticSubscriptionHandle) handle; - thehandle.getConsumers().forEach((consumer)->{ - consumer.accept(null); - }); - }); - } - + } private void UpdateCyclicServicesData(S7CyclicServicesSubscriptionHandle handle,CpuCyclicServicesResponsePayload themsg){ diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7SubscriptionField.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7SubscriptionField.java index 07c24d57663..8630fca14a4 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7SubscriptionField.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7SubscriptionField.java @@ -35,7 +35,7 @@ public class S7SubscriptionField implements PlcField { //Event Subscription private static final Pattern EVENT_SUBSCRIPTION_TYPE_PATTERN = - Pattern.compile("(^MODE)|(^SYS)|(^USR)|(^ALM)"); + Pattern.compile("(^MODE)|(^SYS)|(^USR)|(^ALM_S)|(^ALM_8)"); //Event ack private static final Pattern EVENT_ALARM_ACK_PATTERN = 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 a49ee84882e..0ffd6fec45f 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 @@ -250,6 +250,7 @@ private void encodeEventSubcriptionRequest(PlcRequestContainer msg, List byte subsevent = 0; List parameterItems = new LinkedList<>(); List payloadItems = new LinkedList<>(); + AlarmType alarmType = AlarmType.ALARM_S_INITIATE; PlcSubscriptionRequest subsRequest = (PlcSubscriptionRequest) msg.getRequest(); @@ -257,6 +258,9 @@ private void encodeEventSubcriptionRequest(PlcRequestContainer msg, List if ( subsRequest.getField(fieldName) instanceof S7SubscriptionField){ S7SubscriptionField event = (S7SubscriptionField) subsRequest.getField(fieldName); subsevent = (byte) (subsevent | event.getEventtype().getCode()); + if (event.getEventtype() == SubscribedEventType.ALM_8) { + alarmType = AlarmType.ALARM_INITIATE; + } } } @@ -270,8 +274,11 @@ private void encodeEventSubcriptionRequest(PlcRequestContainer msg, List DataTransportSize.OCTET_STRING, subsevent, new String("HmiRtm "), - AlarmType.ALARM_S_INITIATE); + alarmType); + + payloadItems.add(Data); + S7RequestMessage s7ReadRequest = new S7RequestMessage(MessageType.USER_DATA, @@ -469,6 +476,7 @@ private void encodeEventUnSubcriptionRequest(PlcRequestContainer msg, List parameterItems = new LinkedList<>(); List payloadItems = new LinkedList<>(); + AlarmType alarmType = AlarmType.ALARM_S_INITIATE; PlcSubscriptionRequest subsRequest = (PlcSubscriptionRequest) msg.getRequest(); @@ -476,6 +484,9 @@ private void encodeEventUnSubcriptionRequest(PlcRequestContainer msg, List items = payloadItem.getMsg().getMsgItems(); - ArrayList eventids = event.getAckalarms(); - int index = 0; - for (Object item:items){ - // A ack response contains only the return code for every item. - // Is direct response for the ALARM_ACK, don't pass to - // push message handler. - //subsBuilder2.addEventField("MyAck", "ACK:16#60000001,16#60000002,16#60000003"); - values.put("16#"+Integer.toHexString(eventids.get(index)), new ImmutablePair(decodeResponseCode((DataTransportErrorCode) item),null)); - index++; - } + if (payloadItem.getLength() != 0) { + List items = payloadItem.getMsg().getMsgItems(); + ArrayList eventids = event.getAckalarms(); + int index = 0; + for (Object item:items){ + // A ack response contains only the return code for every item. + // Is direct response for the ALARM_ACK, don't pass to + // push message handler. + //subsBuilder2.addEventField("MyAck", "ACK:16#60000001,16#60000002,16#60000003"); + values.put("16#"+Integer.toHexString(eventids.get(index)), new ImmutablePair(decodeResponseCode((DataTransportErrorCode) item),null)); + index++; + } + } else { + values.put("ERROR", new ImmutablePair(PlcResponseCode.NOT_FOUND,null)); + } } break; case ALARM_QUERY:{ 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 064858ffa78..5ecfdc0d81f 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 @@ -917,14 +917,20 @@ private S7Payload decodeCpuServicesPayload(CpuServicesParameter parameter, ByteB return payload; } case ALARM8:; + logger.info("decode ALARM8....."); + break; case NOTIFY:; + logger.info("decode NOTIFY....."); break; case ALARM8_LOCK:; + logger.info("decode ALARM8_LOCK....."); break; case ALARM8_UNLOCK:; + logger.info("decode ALARM8_UNLOCK....."); break; case SCAN:; + logger.info("decode SCAN....."); break; case ALARM_ACK:{ AlarmMessagePayload payload = decodeMessageServiceAckPayload(parameter, userData); @@ -935,8 +941,10 @@ private S7Payload decodeCpuServicesPayload(CpuServicesParameter parameter, ByteB return payload; } case ALARM8_LOCK_IND:; + logger.info("decode ALARM8_LOCK_IND....."); break; case ALARM8_UNLOCK_IND:; + logger.info("decode ALARM8_UNLOCK_IND....."); break; case ALARM_SQ_IND:{ AlarmMessagePayload payload = decodeMessageServicePushPayload(parameter, userData); @@ -950,8 +958,10 @@ private S7Payload decodeCpuServicesPayload(CpuServicesParameter parameter, ByteB AlarmMessagePayload payload = decodeMessageServiceQueryPayload(parameter, userData); return payload; } - case NOTIFY8:; - break; + case NOTIFY8: { + AlarmMessagePayload payload = decodeMessageServicePushPayload(parameter, userData); + return payload; + } default:; break; } @@ -1259,7 +1269,6 @@ private CpuDiagnosticMessagePayload decodeCpuDiagnosticMessagePayload(CpuService } private AlarmMessagePayload decodeMessageServicePushPayload(CpuServicesParameter parameter, ByteBuf userData){ - List MessageObjects = new LinkedList<>(); List values = new LinkedList<>(); int length; @@ -1267,13 +1276,18 @@ private AlarmMessagePayload decodeMessageServicePushPayload(CpuServicesParameter LocalDateTime timestamp; Byte FunctionID; byte NumberOfMessgaeObjects; + byte EventGoing = 0x00; + byte EventComming = 0x00; + byte EventLastChange = 0x00; + + // DataTransportErrorCode returnCode = DataTransportErrorCode.valueOf(userData.readByte()); DataTransportSize dataTransportSize = DataTransportSize.valueOf(userData.readByte()); length = userData.readShort(); //It is assumed that you have synchronized the time of your PLC with PC. - // + //The most important field. timestamp = readDateAndTime(userData); FunctionID = userData.readByte(); @@ -1297,6 +1311,17 @@ private AlarmMessagePayload decodeMessageServicePushPayload(CpuServicesParameter byte AckStateGoing = userData.readByte(); byte AckStateComming = userData.readByte(); + switch(parameter.getSubFunctionGroup()){ + case ALARM8: + case NOTIFY8: + case NOTIFY: + EventGoing = userData.readByte(); + EventComming = userData.readByte(); + EventLastChange = userData.readByte(); + userData.readByte(); //Reserved = 0x00 + break; + } + //TODO: If NumberOfValues == 0 then AssociatedValues is null List AssociatedValues = new LinkedList<>(); @@ -1326,6 +1351,9 @@ private AlarmMessagePayload decodeMessageServicePushPayload(CpuServicesParameter State, AckStateGoing, AckStateComming, + EventGoing, + EventComming, + EventLastChange, AssociatedValues)); } @@ -1504,23 +1532,31 @@ private AlarmMessagePayload decodeMessageServiceAckPayload(CpuServicesParameter DataTransportSize dataTransportSize = DataTransportSize.valueOf(userData.readByte()); int length = userData.readShort(); //Number of message objects? - //Alarm message section - byte FunctionID = userData.readByte(); - byte NumberOfMessageObjects = userData.readByte(); + if (returnCode == DataTransportErrorCode.OK) { - //In the next leve if is != null -> Success - for(int i=0; i< NumberOfMessageObjects; i++) { - MessageObjects.add(DataTransportErrorCode.valueOf(userData.readByte())); - }; + //Alarm message section + byte FunctionID = userData.readByte(); + byte NumberOfMessageObjects = userData.readByte(); + + //In the next leve if is != null -> Success + for(int i=0; i< NumberOfMessageObjects; i++) { + MessageObjects.add(DataTransportErrorCode.valueOf(userData.readByte())); + }; + + return new AlarmMessagePayload(returnCode, + dataTransportSize, + CpuServicesParameterSubFunctionGroup.ALARM_QUERY, + length, + new AlarmMessageItem(FunctionID, + NumberOfMessageObjects, + MessageObjects)); + } return new AlarmMessagePayload(returnCode, dataTransportSize, CpuServicesParameterSubFunctionGroup.ALARM_QUERY, length, - new AlarmMessageItem(FunctionID, - NumberOfMessageObjects, - MessageObjects)); - + null); } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/AlarmMessagePayload.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/AlarmMessagePayload.java index 5416aa8b877..ffe817b4e2b 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/AlarmMessagePayload.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/AlarmMessagePayload.java @@ -30,7 +30,7 @@ Licensed to the Apache Software Foundation (ASF) under one * @author cgarcia */ public class AlarmMessagePayload implements S7Payload, S7PushMessage { - + private final DataTransportErrorCode returnCode; private final DataTransportSize dataTransportSize; private final Object msgtype; diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/MessageObjectItem.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/MessageObjectItem.java index 752e5ddacea..a8effbc48f3 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/MessageObjectItem.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/MessageObjectItem.java @@ -40,6 +40,9 @@ public class MessageObjectItem { private final byte State; private final byte AckStateGoing; private final byte AckStateComming; + private final byte EventGoing; + private final byte EventComming; + private final byte EventLastChange; private final LocalDateTime TimestampComing; private final LocalDateTime TimestampGoing; private final List ComingValues; @@ -64,6 +67,9 @@ public MessageObjectItem(byte VariableSpecification, this.State = 0x00; this.AckStateGoing = 0x00; this.AckStateComming = 0x00; + this.EventGoing = 0x00; + this.EventComming = 0x00; + this.EventLastChange = 0x00; this.TimestampComing = null; this.ComingValues = null; this.TimestampGoing = null; @@ -93,6 +99,9 @@ public MessageObjectItem(byte Length, this.State = 0x00; this.AckStateGoing = AckStateGoing; this.AckStateComming = AckStateComming; + this.EventGoing = 0x00; + this.EventComming = 0x00; + this.EventLastChange = 0x00; this.TimestampComing = TimestampComing; this.ComingValues = ComingValues; this.TimestampGoing = TimestampGoing; @@ -118,6 +127,9 @@ public MessageObjectItem(byte VariableSpecification, this.State = 0x00; this.AckStateGoing = AckStateGoing; this.AckStateComming = AckStateComming; + this.EventGoing = 0x00; + this.EventComming = 0x00; + this.EventLastChange = 0x00; this.TimestampComing = null; this.ComingValues = null; this.TimestampGoing = null; @@ -146,6 +158,9 @@ public MessageObjectItem(byte VariableSpecification, this.State = State; this.AckStateGoing = AckStateGoing; this.AckStateComming = AckStateComming; + this.EventGoing = 0x00; + this.EventComming = 0x00; + this.EventLastChange = 0x00; this.TimestampComing = null; this.ComingValues = Values; this.TimestampGoing = null; @@ -177,6 +192,9 @@ public MessageObjectItem(byte VariableSpecification, this.State = State; this.AckStateGoing = AckStateGoing; this.AckStateComming = AckStateComming; + this.EventGoing = 0x00; + this.EventComming = 0x00; + this.EventLastChange = 0x00; this.TimestampComing = TimestampComing; this.ComingValues = ComingValues; this.TimestampGoing = TimestampGoing; @@ -185,6 +203,40 @@ public MessageObjectItem(byte VariableSpecification, this.alarmtype = null; } + public MessageObjectItem(byte VariableSpecification, + byte Length, + VariableAddressingMode SyntaxID, + byte NumberOfValues, + int EventID, + byte EventState, + byte State, + byte AckStateGoing, + byte AckStateComming, + byte EventGoing, + byte EventComming, + byte EventLastChange, + List ComingValues) { + + this.VariableSpecification = VariableSpecification; + this.Length = Length; + this.SyntaxID = SyntaxID; + this.NumberOfValues = NumberOfValues; + this.EventID = EventID; + this.EventState = EventState; + this.State = State; + this.AckStateGoing = AckStateGoing; + this.AckStateComming = AckStateComming; + this.EventGoing = 0x00; + this.EventComming = 0x00; + this.EventLastChange = 0x00; + this.TimestampComing = null; + this.ComingValues = ComingValues; + this.TimestampGoing = null; + this.GoingValues = null; + this.querytype = null; + this.alarmtype = null; + } + public byte getVariableSpecification() { return VariableSpecification; } @@ -225,6 +277,18 @@ public LocalDateTime getTimestampComing() { return TimestampComing; } + public byte getEventGoing() { + return EventGoing; + } + + public byte getEventComming() { + return EventComming; + } + + public byte getEventLastChange() { + return EventLastChange; + } + public LocalDateTime getTimestampGoing() { return TimestampGoing; } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuServicesParameterSubFunctionGroup.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuServicesParameterSubFunctionGroup.java index 5b679a5fe0f..10ebcfd48c2 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuServicesParameterSubFunctionGroup.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuServicesParameterSubFunctionGroup.java @@ -41,7 +41,8 @@ public enum CpuServicesParameterSubFunctionGroup { ALARM_SQ_IND((byte) 0x11), ALARM_S_IND((byte) 0x12), ALARM_QUERY((byte) 0x13), - NOTIFY8((byte) 0x16); //TODO + NOTIFY8((byte) 0x16), + NONE((byte) 0x00); //TODO private static final Logger logger = LoggerFactory.getLogger(CpuServicesParameterSubFunctionGroup.class); diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/SubscribedEventType.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/SubscribedEventType.java index d963343b844..3c64845a23c 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/SubscribedEventType.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/SubscribedEventType.java @@ -32,7 +32,8 @@ public enum SubscribedEventType implements PlcField { MODE("MODE", (byte) 0x01), SYS("SYS", (byte) 0x02), USR("USR", (byte) 0x04), - ALM("ALM", (byte) 0x80); + ALM_S("ALM_S", (byte) 0x80), + ALM_8("ALM_8", (byte) 0x80); private static final Map map; diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Alarm8Event.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Alarm8Event.java deleted file mode 100644 index d6664a37e94..00000000000 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Alarm8Event.java +++ /dev/null @@ -1,28 +0,0 @@ -/* -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.protocol.event; - -/** - * - * @author cgarcia - */ -public class S7Alarm8Event { - -} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Alarm8pEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Alarm8pEvent.java deleted file mode 100644 index e4aaec2aad8..00000000000 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Alarm8pEvent.java +++ /dev/null @@ -1,28 +0,0 @@ -/* -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.protocol.event; - -/** - * - * @author cgarcia - */ -public class S7Alarm8pEvent { - -} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmDEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmDEvent.java deleted file mode 100644 index f8e57d26b7a..00000000000 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmDEvent.java +++ /dev/null @@ -1,28 +0,0 @@ -/* -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.protocol.event; - -/** - * - * @author cgarcia - */ -public class S7AlarmDEvent { - -} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmDQEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmDQEvent.java deleted file mode 100644 index a8dc38654e8..00000000000 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmDQEvent.java +++ /dev/null @@ -1,28 +0,0 @@ -/* -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.protocol.event; - -/** - * - * @author cgarcia - */ -public class S7AlarmDQEvent { - -} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmEvent.java index a98d7465aa2..93affa6aa31 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmEvent.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmEvent.java @@ -1,14 +1,642 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ +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.protocol.event; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.plc4x.java.api.messages.PlcReadRequest; +import org.apache.plc4x.java.api.model.PlcField; +import org.apache.plc4x.java.api.types.PlcResponseCode; +import org.apache.plc4x.java.s7.netty.model.payloads.AlarmMessagePayload; +import org.apache.plc4x.java.s7.netty.model.payloads.items.AlarmMessageItem; +import org.apache.plc4x.java.s7.netty.model.payloads.items.AssociatedValueItem; +import org.apache.plc4x.java.s7.netty.model.payloads.items.MessageObjectItem; +import org.apache.plc4x.java.s7.netty.model.types.CpuServicesParameterSubFunctionGroup; + /** * * @author cgarcia */ -public class S7AlarmEvent { +public class S7AlarmEvent implements S7Event { + + public enum Fields{ + MAP, + + TYPE, + TIMESTAMP, + TIMESTAMP_GOING, + TIMESTAMP_COMING, + + EVENT_ID, + EVENT_STATE, + STATE, + ACKSTATE_GOING, + ACKSTATE_COMING, + EVENT_GOING, + EVENT_COMING, + EVENT_LAST_CHANGE, + + SIG, + SIG_1, + SIG_2, + SIG_3, + SIG_4, + SIG_5, + SIG_6, + SIG_7, + SIG_8, + + SIG_STATE, + SIG_1_STATE, + SIG_2_STATE, + SIG_3_STATE, + SIG_4_STATE, + SIG_5_STATE, + SIG_6_STATE, + SIG_7_STATE, + SIG_8_STATE, + + SIG_DATA, + SIG_1_DATA, + SIG_2_DATA, + SIG_3_DATA, + SIG_4_DATA, + SIG_5_DATA, + SIG_6_DATA, + SIG_7_DATA, + SIG_8_DATA, + SIG_1_DATA_GOING, + SIG_2_DATA_GOING, + SIG_3_DATA_GOING, + SIG_4_DATA_GOING, + SIG_5_DATA_GOING, + SIG_6_DATA_GOING, + SIG_7_DATA_GOING, + SIG_8_DATA_GOING, + SIG_1_DATA_COMING, + SIG_2_DATA_COMING, + SIG_3_DATA_COMING, + SIG_4_DATA_COMING, + SIG_5_DATA_COMING, + SIG_6_DATA_COMING, + SIG_7_DATA_COMING, + SIG_8_DATA_COMING, + + } + + //private final Instant timeStamp; + private final Map map; + + public S7AlarmEvent(Map map) { + this.map = map; + } + + public static List getAlarmsEvents(CpuServicesParameterSubFunctionGroup subFunction, + AlarmMessagePayload payload){ + List alarmEvents = new ArrayList(); + Map map = new HashMap(); + Instant timeStamp; + int index = 0; + AssociatedValueItem itemValue; + byte[] datos; + + AlarmMessageItem msgItem = payload.getMsg(); + List objects = msgItem.getMsgItems(); + for (Object object:objects){ + MessageObjectItem item = (MessageObjectItem) object; + alarmEvents.add(createAlarmEvent(subFunction, msgItem, item)); + } + + return alarmEvents; + } + + private static S7AlarmEvent createAlarmEvent(CpuServicesParameterSubFunctionGroup subFunction, + AlarmMessageItem msgItem, + MessageObjectItem message){ + Map map = new HashMap(); + AssociatedValueItem itemValue; + byte[] datos; + + switch(subFunction){ + case ALARM_QUERY:{ + switch(message.getAlarmtype()){ + case ALARM_S: + map.put(Fields.TYPE.toString(), CpuServicesParameterSubFunctionGroup.ALARM_S.getCode()); + map.put(Fields.EVENT_ID.name(), message.getEventID()); + map.put(Fields.EVENT_STATE.name(), message.getEventState()); + map.put(Fields.ACKSTATE_GOING.name(), message.getAckStateGoing()); + map.put(Fields.ACKSTATE_COMING.name(), message.getAckStateComming()); + + map.put(Fields.TIMESTAMP_GOING.name(), message.getTimestampGoing().toInstant(ZoneOffset.UTC)); + + AssociatedValueItem itemg = message.getComingValues().get(0); + datos = new byte[itemg.getLength()]; + if (itemg.getLength() != 0) { + itemg.getData().getBytes(0, datos); + }; + map.put(Fields.SIG_1_DATA_GOING.name(), datos); + + map.put(Fields.TIMESTAMP_COMING.name(), message.getTimestampComing().toInstant(ZoneOffset.UTC)); + + AssociatedValueItem itemc = message.getComingValues().get(0); + datos = new byte[itemc.getLength()]; + if (itemc.getLength() != 0) { + itemc.getData().getBytes(0, datos); + } + map.put(Fields.SIG_1_DATA_COMING.name(), datos); + break; + + case ALARM_8: + + map.put(Fields.TYPE.toString(), CpuServicesParameterSubFunctionGroup.ALARM8); + break; + case SCAN: + map.put(Fields.TYPE.toString(), CpuServicesParameterSubFunctionGroup.SCAN); + break; + case NONE: + map.put(Fields.TYPE.toString(), CpuServicesParameterSubFunctionGroup.NONE); + break; + default:; + } + } + break; + case ALARM_ACK_IND:; + break; + case ALARM_SQ_IND: + case ALARM_S_IND:{ + map.put(Fields.TYPE.toString(), CpuServicesParameterSubFunctionGroup.ALARM_S_IND.getCode()); + map.put(Fields.TIMESTAMP.name(), msgItem.getTimestamp().toInstant(ZoneOffset.UTC)); + map.put(Fields.EVENT_ID.name(), message.getEventID()); + map.put(Fields.EVENT_STATE.name(), message.getEventState()); + map.put(Fields.STATE.name(), message.getState()); + map.put(Fields.ACKSTATE_GOING.name(), message.getAckStateGoing()); + map.put(Fields.ACKSTATE_COMING.name(), message.getAckStateComming()); + AssociatedValueItem itemc = message.getComingValues().get(0); + datos = new byte[itemc.getLength()]; + if (itemc.getLength() != 0) { + itemc.getData().getBytes(0, datos); + } + map.put(Fields.SIG_1_DATA.name(), datos); + }; + break; + case NOTIFY8:{ + map.put(Fields.TYPE.toString(), CpuServicesParameterSubFunctionGroup.NOTIFY8.getCode()); + map.put(Fields.TIMESTAMP.name(), msgItem.getTimestamp().toInstant(ZoneOffset.UTC)); + map.put(Fields.EVENT_ID.name(), message.getEventID()); + map.put(Fields.EVENT_STATE.name(), message.getEventState()); + map.put(Fields.STATE.name(), message.getState()); + map.put(Fields.ACKSTATE_GOING.name(), message.getAckStateGoing()); + map.put(Fields.ACKSTATE_COMING.name(), message.getAckStateComming()); + map.put(Fields.EVENT_GOING.name(), message.getEventGoing()); + map.put(Fields.EVENT_COMING.name(), message.getEventComming()); + map.put(Fields.EVENT_LAST_CHANGE.name(), message.getEventLastChange()); + for(int i = 0; i < message.getNumberOfValues(); i++){ + itemValue = message.getComingValues().get(i); + datos = new byte[itemValue.getLength()]; + map.put("SIG_"+ (i+1) +"_STATE", itemValue.getReturnCode().getCode()); + itemValue.getData().getBytes(0, datos); + map.put("SIG_"+ (i+1) +"_DATA", datos); + } + } + break; + } + + return new S7AlarmEvent(map); + } + + + + @Override + public Instant getTimestamp() { + return (Instant) map.get(Fields.TIMESTAMP.name()); + } + + @Override + public PlcReadRequest getRequest() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getNumberOfValues(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Object getObject(String name) { + switch(Fields.valueOf(name)){ + case MAP: return map; + default:; + } + return null; + } + + @Override + public Object getObject(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllObjects(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBoolean(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBoolean(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Boolean getBoolean(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Boolean getBoolean(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllBooleans(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidByte(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidByte(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Byte getByte(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Byte getByte(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllBytes(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidShort(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidShort(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Short getShort(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Short getShort(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllShorts(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Integer getInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Integer getInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllIntegers(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBigInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBigInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BigInteger getBigInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BigInteger getBigInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllBigIntegers(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidLong(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidLong(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Long getLong(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Long getLong(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllLongs(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidFloat(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidFloat(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Float getFloat(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Float getFloat(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllFloats(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDouble(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDouble(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Double getDouble(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Double getDouble(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllDoubles(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBigDecimal(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBigDecimal(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BigDecimal getBigDecimal(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BigDecimal getBigDecimal(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllBigDecimals(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidString(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidString(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getString(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getString(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllStrings(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalTime getTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalTime getTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllTimes(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDate(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDate(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalDate getDate(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalDate getDate(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllDates(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDateTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDateTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalDateTime getDateTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalDateTime getDateTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllDateTimes(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidByteArray(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidByteArray(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Byte[] getByteArray(String name) { + return (Byte[]) map.get(name); + } + + @Override + public Byte[] getByteArray(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllByteArrays(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getFieldNames() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public PlcField getField(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public PlcResponseCode getResponseCode(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Map getMap() { + return map; + } + + } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmSEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmSEvent.java deleted file mode 100644 index 0c2542ac1f2..00000000000 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmSEvent.java +++ /dev/null @@ -1,434 +0,0 @@ -/* -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.protocol.event; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.time.Instant; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.util.Collection; -import org.apache.plc4x.java.api.messages.PlcReadRequest; -import org.apache.plc4x.java.api.model.PlcField; -import org.apache.plc4x.java.api.types.PlcResponseCode; - -/** - * - * @author cgarcia - */ -public class S7AlarmSEvent implements S7Event { - - @Override - public Instant getTimestamp() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public PlcReadRequest getRequest() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public int getNumberOfValues(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Object getObject(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Object getObject(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Collection getAllObjects(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidBoolean(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidBoolean(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Boolean getBoolean(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Boolean getBoolean(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Collection getAllBooleans(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidByte(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidByte(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Byte getByte(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Byte getByte(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Collection getAllBytes(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidShort(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidShort(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Short getShort(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Short getShort(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Collection getAllShorts(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidInteger(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidInteger(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Integer getInteger(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Integer getInteger(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Collection getAllIntegers(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidBigInteger(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidBigInteger(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public BigInteger getBigInteger(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public BigInteger getBigInteger(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Collection getAllBigIntegers(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidLong(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidLong(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Long getLong(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Long getLong(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Collection getAllLongs(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidFloat(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidFloat(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Float getFloat(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Float getFloat(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Collection getAllFloats(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidDouble(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidDouble(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Double getDouble(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Double getDouble(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Collection getAllDoubles(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidBigDecimal(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidBigDecimal(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public BigDecimal getBigDecimal(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public BigDecimal getBigDecimal(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Collection getAllBigDecimals(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidString(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidString(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public String getString(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public String getString(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Collection getAllStrings(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidTime(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidTime(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public LocalTime getTime(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public LocalTime getTime(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Collection getAllTimes(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidDate(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidDate(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public LocalDate getDate(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public LocalDate getDate(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Collection getAllDates(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidDateTime(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidDateTime(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public LocalDateTime getDateTime(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public LocalDateTime getDateTime(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Collection getAllDateTimes(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidByteArray(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public boolean isValidByteArray(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Byte[] getByteArray(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Byte[] getByteArray(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Collection getAllByteArrays(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Collection getFieldNames() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public PlcField getField(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public PlcResponseCode getResponseCode(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - -} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmSQEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmSQEvent.java deleted file mode 100644 index f87189d3f00..00000000000 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmSQEvent.java +++ /dev/null @@ -1,28 +0,0 @@ -/* -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.protocol.event; - -/** - * - * @author cgarcia - */ -public class S7AlarmSQEvent { - -} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Event.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Event.java index 7a509ef22b0..04c9fe619a8 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Event.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Event.java @@ -19,12 +19,37 @@ Licensed to the Apache Software Foundation (ASF) under one package org.apache.plc4x.java.s7.protocol.event; +import java.util.Map; import org.apache.plc4x.java.api.messages.PlcSubscriptionEvent; /** - * + * Like JMS but different. + * Maintain the same pattern as JMS MapMessage. + * S7Event is a Map whose key is a String and its value is an + * Object of primitive values. + * Classes derived from the S7Event must respect the following + * conversion table. + * + * | | boolean byte short char int long float double String byte[] + * |--------+------------------------------------------------------------- + * |boolean | X X + * |byte | X X X X X + * |short | X X X X + * |char | X X + * |int | X X X + * |long | X X + * |float | X X X + * |double | X X + * |String | X X X X X X X X + * |byte[] | X + * |--------+------------------------------------------------------------- + * * @author cgarcia */ public interface S7Event extends PlcSubscriptionEvent{ + + public Map getMap(); + + } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7ModeEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7ModeEvent.java index 869faf4f826..2493925e08a 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7ModeEvent.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7ModeEvent.java @@ -43,19 +43,22 @@ Licensed to the Apache Software Foundation (ASF) under one */ public class S7ModeEvent implements S7Event { - public static final String METHOD = "METHOD"; - public static final String TYPE = "TYPE"; - public static final String FUNCTION = "FUNCTION"; - public static final String CURRENT_MODE = "CURRENT_MODE"; - + public enum Fields{ + MAP, + METHOD, + TYPE, + FUNCTION, + CURRENT_MODE + } + private final Instant timeStamp; private Map map = new HashMap(); public S7ModeEvent(Instant timeStamp, CpuDiagnosticPushParameter parameter) { - map.put(METHOD, parameter.getMethod()); - map.put(TYPE, parameter.getParameterType()); - map.put(FUNCTION, parameter.getParameterFunction()); - map.put(CURRENT_MODE, parameter.getCurrentMode()); + map.put(Fields.METHOD.name(), parameter.getMethod()); + map.put(Fields.TYPE.name(), parameter.getParameterType()); + map.put(Fields.FUNCTION.name(), parameter.getParameterFunction()); + map.put(Fields.CURRENT_MODE.name(), parameter.getCurrentMode()); this.timeStamp = timeStamp; } @@ -76,8 +79,11 @@ public int getNumberOfValues(String name) { @Override public Object getObject(String name) { - Object object = map.get(name); - return object; + switch(Fields.valueOf(name)){ + case MAP: return map; + default:; + } + return null; } @Override @@ -483,5 +489,12 @@ public PlcResponseCode getResponseCode(String name) { public String toString() { return "S7ModeEvent{" + "timeStamp=" + timeStamp + ", map=" + map + '}'; } + + @Override + public Map getMap() { + return map; + } + + } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Notify8pEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Notify8pEvent.java deleted file mode 100644 index 9afcf2fa86e..00000000000 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7Notify8pEvent.java +++ /dev/null @@ -1,28 +0,0 @@ -/* -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.protocol.event; - -/** - * - * @author cgarcia - */ -public class S7Notify8pEvent { - -} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7NotifyEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7NotifyEvent.java deleted file mode 100644 index 56e27c15e73..00000000000 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7NotifyEvent.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.apache.plc4x.java.s7.protocol.event; - -/** - * - * @author cgarcia - */ -public class S7NotifyEvent { - -} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7SysEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7SysEvent.java index c24a18aa223..30890622f28 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7SysEvent.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7SysEvent.java @@ -40,24 +40,28 @@ Licensed to the Apache Software Foundation (ASF) under one */ public class S7SysEvent implements S7Event{ - public static final String EVENT_ID = "EVENT_ID"; - public static final String PRIORITY_CLASS = "PRIORITY_CLASS"; - public static final String OB_NUMBER = "OB_NUMBER"; - public static final String DAT_ID = "DAT_ID"; - public static final String INFO1 = "INFO1"; - public static final String INFO2 = "INFO2"; + public enum Fields{ + TIMESTAMP, + EVENT_ID, + PRIORITY_CLASS, + OB_NUMBER, + DAT_ID, + INFO1, + INFO2 + } private final Instant timeStamp; private Map map = new HashMap(); public S7SysEvent(CpuDiagnosticMessageItem item) { - map.put(EVENT_ID, item.getEventID()); - map.put(PRIORITY_CLASS, item.getPriorityClass()); - map.put(OB_NUMBER, item.getObNumber()); - map.put(DAT_ID, item.getDatID()); - map.put(INFO1, item.getInfo1()); - map.put(INFO2, item.getInfo2()); + map.put(Fields.EVENT_ID.name(), item.getEventID()); + map.put(Fields.PRIORITY_CLASS.name(), item.getPriorityClass()); + map.put(Fields.OB_NUMBER.name(), item.getObNumber()); + map.put(Fields.DAT_ID.name(), item.getDatID()); + map.put(Fields.INFO1.name(), item.getInfo1()); + map.put(Fields.INFO2.name(), item.getInfo2()); this.timeStamp = item.getTimeStamp().toInstant(ZoneOffset.UTC); + map.put(Fields.TIMESTAMP.name(),this.timeStamp); } @Override @@ -77,7 +81,11 @@ public int getNumberOfValues(String name) { @Override public Object getObject(String name) { - throw new UnsupportedOperationException("Not supported yet."); + switch(S7AlarmEvent.Fields.valueOf(name)){ + case MAP: return map; + default:; + } + return null; } @Override @@ -339,7 +347,11 @@ public boolean isValidString(String name, int index) { @Override public String getString(String name) { - throw new UnsupportedOperationException("Not supported yet."); + Object object = map.get(name); + if (object instanceof Integer){ + return object.toString(); + } + return null; } @Override @@ -471,6 +483,11 @@ public PlcResponseCode getResponseCode(String name) { public String toString() { return "S7SysEvent{" + "timeStamp=" + timeStamp + ", map=" + map + '}'; } + + @Override + public Map getMap() { + return map; + } From 30aa0e23392f9ea95361d16949b7bf3771627bc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Wed, 26 Feb 2020 07:53:40 -0400 Subject: [PATCH 09/17] Fix some write problems. --- .../plc4x/java/s7/model/S7SslField.java | 1 - .../plc4x/java/s7/netty/Plc4XS7Protocol.java | 45 +- .../plc4x/java/s7/netty/S7Protocol.java | 217 +++- .../model/payloads/items/VarPayloadItem.java | 10 + .../model/types/DataTransportErrorCode.java | 6 +- .../s7/netty/model/types/TransportSize.java | 33 +- .../java/s7/netty/util/S7SizeHelper.java | 5 +- .../java/s7/protocol/S7ByteReadResponse.java | 4 +- .../java/s7/utils/S7DiagnosticEventId.java | 46 +- .../plc4x/java/s7/utils/S7SslHelper.java | 1118 ++++++++++++++++- 10 files changed, 1363 insertions(+), 122 deletions(-) diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7SslField.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7SslField.java index 75d58ec295d..cfed69a72b8 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7SslField.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7SslField.java @@ -54,7 +54,6 @@ public int getIndex() { } public static boolean matches(String fieldString) { - System.out.println("fieldString: " + fieldString); return SSL_ADDRESS_PATTERN.matcher(fieldString).matches(); } 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 0ffd6fec45f..1140cc941ed 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 @@ -846,11 +846,39 @@ protected void decode(ChannelHandlerContext ctx, S7Message msg, List out PlcResponse response = null; if (request instanceof PlcReadRequest) { response = decodeReadResponse(responseMessage, requestContainer); + //If responseMessage is SSL type and response is null + //At moments Alarms and SSL request must be fragmented + if (response == null){ //Fragmented message? Query again! + if (responseMessage.getPayloads().get(0) instanceof CpuServicesPayload){ + requests.put(tpduReference, requestContainer); + S7RequestMessage sslRequestMessage = new S7RequestMessage(MessageType.USER_DATA, + msg.getTpduReference(), + Collections.singletonList(new CpuServicesResponseParameter( + CpuServicesParameterFunctionGroup.CPU_FUNCTIONS, + CpuServicesParameterSubFunctionGroup.READ_SSL, + ((CpuServicesParameter) msg.getParameters().get(0)).getSequenceNumber())), + Collections.singletonList(new CpuServicesPayload(DataTransportErrorCode.NOT_FOUND, + SslId.NULL, + (short) 0x0000)), null); + try { + ChannelFuture future = ctx.writeAndFlush(sslRequestMessage); + future.addListener(new ChannelFutureListener() { + public void operationComplete(ChannelFuture future) { + logger.info("Request fragment READ_SSL done: " + future.isSuccess()); + } + }); + } catch (Exception ex) { + java.util.logging.Logger.getLogger(Plc4XS7Protocol.class.getName()).log(Level.SEVERE, null, ex); + } + } + } + } else if (request instanceof PlcWriteRequest) { response = decodeWriteResponse(responseMessage, requestContainer); } else if (request instanceof PlcSubscriptionRequest) { response = decodeSubscriptionResponse(responseMessage, requestContainer); + //At moments Alarms and SSL request must be fragmented if (response == null){ //Fragmented message? Query again! requests.put(tpduReference, requestContainer); List parameterItems = new LinkedList<>(); @@ -861,13 +889,13 @@ protected void decode(ChannelHandlerContext ctx, S7Message msg, List out 0x0000, null); payloadItems.add(payload); - + //TODO: Check multiple parameters CpuServicesParameter cpuservice = new CpuServicesResponseParameter(CpuServicesParameterFunctionGroup.CPU_FUNCTIONS, CpuServicesParameterSubFunctionGroup.ALARM_QUERY, ((CpuServicesParameter) msg.getParameters().get(0)).getSequenceNumber()); parameterItems.add(cpuservice); - + S7RequestMessage s7ReadRequest = new S7RequestMessage(MessageType.USER_DATA, msg.getTpduReference(), parameterItems, @@ -1069,9 +1097,17 @@ private PlcResponse decodeReadResponse(S7ResponseMessage responseMessage, PlcReq private PlcResponse decodeSslReadResponse(S7ResponseMessage responseMessage, PlcRequestContainer requestContainer) throws PlcProtocolException { InternalPlcReadRequest plcReadRequest = (InternalPlcReadRequest) requestContainer.getRequest(); - Map> values = new HashMap<>(); - + Map> values = new HashMap<>(); List payloads = responseMessage.getPayloads(); + + if (payloads.get(0) instanceof CpuServicesPayload){ + CpuServicesPayload payload = (CpuServicesPayload) payloads.get(0); + if (payload.getSslPayload() == null) { + logger.debug("decodeSslReadResponse: Check for fragment payload"); + return null; + } + } + payloads.forEach((payload)->{ CpuServicesPayload s7payload = (CpuServicesPayload) payload;}); @@ -1083,7 +1119,6 @@ private PlcResponse decodeSslReadResponse(S7ResponseMessage responseMessage, Plc Pair result = new ImmutablePair<>( decodeResponseCode(payload.getReturnCode()), payload.getSslPayload()); - values.put(requestName, result); index++; 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 5ecfdc0d81f..ad3591c5bc4 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 @@ -265,64 +265,94 @@ private void encodePayloads(S7Message in, ByteBuf buf) throws PlcProtocolExcepti } } + /* + * + */ private void encodeWriteVarPayload(VarPayload varPayload, ByteBuf buf, boolean lastItem) { for (VarPayloadItem payloadItem : varPayload.getItems()) { buf.writeByte(payloadItem.getReturnCode().getCode()); buf.writeByte(payloadItem.getDataTransportSize().getCode()); - // TODO: Check if this is correct?!?! Might be problems with sizeInBits = true/false - buf.writeShort(payloadItem.getData().length); - buf.writeBytes(payloadItem.getData()); + //TODO: Check if this is correct?!?! Might be problems with sizeInBits = true/false + //TODO: This field is in BCD + switch (payloadItem.getDataTransportSize()){ + case BIT: + //Check for bits length + buf.writeShort(payloadItem.getData().length); + break; + case BYTE_WORD_DWORD: + case INTEGER: + //Length in bits + buf.writeShort(payloadItem.getData().length * 8); + break; + case NULL: + break; + case DINTEGER: + case OCTET_STRING: + case REAL: + //Length in bytes + buf.writeShort(payloadItem.getData().length); + break; + } + buf.writeBytes(payloadItem.getData()); // if this is not the last item and it's payload is exactly one byte, we need to output a fill-byte. if((payloadItem.getData().length == 1) && !lastItem) { buf.writeByte(0x00); } + + System.out.println("encodeWriteVarPayload ByteBuf:... \r\n" + ByteBufUtil.prettyHexDump(buf)); + } } - private void encodeCpuServicesPayload(CpuServicesPayload cpuServicesPayload, ByteBuf buf) throws PlcProtocolException { buf.writeByte(cpuServicesPayload.getReturnCode().getCode()); + + if (cpuServicesPayload.getReturnCode() == DataTransportErrorCode.NOT_FOUND) { + buf.writeByte(DataTransportSize.NULL.getCode()); + buf.writeShort(0x0000); // This seems to be constantly set to this. - buf.writeByte(DataTransportSize.OCTET_STRING.getCode()); + } else { + buf.writeByte(DataTransportSize.OCTET_STRING.getCode()); - // A request payload is simple. - if (cpuServicesPayload.getSslDataRecords().isEmpty()) { - buf.writeShort(4); - buf.writeShort(cpuServicesPayload.getSslId().getCode()); - buf.writeShort(cpuServicesPayload.getSslIndex()); - } - // The response payload contains a lot more information. - else { - throw new PlcProtocolException("Unexpected SZL Data Records"); - /*short length = 8; - short sizeOfDataItem = 0; - for (SslDataRecord sslDataRecord : cpuServicesPayload.getSslDataRecords()) { - sizeOfDataItem = (short) (sslDataRecord.getLengthInWords() * (short) 2); - length += sizeOfDataItem; + // A request payload is simple. + if (cpuServicesPayload.getSslDataRecords().isEmpty()) { + buf.writeShort(4); + buf.writeShort(cpuServicesPayload.getSslId().getCode()); + buf.writeShort(cpuServicesPayload.getSslIndex()); } - buf.writeShort(length); - buf.writeShort(cpuServicesPayload.getSslId().getCode()); - buf.writeShort(cpuServicesPayload.getSslIndex()); - buf.writeShort(sizeOfDataItem); - buf.writeShort(cpuServicesPayload.getSslDataRecords().size()); - // Output any sort of ssl list items, if there are any. - for (SslDataRecord sslDataRecord : cpuServicesPayload.getSslDataRecords()) { - if(sslDataRecord instanceof SslModuleIdentificationDataRecord) { - SslModuleIdentificationDataRecord midr = (SslModuleIdentificationDataRecord) sslDataRecord; - buf.writeShort(midr.getIndex()); - byte[] articleNumberBytes = midr.getArticleNumber().getBytes(StandardCharsets.UTF_8); - // An array full of 20 spaces. - byte[] data = new byte[]{0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20}; - // Copy max 20 bytes from the article number into the dest array. - System.arraycopy(articleNumberBytes, 0, data, 0, 20); - buf.writeBytes(data); - buf.writeShort(midr.getModuleOrOsVersion()); - buf.writeShort(midr.getPgDescriptionFileVersion()); + // The response payload contains a lot more information. + else { + throw new PlcProtocolException("Unexpected SZL Data Records"); + /*short length = 8; + short sizeOfDataItem = 0; + for (SslDataRecord sslDataRecord : cpuServicesPayload.getSslDataRecords()) { + sizeOfDataItem = (short) (sslDataRecord.getLengthInWords() * (short) 2); + length += sizeOfDataItem; } - }*/ + buf.writeShort(length); + buf.writeShort(cpuServicesPayload.getSslId().getCode()); + buf.writeShort(cpuServicesPayload.getSslIndex()); + buf.writeShort(sizeOfDataItem); + buf.writeShort(cpuServicesPayload.getSslDataRecords().size()); + // Output any sort of ssl list items, if there are any. + for (SslDataRecord sslDataRecord : cpuServicesPayload.getSslDataRecords()) { + if(sslDataRecord instanceof SslModuleIdentificationDataRecord) { + SslModuleIdentificationDataRecord midr = (SslModuleIdentificationDataRecord) sslDataRecord; + buf.writeShort(midr.getIndex()); + byte[] articleNumberBytes = midr.getArticleNumber().getBytes(StandardCharsets.UTF_8); + // An array full of 20 spaces. + byte[] data = new byte[]{0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20}; + // Copy max 20 bytes from the article number into the dest array. + System.arraycopy(articleNumberBytes, 0, data, 0, 20); + buf.writeBytes(data); + buf.writeShort(midr.getModuleOrOsVersion()); + buf.writeShort(midr.getPgDescriptionFileVersion()); + } + }*/ + } } } @@ -1060,7 +1090,7 @@ private CpuServicesParameter decodeCpuServicesParameter(ByteBuf in) { CpuServicesParameterFunctionGroup functionGroup = CpuServicesParameterFunctionGroup.valueOf(typeAndFunctionGroup); - + CpuServicesParameterSubFunctionGroup subFunctionGroup = CpuServicesParameterSubFunctionGroup.valueOf(in.readByte()); @@ -1073,6 +1103,7 @@ private CpuServicesParameter decodeCpuServicesParameter(ByteBuf in) { byte dataUnitReferenceNumber = in.readByte(); boolean lastDataUnit = in.readByte() == 0x00; ParameterError error = ParameterError.valueOf(in.readShort()); + logger.info("decodeParameter.: " + error); return new CpuCyclicServicesResponseParameter(functionGroup, subCycFunctionGroup, sequenceNumber, dataUnitReferenceNumber, lastDataUnit, error); @@ -1085,6 +1116,7 @@ private CpuServicesParameter decodeCpuServicesParameter(ByteBuf in) { byte dataUnitReferenceNumber = in.readByte(); boolean lastDataUnit = in.readByte() == 0x00; ParameterError error = ParameterError.valueOf(in.readShort()); + return new CpuServicesResponseParameter(functionGroup, subFunctionGroup, sequenceNumber, dataUnitReferenceNumber, lastDataUnit, error); } @@ -1154,11 +1186,23 @@ private List decodeReadWriteVarParameter(ByteBuf in, byte numI return items; } - private CpuServicesPayload decodeReadSslPayload(CpuServicesParameter parameter, ByteBuf userData){ + private CpuServicesPayload decodeReadSslPayload(CpuServicesParameter parameter, ByteBuf userData){ + //logger.info("decodeReadSslPayload: \r\n" + ByteBufUtil.prettyHexDump(userData)); + CpuServicesResponseParameter thisparameter = null; + short length; + short dataUnitReferenceNumber = 0x0000; + boolean lastdataunit = true; + DataTransportErrorCode returnCode = DataTransportErrorCode.valueOf(userData.readByte()); DataTransportSize dataTransportSize = DataTransportSize.valueOf(userData.readByte()); - short length; + + if (parameter instanceof CpuServicesResponseParameter){ + thisparameter = (CpuServicesResponseParameter) parameter; + dataUnitReferenceNumber = (short) thisparameter.getDataUnitReferenceNumber(); + lastdataunit = thisparameter.isLastDataUnit(); + } + /* if(dataTransportSize != DataTransportSize.OCTET_STRING) { if(dataTransportSize == DataTransportSize.NULL) { length = userData.readShort(); @@ -1170,39 +1214,78 @@ private CpuServicesPayload decodeReadSslPayload(CpuServicesParameter parameter, } } + */ + length = userData.readShort(); + //If is fragment message + SslId sslId = SslId.NULL; + short sslIndex = 0x0000; + + + //Check for service not found + if (returnCode == DataTransportErrorCode.NOT_FOUND && !lastdataunit){ + userData.clear(); + if (thisparameter != null){ + userData.writeShort(thisparameter.getError().getCode()); + } else { + userData.writeShort(ParameterError.PROTOCOL_ERROR.getCode()); + } + return new CpuServicesPayload(returnCode, sslId, sslIndex, userData); + } - length = userData.readShort(); - SslId sslId = SslId.valueOf(userData.readShort()); - short sslIndex = userData.readShort(); // If the length is 4 there is no `partial list length in bytes` and `partial list count` parameters. if(length == 4) { + //logger.info("decodeReadSslPayload: error response."); + sslId = SslId.valueOf(userData.readShort()); + sslIndex = userData.readShort(); return new CpuServicesPayload(returnCode, sslId, sslIndex); } // If the length is not 4, then it has to be at least 8. - else if(length >= 8) { + else if((length >= 8) || ((length == 0) && lastdataunit)) { + if (!lastdataunit) { + //TODO: Work with two fragments, we need test with 3 and more + Pair> fragments = fragmentedData.get(dataUnitReferenceNumber); + if (fragments != null) { + Queue bytebufqueue = fragments.getValue(); + bytebufqueue.add(userData); + } else { + sslId = SslId.valueOf(userData.readShort()); + sslIndex = userData.readShort(); + Queue bytebufqueue = new ArrayDeque(); + bytebufqueue.add(userData); + Pair> firtsfragment = new ImmutablePair(LocalDateTime.now(), bytebufqueue); + fragmentedData.put(dataUnitReferenceNumber, firtsfragment); + } + return new CpuServicesPayload(returnCode, sslId, sslIndex); + } + + //Reemsable the fragments - // TODO: We should probably ensure we don't read more than this. - // Skip the partial list length in words. - // TODO: Transfer all Payload to the client app. Use helper class. - /* - userData.skipBytes(2); - short partialListCount = userData.readShort(); - List sslDataRecords = new LinkedList<>(); - for(int i = 0; i < partialListCount; i++) { - short index = userData.readShort(); - byte[] articleNumberBytes = new byte[20]; - userData.readBytes(articleNumberBytes); - String articleNumber = new String(articleNumberBytes, StandardCharsets.UTF_8).trim(); - short bgType = userData.readShort(); - short moduleOrOsVersion = userData.readShort(); - short pgDescriptionFileVersion = userData.readShort(); - sslDataRecords.add(new SslModuleIdentificationDataRecord( - index, articleNumber, bgType, moduleOrOsVersion, pgDescriptionFileVersion)); + if (dataUnitReferenceNumber != 0x0000){ + Pair> fragments = fragmentedData.get(dataUnitReferenceNumber); + if (fragments != null){ + Queue bytebufqueue = fragments.getValue(); + ByteBuf payload = bytebufqueue.remove(); + for(ByteBuf nextpayload:bytebufqueue){ + if (nextpayload != null) { + payload.writeBytes(nextpayload); + nextpayload.release(); + }; + } + payload.writeBytes(userData); + userData.clear(); + userData.writeBytes(payload); + payload.release(); + fragmentedData.remove(dataUnitReferenceNumber); + returnCode = DataTransportErrorCode.OK; + } + } else { + sslId = SslId.valueOf(userData.readShort()); + sslIndex = userData.readShort(); } - */ - ByteBuf payload = Unpooled.copiedBuffer(userData); - - return new CpuServicesPayload(returnCode, sslId, sslIndex, payload); + + //TODO: sslId & sslIndex in this point dont care, we need check! + return new CpuServicesPayload(returnCode, sslId, sslIndex, userData); + } // In all other cases, it's probably an error. else { diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/VarPayloadItem.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/VarPayloadItem.java index bfc30d943e3..9cf9b9b39d6 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/VarPayloadItem.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/payloads/items/VarPayloadItem.java @@ -45,4 +45,14 @@ public byte[] getData() { return data; } + @Override + public String toString() { + return "VarPayloadItem{" + + "returnCode=" + returnCode + + ", dataTransportSize=" + dataTransportSize + + ", data=" + data.length + '}'; + } + + + } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/DataTransportErrorCode.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/DataTransportErrorCode.java index bbbd3f5980c..90159606ef0 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/DataTransportErrorCode.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/DataTransportErrorCode.java @@ -18,11 +18,10 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.s7.netty.model.types; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.HashMap; import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public enum DataTransportErrorCode { RESERVED((byte) 0x00), @@ -30,6 +29,7 @@ public enum DataTransportErrorCode { ACCESS_DENIED((byte) 0x03), INVALID_ADDRESS((byte) 0x05), DATA_TYPE_NOT_SUPPORTED((byte) 0x06), + DATA_TYPE_INCONSISTENT((byte) 0x07), NOT_FOUND((byte) 0x0A); private static final Logger logger = LoggerFactory.getLogger(DataTransportErrorCode.class); diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/TransportSize.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/TransportSize.java index 2f806ed86d5..93e96462069 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/TransportSize.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/TransportSize.java @@ -18,9 +18,8 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.s7.netty.model.types; -import org.apache.plc4x.java.s7.types.S7ControllerType; - import java.util.*; +import org.apache.plc4x.java.s7.types.S7ControllerType; public enum TransportSize { @@ -46,17 +45,17 @@ public enum TransportSize { // Integers // ----------------------------------------- // Signed Int - INT(0x05, "W", 2, null, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.ANY), + INT(0x05, "W", 2, null, DataTransportSize.INTEGER, S7ControllerType.ANY), // Unsigned Int - UINT(0x05, "W", 2, INT, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.S7_1200, S7ControllerType.S7_1500), + UINT(0x05, "W", 2, INT, DataTransportSize.INTEGER, S7ControllerType.S7_1200, S7ControllerType.S7_1500), // (Signed) Small Int - SINT(0x02, "B", 1, INT, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.S7_1200, S7ControllerType.S7_1500), + SINT(0x02, "B", 1, INT, DataTransportSize.INTEGER, S7ControllerType.S7_1200, S7ControllerType.S7_1500), // Unsigned Small Int - USINT(0x02, "B", 1, INT, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.S7_1200, S7ControllerType.S7_1500), + USINT(0x02, "B", 1, INT, DataTransportSize.INTEGER, S7ControllerType.S7_1200, S7ControllerType.S7_1500), // Double Precision Int - DINT(0x07, "D", 4, INT, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.ANY), + DINT(0x07, "D", 4, INT, DataTransportSize.INTEGER, S7ControllerType.ANY), // Unsigned Double Precision Int - UDINT(0x07, "D", 4, INT, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.S7_1200, S7ControllerType.S7_1500), + UDINT(0x07, "D", 4, INT, DataTransportSize.INTEGER, S7ControllerType.S7_1200, S7ControllerType.S7_1500), // Only got a basic TIA license (S7-1500 needed to find this out) // TODO: Find the code LINT(0x00, "X", 8, INT, null, S7ControllerType.S7_1500), @@ -67,7 +66,7 @@ public enum TransportSize { // ----------------------------------------- // Reals // ----------------------------------------- - REAL(0x08, "D", 4, null, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.ANY), + REAL(0x08, "D", 4, null, DataTransportSize.REAL, S7ControllerType.ANY), // TODO: Find the code LREAL(0x00, "X", 8, REAL, null, S7ControllerType.S7_1200, S7ControllerType.S7_1200, S7ControllerType.S7_1500), @@ -75,7 +74,7 @@ public enum TransportSize { // Durations // ----------------------------------------- // IEC time - TIME(0x0B, "X", 4, null, null, S7ControllerType.ANY), + TIME(0x0B, "D", 4, null, DataTransportSize.INTEGER, S7ControllerType.ANY), // TODO: Find the code LTIME(0x00, "X", 8, TIME, null, S7ControllerType.S7_1500), @@ -83,32 +82,32 @@ public enum TransportSize { // Date // ----------------------------------------- // IEC date (yyyy-m-d) - DATE(0x02, "X", 2, null, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.ANY), + DATE(0x02, "W", 2, null, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.ANY), // ----------------------------------------- // Time of day // ----------------------------------------- // Time (hh:mm:ss.S) - TIME_OF_DAY(0x02, "X", 4, null, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.ANY), + TIME_OF_DAY(0x02, "D", 4, null, DataTransportSize.INTEGER, S7ControllerType.ANY), // ----------------------------------------- // Date and time of day // ----------------------------------------- - DATE_AND_TIME(0x02, "X", 8, null, null, S7ControllerType.S7_1500, S7ControllerType.S7_300, S7ControllerType.S7_400), + DATE_AND_TIME(0x02, "X", 8, null, DataTransportSize.INTEGER, S7ControllerType.S7_1500, S7ControllerType.S7_300, S7ControllerType.S7_400), // ----------------------------------------- // ASCII Strings // ----------------------------------------- // Single-byte character - CHAR(0x03, "B", 1, null, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.ANY), + CHAR(0x03, "B", 1, null, DataTransportSize.OCTET_STRING, S7ControllerType.ANY), // Double-byte character // TODO: Find the code (Perhaps 0x13) - WCHAR(0x13, "X", 2, null, null, S7ControllerType.S7_1200, S7ControllerType.S7_1500), + WCHAR(0x13, "B", 2, null, null, S7ControllerType.S7_1200, S7ControllerType.S7_1500), // Variable-length single-byte character string - STRING(0x03, "X", 1, null, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.ANY), + STRING(0x03, "B", 1, null, DataTransportSize.OCTET_STRING, S7ControllerType.ANY), // Variable-length double-byte character string // TODO: Find the code (Perhaps 0x13) - WSTRING(0x00, "X", 1, null, null, S7ControllerType.S7_1200, S7ControllerType.S7_1500); + WSTRING(0x00, "B", 1, null, DataTransportSize.OCTET_STRING, S7ControllerType.S7_1200, S7ControllerType.S7_1500); /* TO BE CONTINUED */ diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7SizeHelper.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7SizeHelper.java index 45076458a5b..f1f5849666a 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7SizeHelper.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7SizeHelper.java @@ -33,6 +33,7 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.netty.model.payloads.VarPayload; import org.apache.plc4x.java.s7.netty.model.payloads.items.VarPayloadItem; import org.apache.plc4x.java.s7.netty.model.payloads.ssls.SslDataRecord; +import org.apache.plc4x.java.s7.netty.model.types.DataTransportErrorCode; import org.apache.plc4x.java.s7.netty.model.types.VariableAddressingMode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -69,7 +70,9 @@ public static short getPayloadsLength(List payloads) { } } else if(payload instanceof CpuServicesPayload) { CpuServicesPayload cpuServicesPayload = (CpuServicesPayload) payload; - if(cpuServicesPayload.getSslDataRecords().isEmpty()) { + if(cpuServicesPayload.getReturnCode() == DataTransportErrorCode.NOT_FOUND ){ + return 4; + } else if(cpuServicesPayload.getSslDataRecords().isEmpty()) { return 8; } else { short length = 0; diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7ByteReadResponse.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7ByteReadResponse.java index 27f27c966d2..655cd21945d 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7ByteReadResponse.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7ByteReadResponse.java @@ -30,7 +30,6 @@ Licensed to the Apache Software Foundation (ASF) under one import java.util.Objects; import org.apache.commons.lang3.tuple.Pair; import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; -import org.apache.plc4x.java.api.exceptions.PlcRuntimeException; import org.apache.plc4x.java.api.model.PlcField; import org.apache.plc4x.java.api.types.PlcResponseCode; import org.apache.plc4x.java.base.messages.InternalPlcReadRequest; @@ -470,9 +469,12 @@ protected ByteBuf getByteBufInternal(String name) { if (values.get(name) == null) { throw new PlcInvalidFieldException(name); } + //TODO: Check for error respont + /* if (values.get(name).getKey() != PlcResponseCode.OK) { throw new PlcRuntimeException("Field '" + name + "' could not be fetched, response was " + values.get(name).getKey()); } + */ // No need to check for "null" as this is already captured by the constructors. return values.get(name).getValue(); } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7DiagnosticEventId.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7DiagnosticEventId.java index 741ac4417e6..e03890fbccd 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7DiagnosticEventId.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7DiagnosticEventId.java @@ -630,7 +630,7 @@ public enum S7DiagnosticEventId { //Event Classes F - Reserved for modules not in central // rack (for example, CPs or FMs) - EVENTID_0x0000((short) 0x0000, "NULL"),; + EVENTID_0x0000((short) 0x0000, "NULL: Check for user information."); @@ -641,8 +641,8 @@ public enum S7DiagnosticEventId { static { map = new HashMap<>(); idstr = new HashMap<>(); - for (S7DiagnosticEventId subevent : S7DiagnosticEventId .values()) { - map.put(subevent.code, subevent); + for (S7DiagnosticEventId event : S7DiagnosticEventId.values()) { + map.put(event.code, event); } idstr.put((short) 0x0000, "Event leaving state. "); @@ -652,40 +652,34 @@ public enum S7DiagnosticEventId { idstr.put((short) 0x0800, "External error. "); } - private final String event; + private final String description; private final short code; - S7DiagnosticEventId(short code, String event){ - this.event = event; - this.code = code; + S7DiagnosticEventId(final short code, final String description){ + this.code = code; + this.description = description; } - public String getEvent(){ - short id = (short) (code & 0x0F00); - return event; + public String getDescription(){ + //short id = (short) (code & 0x0F00); + return description; } public short getCode() { return code; } - - public static S7DiagnosticEventId valueOfEvent(String event) { - for (S7DiagnosticEventId value : S7DiagnosticEventId .values()) { - if(value.getEvent().equals(event)) { - return value; - } - } - return null; - } public static S7DiagnosticEventId valueOf(short code) { - if ((code > 0x8000) & (code < 0xA000)){ - if ((code != 0x9101) & (code != 0x9190) & (code != 0x91F0) - & (code != 0x91F1) & (code != 0x91F2) - & (code != 0x91F3)) - code = (short) (code & 0xF0FF); - } - return map.get(code); + Integer intcode = Short.toUnsignedInt(code); + + if ((intcode > 0x8000) && (intcode < 0xA000)){ + if ((intcode != 0x9101) && (intcode != 0x9190) && (intcode != 0x91F0) + && (intcode != 0x91F1) && (intcode != 0x91F2) + && (intcode != 0x91F3)) + intcode = (intcode & 0xF0FF); + } else if (((intcode >= 0xA000) && (intcode <= 0xBFFF))) intcode = 0x0000; + + return map.get(intcode.shortValue()); } } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7SslHelper.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7SslHelper.java index 61965a3507a..d667769f698 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7SslHelper.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7SslHelper.java @@ -19,10 +19,1126 @@ Licensed to the Apache Software Foundation (ASF) under one package org.apache.plc4x.java.s7.utils; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + /** - * + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * |15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| + * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + * \__________/\__________/\____________________/ + * Module Number of Number of the partial + * class the partial list + * list + * extract + * + * Module Class: + * +--------------+-----------------+ + * | Module class | Coding (Binary) | + * +--------------|-----------------+ + * | CPU | 0000 | + * +--------------|-----------------+ + * | IM | 0100 | + * +--------------|-----------------+ + * | FM | 1000 | + * +--------------|-----------------+ + * | CP | 1100 | + * +--------------|-----------------+ + * + * Possible SSL Partial Lists: + * +-----------------------------------------------------------|--------------+ + * | Module class | SSL-ID | + * +-----------------------------------------------------------|--------------+ + * | Module identification | 16#xy11 | + * +-----------------------------------------------------------|--------------+ + * | CPU characteristics | 16#xy12 | + * +-----------------------------------------------------------|--------------+ + * | User memory areas | 16#xy13 | + * +-----------------------------------------------------------|--------------+ + * | System areas | 16#xy14 | + * +-----------------------------------------------------------|--------------+ + * | Block types | 16#xy15 | + * +-----------------------------------------------------------|--------------+ + * | Interrupt status | 16#xy22 | + * +-----------------------------------------------------------|--------------+ + * | Assignment between process image partitions and OBs | 16#xy25 | + * +-----------------------------------------------------------|--------------+ + * | Communication status data | 16#xy32 | + * +-----------------------------------------------------------|--------------+ + * | H CPU group information | 16#xy71 | + * +-----------------------------------------------------------|--------------+ + * | Status of the module LEDs | 16#xy74 | + * +-----------------------------------------------------------|--------------+ + * | Switched DP slaves in the H-system | 16#xy75 | + * +-----------------------------------------------------------|--------------+ + * | Module status information | 16#xy91 | + * +-----------------------------------------------------------|--------------+ + * | Rack / station status information | 16#xy92 | + * +-----------------------------------------------------------|--------------+ + * | Rack / station status information | 16#xy94 | + * +-----------------------------------------------------------|--------------+ + * | Extended DP master system / PROFINET IO system information| 16#xy95 | + * +-----------------------------------------------------------|--------------+ + * | Module status information, PROFINET IO and PROFIBUS DP | 16#xy96 | + * +-----------------------------------------------------------|--------------+ + * | Tool changer information (PROFINET IO) | 16#xy9C | + * +-----------------------------------------------------------|--------------+ + * | Diagnostic buffer of the CPU | 16#xyA0 | + * +-----------------------------------------------------------|--------------+ + * | Module diagnostic information (data record 0) | 16#xyB1 | + * +-----------------------------------------------------------|--------------+ + * | Module diagnostic information (data record 1), | 16#xyB2 | + * | geographical address | | + * +-----------------------------------------------------------|--------------+ + * | Module diagnostic information (data record 1), | 16#xyB3 | + * | logical address | | + * +-----------------------------------------------------------|--------------+ + * | Diagnostic data of a DP slave | 16#xyB4 | + * +-----------------------------------------------------------|--------------+ + * + * * @author cgarcia */ + public class S7SslHelper { + /** + * + */ + public enum OB { + FREE_CYC(0X0000,"OB1 Free cycle"), + + //Time of day + TOD_INT0(0X000A,"OB10 Time of day interrupt"), + TOD_INT1(0X000B,"OB11 Time of day interrupt"), + TOD_INT2(0X000C,"OB12 Time of day interrupt"), + TOD_INT3(0X000D,"OB13 Time of day interrupt"), + TOD_INT4(0X000E,"OB14 Time of day interrupt"), + TOD_INT5(0X000F,"OB15 Time of day interrupt"), + TOD_INT6(0X0010,"OB16 Time of day interrupt"), + TOD_INT7(0X0011,"OB17 Time of day interrupt"), + + //Time delay + DEL_INT0(0X0014,"OB20 Time delay interrupt"), + DEL_INT1(0X0015,"OB21 Time delay interrupt"), + DEL_INT2(0X0016,"OB22 Time delay interrupt"), + DEL_INT3(0X0017,"OB23 Time delay interrupt"), + + //Cyclic + CYC_INT0(0X001E,"OB30 Cyclic interrupt"), + CYC_INT1(0X001F,"OB31 Cyclic interrupt"), + CYC_INT2(0X0020,"OB32 Cyclic interrupt"), + CYC_INT3(0X0021,"OB33 Cyclic interrupt"), + CYC_INT4(0X0022,"OB34 Cyclic interrupt"), + CYC_INT5(0X0023,"OB35 Cyclic interrupt"), + CYC_INT6(0X0024,"OB36 Cyclic interrupt"), + CYC_INT7(0X0025,"OB37 Cyclic interrupt"), + CYC_INT8(0X0026,"OB38 Cyclic interrupt"), + + //Hardware interrupts + HW_INT0(0X0028,"OB40 Hardware interrupt"), + HW_INT1(0X0029,"OB41 Hardware interrupt"), + HW_INT2(0X002A,"OB42 Hardware interrupt"), + HW_INT3(0X002B,"OB43 Hardware interrupt"), + HW_INT4(0X002C,"OB44 Hardware interrupt"), + HW_INT5(0X002D,"OB45 Hardware interrupt"), + HW_INT6(0X002E,"OB46 Hardware interrupt"), + HW_INT7(0X002F,"OB47 Hardware interrupt"), + + //Startup + BACKGROUND(0X005A,"OB90 Background"), + COMPLETE_RESTART(0X0064,"OB100 Startup"), + RESTART(0X0064,"OB101 Background"), + COLD_RESTART(0X005A,"OB101 Background"), + + //Fault interrupts + CYC_FLT(0X0051,"OB80 Time execution error interrupt"), + PS_FLT(0X0051,"OB81 Power supply interrupt"), + IO_FLT1(0X0052,"OB82 Module diagnostic interrupt"), + IO_FLT2(0X0053,"OB83 Module change interrupt"), + CPU_FLT(0X0054,"OB84 CPU hardware error interrupt"), + OBNL_FLT(0X0055,"OB85 Program execution error interrupt"), + RACK_FLT(0X0056,"OB86 Rack fault interrupt"), + COMM_FLT(0X0057,"OB87 Communication error interrupt"), + BREAKUP_ERR(0X0058,"OB88 Process interrupt"), + SYNC_ERR(0X0079,"OB120 Synchronous error interrupt"), + PROG_ERR(0X0079,"OB121 Program error interrupt"), + MOD_ERR(0X007A,"OB122 Module error interrupt"); + + private int code; + private String description; + + private static final Map map; + + static { + map = new HashMap<>(); + for (OB obid : OB.values()) { + map.put(obid.code, obid); + } + } + + OB(final int code, final String description){ + this.code = code; + this.description = description; + } + + public int getCode(){ + return code; + } + + public String getDescription(){ + return description; + } + + public static OB valueOf(int code) { + return map.get(code); + } + + + } + + + /** + * + */ + public enum MODULE{ + CPU(0X00), + IM(0X04), + FM(0X80), + CP(0XC0); + + private int code; + + MODULE(final int code){ + this.code = code; + } + + public int getCode(){ + return code; + } + } + + /** + * + */ + public enum LED_ID { + SF(0X0001,"Group error"), + INTF(0X0002,"Internal error"), + EXTF(0X0003,"External error"), + RUN(0X0004,"RUN"), + STOP(0X0005,"STOP"), + FRCE(0X0006,"Force"), + CRST(0X0007,"Cold restart"), + BAF(0X0008,"Battery fault"), + USR(0X0009,"User defined"), + USR1(0X000A,"User defined"), + BUS1F(0X000B,"Bus error interface 1"), + BUS2F(0X000C,"Bus error interface 2"), + REDF(0X000D,"Redundancy error"), + MSTR(0X000E,"Master"), + RACK0(0X000F,"Rack number 0"), + RACK1(0X0010,"Rack number 1"), + RACK2(0X0011,"Rack number 2"), + IFM1F(0X0012,"Interface error interface module 1"), + IFM2F(0X0013,"Interface error interface module 2"), + BUS3F(0X0014,"Bus error interface 3"), + MAINT(0X0015,"Maintenance demand"), + DC24V(0X0016,"DC24V"), + BUS5F(0X0017,"Bus error interface 5"), + BUS8F(0X0018,"Bus error interface 8"), + IF(0X0080,"Init failure"), + UF(0X0081,"User failure"), + MF(0X0082,"Monitoring failure"), + CF(0X0083,"Communication failure"), + TF(0X0084,"Task failure"), + APPL_STATE_RED(0X00EC,"APPL_STATE_RED"), + APPL_STATE_GREEN(0X00ED,"APPL_STATE_GREEN"); + + private int code; + private String description; + + private static final Map map; + + static { + map = new HashMap<>(); + for (LED_ID ledid : LED_ID.values()) { + map.put(ledid.code, ledid); + } + } + + LED_ID(final int code, final String description){ + this.code = code; + this.description = description; + } + + public int getCode(){ + return code; + } + + public String getDescription(){ + return description; + } + + public static LED_ID valueOf(int code) { + return map.get(code); + } + + + } + + /** + * + */ + public enum CPU_CHARACTERISTICS { + CH_0x0000(0X0000,"MC7 processing unit (group with index 0000)"), + CH_0x0001(0X0001,"MC7 processing generating code"), + CH_0x0002(0X0002,"MC7 interpreter"), + + CH_0x0100(0X0100,"Time system (group with index 0100)"), + CH_0x0101(0X0101,"1 ms resolution"), + CH_0x0102(0X0102,"10 ms resolution"), + CH_0x0103(0X0103,"No real time clock"), + CH_0x0104(0X0104,"BCD time-of-day format"), + CH_0x0105(0X0105,"All time-of-day functions"), + CH_0x0106(0X0106,"SFC 78 \"OB_RT\" is available"), + + CH_0x0200(0X0200,"System response (group with index 0200)"), + CH_0x0201(0X0201,"Capable of multiprocessor mode"), + CH_0x0202(0X0202,"Cold restart, warm restart and hot restart possible"), + CH_0x0203(0X0203,"Cold restart and hot restart possible"), + CH_0x0204(0X0204,"Warm restart and hot restart possible"), + CH_0x0205(0X0205,"Only warm restart possible"), + CH_0x0206(0X0206,"New distributed I/O configuration is possible during\n" + + "RUN by using predefined resources"), + CH_0x0207(0X0207,"H-CPU in stand-alone mode: New distributed I/O configuration\n" + + "is possible during RUN by using predefined resources"), + CH_0x0208(0X0208,"For taking motion control functionality into account"), + + CH_0x0300(0X0300,"MC7 Language description of the CPU (group with index 0300)"), + CH_0x0301(0X0301,"Reserved"), + CH_0x0302(0X0302,"All 32 bit fixed-point instructions"), + CH_0x0303(0X0303,"All floating-point instructions"), + CH_0x0304(0X0304,"sin, asin, cos, acos, tan, atan, sqr, sqrt, ln, exp"), + CH_0x0305(0X0305,"Accumulator 3/accumulator 4 with corresponding instructions\n" + + "(ENT,PUSH,POP,LEAVE)"), + CH_0x0306(0X0306,"Master Control Relay instructions"), + CH_0x0307(0X0307,"Address register 1 exists with corresponding instructions"), + CH_0x0308(0X0308,"Address register 2 exists with corresponding instructions"), + CH_0x0309(0X0309,"Operations for area-crossing addressing"), + CH_0x030A(0X030A,"Operations for area-internal addressing"), + CH_0x030B(0X030B,"All memory-indirect addressing instructions for bit memory (M)"), + CH_0x030C(0X030C,"All memory-indirect addressing instructions for data blocks (DB)"), + CH_0x030D(0X030D,"All memory-indirect addressing instructions for data blocks (DI)"), + CH_0x030E(0X030E,"All memory-indirect addressing instructions for local data (L)"), + CH_0x030F(0X030F,"All instructions for parameter transfer in FCs"), + CH_0x0310(0X0310,"Memory bit edge instructions for process image input (I)"), + CH_0x0311(0X0311,"Memory bit edge instructions for process image output (Q)"), + CH_0x0312(0X0312,"Memory bit edge instructions for bit memory (M)"), + CH_0x0313(0X0313,"Memory bit edge instructions for data blocks (DB)"), + CH_0x0314(0X0314,"Memory bit edge instructions for data blocks (DI)"), + CH_0x0315(0X0315,"Memory bit edge instructions for local data (L)"), + CH_0x0316(0X0316,"Dynamic evaluation of the FC bit"), + CH_0x0317(0X0317,"Dynamic local data area with the corresponding instructions"), + CH_0x0318(0X0318,"Reserved"), + CH_0x0319(0X0319,"Reserved"), + + CH_0x0401(0X0401,"SFC 87 \"C_DIAG\" is available"), + CH_0x0402(0X0402,"SFC 88 \"C_CNTRL\" is available)"); + + private int code; + private String description; + + private static final Map map; + + static { + map = new HashMap<>(); + for (CPU_CHARACTERISTICS cpuc : CPU_CHARACTERISTICS.values()) { + map.put(cpuc.code, cpuc); + } + } + + CPU_CHARACTERISTICS(final int code, final String description){ + this.code = code; + this.description = description; + } + + public int getCode(){ + return code; + } + + public String getDescription(){ + return description; + } + + public static CPU_CHARACTERISTICS valueOf(int code) { + return map.get(code); + } + + + } + + /** + * + */ + public enum SSL { + ID_0x0011(0x0011,"Module identification."){ + @Override + public StringBuilder execute(ByteBuf data) { + return ID_0xXY11(data); + } + + }, + ID_0x0012(0x0012,"CPU characteristics ."){ + @Override + public StringBuilder execute(ByteBuf data) { + return ID_0xXY12(data); + } + + }, + ID_0x0013(0x0013,"User memory areas."){ + @Override + public StringBuilder execute(ByteBuf data) { + return ID_0xXY13(data); + } + + }, + ID_0x0014(0x0014,"System areas."){ + @Override + public StringBuilder execute(ByteBuf data) { + return ID_0xXY14(data); + } + + }, + ID_0x0015(0x0015,"Block types."){ + @Override + public StringBuilder execute(ByteBuf data) { + return ID_0xXY15(data); + } + + }, + ID_0x001C(0x001C,"Component identification."){ + @Override + public StringBuilder execute(ByteBuf data) { + return ID_0xXY1C(data); + } + + }, + ID_0x0022(0x0022,"Interrupt status."){ + @Override + public StringBuilder execute(ByteBuf data) { + return ID_0xXY22(data); + } + + }, + ID_0x0025(0x0025,"Assignment between process image partitions and OBs."){ + @Override + public StringBuilder execute(ByteBuf data) { + return ID_0xXY25(data); + } + + }, + ID_0x0032(0x0032,"Communication status data."){ + @Override + public StringBuilder execute(ByteBuf data) { + return ID_0xXY32(data); + } + + }, + ID_0x0071(0x0071,"H CPU group information."){ + @Override + public StringBuilder execute(ByteBuf data) { + return ID_0xXY71(data); + } + + }, + ID_0x0074(0x0074,"Status of the module LEDs."){ + @Override + public StringBuilder execute(ByteBuf data) { + return ID_0xXY74(data); + } + + }, + ID_0x0075(0x0075,"Switched DP slaves in the H-system."){ + @Override + public StringBuilder execute(ByteBuf data) { + return ID_0xXY75(data); + } + + }, + ID_0x0090(0x0090,"DP Master System Information."){ + @Override + public StringBuilder execute(ByteBuf data) { + return ID_0xXY90(data); + } + + }, + ID_0x0091(0x0091,"Module status information."){ + @Override + public StringBuilder execute(ByteBuf data) { + return ID_0xXY91(data); + } + + }, + ID_0x0092(0x0092,"Rack / station status information."){ + @Override + public StringBuilder execute(ByteBuf data) { + return ID_0xXY92(data); + } + + }, + ID_0x0094(0x0094,"Rack / station status information."){ + @Override + public StringBuilder execute(ByteBuf data) { + return ID_0xXY94(data); + } + + }, + ID_0x0095(0x0095,"Extended DP master system / PROFINET IO system information."){ + @Override + public StringBuilder execute(ByteBuf data) { + return ID_0xXY95(data); + } + + }, + ID_0x0096(0x0096,"Module status information, PROFINET IO and PROFIBUS DP."){ + @Override + public StringBuilder execute(ByteBuf data) { + return ID_0xXY96(data); + } + + }, + ID_0x009C(0x009C,"Tool changer information (PROFINET IO)."){ + @Override + public StringBuilder execute(ByteBuf data) { + return ID_0xXY9C(data); + } + + }, + ID_0x00A0(0x00A0,"Diagnostic buffer of the CPU."){ + @Override + public StringBuilder execute(ByteBuf data) { + return ID_0xXYA0(data); + } + + }, + ID_0x00B1(0x00B1,"Module diagnostic information (data record 0) ."){ + @Override + public StringBuilder execute(ByteBuf data) { + return ID_0xXYB1(data); + } + + }, + ID_0x00B2(0x00B2,"Module diagnostic information (data record 1),geographical address."){ + @Override + public StringBuilder execute(ByteBuf data) { + return ID_0xXYB2(data); + } + + }, + ID_0x00B3(0x00B3,"Module diagnostic information (data record 1),logical address."){ + @Override + public StringBuilder execute(ByteBuf data) { + return ID_0xXYB3(data); + } + + }, + ID_0x00B4(0x00B4,"Diagnostic data of a DP slave."){ + @Override + public StringBuilder execute(ByteBuf data) { + return ID_0xXYB4(data); + } + + }; + + private int code; + private String description; + + private static final Map map; + + static { + map = new HashMap<>(); + for (SSL subssl : SSL.values()) { + map.put(subssl.code, subssl); + } + } + + SSL(final int code, final String description){ + this.code = code; + this.description = description; + } + + public int getCode(){ + return code; + } + + public String getDescription(){ + return description; + } + + public static SSL valueOf(int code) { + return map.get(code); + } + + public abstract StringBuilder execute(ByteBuf data); + + private static StringBuilder ID_0xXY11(ByteBuf data){ + StringBuilder sb = new StringBuilder(); + int ssl_length = data.readShort(); + int ssl_count = data.readShort(); + try { + sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n"); + sb.append("SSL partial list count: ").append(ssl_count).append("\r\n"); + for (int i=1; i <= ssl_count; i++){ + sb.append("Data Record: ").append(i).append("\r\n"); + + sb.append("Index: ").append(data.readShort()).append("\r\n"); + byte[] bytestr = new byte[20]; + data.readBytes(bytestr, 0, 20); + sb.append("Mlfb (Order number): ").append(new String(bytestr)).append("\r\n"); + sb.append("BGTyp (Moduler type ID): ").append(data.readShort()).append("\r\n"); + sb.append("Ausbg (Version of the module/hardware version): ").append(data.readShort()).append("\r\n"); + sb.append("Ausbe (Firmware version): ").append(data.readShort()).append("\r\n"); + } + } catch (Exception ex){ + sb.append(ex.toString()); + } + return sb; + } + + private static StringBuilder ID_0xXY12(ByteBuf data){ + StringBuilder sb = new StringBuilder(); + int ssl_length = data.readShort(); + int ssl_count = data.readShort(); + try { + sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n"); + sb.append("SSL partial list count: ").append(ssl_count).append("\r\n"); + for (int i=1; i <= ssl_count; i++){ + sb.append("Data Record: ").append(i).append("\r\n"); + int code = data.readShort(); + sb.append(CPU_CHARACTERISTICS.valueOf(code)).append(": "). + append(CPU_CHARACTERISTICS.valueOf(code).getDescription()).append("\r\n"); + } + } catch (Exception ex){ + sb.append(ex.toString()); + } + return sb; + } + + private static StringBuilder ID_0xXY13(ByteBuf data){ + StringBuilder sb = new StringBuilder(); + int ssl_length = data.readShort(); + int ssl_count = data.readShort(); + try { + sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n"); + sb.append("SSL partial list count: ").append(ssl_count).append("\r\n"); + for (int i=1; i <= ssl_count; i++){ + sb.append("Data Record: ").append(i).append("\r\n"); + sb.append("Index: ").append(data.readShort()).append("\r\n"); + int code = data.readShort(); + int size = data.readInt(); + int mode = data.readShort(); + int granu = data.readShort(); + int ber1 = data.readInt(); + int be1egt1 = data.readInt(); + int block1 = data.readInt(); + int ber2 = data.readInt(); + int be1egt2 = data.readInt(); + int block2 = data.readInt(); + + switch(code){ + case 0x0001:sb.append("Code (Memory Type): ").append("Volatile memory (RAM)\r\n"); + break; + case 0x0002:sb.append("Code (Memory Type): ").append("Non-volatile memory (FEPROM)\r\n"); + break; + case 0x0003:sb.append("Code (Memory Type): ").append("mixed memory (RAM + FEPROM)\r\n"); + break; + } + sb.append("Size (Total size of the selected memory (total of area 1 and area 2)): ").append(size).append("\r\n"); + + sb.append("Mode (Volatile memory area): ").append(((mode & 0x0001) != 0)).append("\r\n"); + sb.append("Mode (Non-volatile memory area): ").append(((mode & 0x0002) != 0)).append("\r\n"); + sb.append("Mode (Mixed memory area): ").append(((mode & 0x0004) != 0)).append("\r\n"); + sb.append("Mode (Code and data separate): ").append(((mode & 0x0008) != 0)).append("\r\n"); + sb.append("Mode (Code and data together): ").append(((mode & 0x0010) != 0)).append("\r\n"); + + sb.append("Granu (Always zero): ").append(granu).append("\r\n"); + + sb.append("Ber1 (Size of the volatile memory area in bytes): ").append(ber1).append("\r\n"); + sb.append("Belegt1 (Size of the volatile memory area being used): ").append(be1egt1).append("\r\n"); + sb.append("Block1 (Largest free block in the volatile memory area): ").append(block1).append("\r\n"); + + sb.append("Ber2 (Size of the non-volatile memory area in bytes): ").append(ber2).append("\r\n"); + sb.append("Belegt2 (Size of the non-volatile memory area being used): ").append(be1egt2).append("\r\n"); + sb.append("Block2 (Largest free block in the non-volatile memory area): ").append(block2).append("\r\n"); + + } + } catch (Exception ex){ + sb.append(ex.toString()); + } + return sb; + } + + private static StringBuilder ID_0xXY14(ByteBuf data){ + StringBuilder sb = new StringBuilder(); + int ssl_length = data.readShort(); + int ssl_count = data.readShort(); + try { + sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n"); + sb.append("SSL partial list count: ").append(ssl_count).append("\r\n"); + for (int i=1; i <= ssl_count; i++){ + int index = data.readShort(); + int code = data.readShort(); + int quantity = data.readShort(); + int reman = data.readShort(); + + sb.append("Data Record: ").append(i).append("\r\n"); + sb.append("Index: ").append(index).append(" System area: "); + switch(index) { + case 0x0001: sb.append("PII (number in bytes)").append("\r\n"); + break; + case 0x0002: sb.append("PIQ (number in bytes))").append("\r\n"); + break; + case 0x0003: sb.append("memory (number in bits)").append("\r\n"); + break; + case 0x0004: sb.append("timers (number)").append("\r\n"); + break; + case 0x0005: sb.append("counter (number)").append("\r\n"); + break; + case 0x0006: sb.append("number of bytes in the logical address area)").append("\r\n"); + break; + case 0x0007: sb.append("local data (entire local data area of the CPU in bytes)").append("\r\n"); + break; + case 0x0008: sb.append("memory (number in bytes)").append("\r\n"); + break; + case 0x0009: sb.append("local data (entire local data area of the CPU in Kbytes)").append("\r\n"); + break; + } + sb.append("Code: ").append(code).append(" Memory type: "); + switch(code) { + case 0x0001: sb.append("volatile memory (RAM)").append("\r\n"); + break; + case 0x0002: sb.append("non-volatile memory (FEPROM)").append("\r\n"); + break; + case 0x0003: sb.append("mixed memory (RAM and FEPROM)").append("\r\n"); + break; + } + sb.append("Quantity: ").append(quantity).append("\r\n"); + sb.append("Reman: ").append(reman).append("\r\n"); + } + } catch (Exception ex){ + sb.append(ex.toString()); + } + return sb; + } + + private static StringBuilder ID_0xXY15(ByteBuf data){ + StringBuilder sb = new StringBuilder(); + int ssl_length = data.readShort(); + int ssl_count = data.readShort(); + try { + sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n");; + sb.append("SSL partial list count: ").append(ssl_count).append("\r\n");; + + for (int i=1; i <= ssl_count; i++){ + sb.append("Data Record: ").append(i).append("\r\n"); + int type = data.readShort(); + switch(type){ + case 0x0800: sb.append("Block type: OB\r\n"); + break; + case 0x0A00: sb.append("Block type: DB\r\n"); + break; + case 0x0B00: sb.append("Block type: SDB\r\n"); + break; + case 0x0C00: sb.append("Block type: FC\r\n"); + break; + case 0x0E00: sb.append("Block type: FB\r\n"); + break; + default: + } + sb.append("Maximum number of blocks of the type: ").append(data.readShort()).append("\r\n"); ; + sb.append("Maximum total size of the object to be loaded in Kbytes: ").append(data.readShort()).append("\r\n"); ; + sb.append("Maximum length of the work memory part of a block in bytes: ").append(data.readInt()).append("\r\n"); ; + } + } catch (Exception ex){ + sb.append(ex.toString()); + } + return sb; + } + + private static StringBuilder ID_0xXY1C(ByteBuf data){ + StringBuilder sb = new StringBuilder(); + int ssl_length = data.readShort(); + int ssl_count = data.readShort(); + try { + sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n");; + sb.append("SSL partial list count: ").append(ssl_count).append("\r\n");; + + for (int i=1; i <= ssl_count; i++){ + sb.append("Data Record: ").append(i).append("\r\n"); + int index = data.getShort(data.readerIndex()); + int index_b0 = data.readByte(); + int index_b1 = data.readByte(); + sb.append("Index: ").append(index).append("\r\n"); + sb.append("Index b1: ").append(index_b1).append("\r\n"); + + switch(index_b1){ + case 0x01: + case 0x02: { + byte[] strbyte = new byte[24]; + data.readBytes(strbyte, 0, 24); + sb.append("Name: ").append(new String(strbyte)).append("\r\n"); + ByteBuf data2 = data.readSlice(8); + sb.append("Reserved: ").append(ByteBufUtil.hexDump(data2)).append("\r\n"); + }; + break; + case 0x03: { + byte[] strbyte = new byte[32]; + data.readBytes(strbyte, 0, 32); + sb.append("Tag: ").append(new String(strbyte)).append("\r\n"); + }; + break; + case 0x04: { + byte[] strbyte = new byte[26]; + data.readBytes(strbyte, 0, 26); + sb.append("Copyright: ").append(new String(strbyte)).append("\r\n"); + ByteBuf data2 = data.readSlice(6); + sb.append("Reserved: ").append(ByteBufUtil.hexDump(data2)).append("\r\n"); + }; + break; + case 0x05: { + byte[] strbyte = new byte[24]; + data.readBytes(strbyte, 0, 24); + sb.append("Serial: ").append(new String(strbyte)).append("\r\n"); + ByteBuf data2 = data.readSlice(8); + sb.append("Reserved: ").append(ByteBufUtil.hexDump(data2)).append("\r\n"); + }; + break; + case 0x06: { + + }; + break; + case 0x07: { + byte[] strbyte = new byte[32]; + data.readBytes(strbyte, 0, 32); + sb.append("Cpu type: ").append(new String(strbyte)).append("\r\n"); + }; + break; + case 0x08: { + byte[] strbyte = new byte[32]; + data.readBytes(strbyte, 0, 32); + sb.append("Serial mc/mmc: ").append(new String(strbyte)).append("\r\n"); + }; + break; + case 0x09: { + sb.append("Manufacturer ID: ").append(data.readShort()).append("\r\n"); + sb.append("Profile ID: ").append(data.readShort()).append("\r\n"); + sb.append("Profile specific type: ").append(data.readShort()).append("\r\n"); + ByteBuf data2 = data.readSlice(26); + sb.append("Reserved: ").append(ByteBufUtil.hexDump(data2)).append("\r\n"); + }; + break; + case 0x0A: { + byte[] strbyte = new byte[26]; + data.readBytes(strbyte, 0, 26); + sb.append("OEM copyright: ").append(new String(strbyte)).append("\r\n"); + sb.append("OEM ID: ").append(data.readShort()).append("\r\n"); + sb.append("OEM add ID: ").append(data.readInt()).append("\r\n"); + }; + break; + case 0x0B: { + byte[] strbyte = new byte[32]; + data.readBytes(strbyte, 0, 32); + sb.append("Location ID: ").append(new String(strbyte)).append("\r\n"); + }; + break; + case 0x0C: { + byte[] strbyte = new byte[10]; + data.readBytes(strbyte, 0, 10); + sb.append("Order number sync module 1: ").append(new String(strbyte)).append("\r\n"); + data.readShort(); + byte[] strbyte2 = new byte[2]; + data.readBytes(strbyte2, 0, 2); + sb.append("Product version: ").append(new String(strbyte2)).append("\r\n"); + data.readByte(); + ByteBuf data2 = data.readSlice(17); + sb.append("Vendor serial: ").append(ByteBufUtil.hexDump(data2)).append("\r\n"); + }; + break; + case 0x0D: { + byte[] strbyte = new byte[10]; + data.readBytes(strbyte, 0, 10); + sb.append("Order number sync module 2: ").append(new String(strbyte)).append("\r\n"); + data.readShort(); + byte[] strbyte2 = new byte[2]; + data.readBytes(strbyte2, 0, 2); + sb.append("Product version: ").append(new String(strbyte2)).append("\r\n"); + data.readByte(); + ByteBuf data2 = data.readSlice(17); + sb.append("Vendor serial: ").append(ByteBufUtil.hexDump(data2)).append("\r\n"); + }; + break; + case 0x0E: { + byte[] strbyte = new byte[18]; + data.readBytes(strbyte, 0, 18); + sb.append("Serial number: ").append(new String(strbyte)).append("\r\n"); + ByteBuf data2 = data.readSlice(14); + sb.append("Reserved: ").append(ByteBufUtil.hexDump(data2)).append("\r\n"); + }; + break; + } + + } + } catch (Exception ex){ + sb.append(ex.toString()); + } + return sb; + } + + private static StringBuilder ID_0xXY22(ByteBuf data){ + StringBuilder sb = new StringBuilder(); + int ssl_length = data.readShort(); + int ssl_count = data.readShort(); + + try { + sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n");; + sb.append("SSL partial list count: ").append(ssl_count).append("\r\n");; + + for (int i=1; i <= ssl_count; i++){ + sb.append("Data Record: ").append(i).append("\r\n"); + ByteBuf infobytes = data.readSlice(20); + short al1 = data.readShort(); + short al2 = data.readShort(); + int al3 = data.readInt(); + sb.append("Info: ").append(ByteBufUtil.hexDump(infobytes)).append("\r\n"); + sb.append("al 1: ").append(Integer.toHexString(al1)).append("\r\n"); + sb.append("al 2: ").append(Integer.toHexString(al2)).append("\r\n"); + sb.append("al 3: ").append(Integer.toHexString(al3)).append("\r\n"); + } + }catch (Exception ex){ + sb.append(ex.toString()); + } + return sb; + + } + + private static StringBuilder ID_0xXY25(ByteBuf data){ + StringBuilder sb = new StringBuilder(); + sb.append("It is not implemeted yet!"); + return sb; + } + + private static StringBuilder ID_0xXY32(ByteBuf data){ + StringBuilder sb = new StringBuilder(); + sb.append("It is not implemeted yet!"); + return sb; + } + + private static StringBuilder ID_0xXY71(ByteBuf data){ + StringBuilder sb = new StringBuilder(); + sb.append("It is not implemeted yet!"); + return sb; + } + + private static StringBuilder ID_0xXY74(ByteBuf data){ + StringBuilder sb = new StringBuilder(); + int ssl_length = data.readShort(); + int ssl_count = data.readShort(); + try { + sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n"); + sb.append("SSL partial list count: ").append(ssl_count).append("\r\n"); + for (int i=1; i <= ssl_count; i++){ + sb.append("Data Record: ").append(i).append("\r\n"); + int cpu_type = data.readByte(); + int led_id = data.readByte(); + boolean led_onoff = (data.readByte() != 0x00); + int led_flashing = data.readByte(); + + sb.append("Rack number: ").append((cpu_type & 0x07)).append("\r\n"); + sb.append("CPU Type: ").append((cpu_type & 0x08) == 0x00?"Standby":"Master").append("\r\n"); + sb.append("LED ID: ").append(LED_ID.valueOf(led_id)).append(" (").append(LED_ID.valueOf(led_id).description).append(")\r\n"); + sb.append("LED status: ").append(led_onoff).append("\r\n"); + switch(led_flashing){ + case 0x00: sb.append("LED flashing: not.").append("\r\n"); + break; + case 0x01: sb.append("LED blinking: normally (2 Hz).").append("\r\n"); + break; + case 0x02: sb.append("LED blinking: slowly (0.5 Hz).").append("\r\n"); + break; + default: sb.append("LED blinking: no information.").append("\r\n"); + } + } + } catch (Exception ex){ + sb.append(ex.toString()); + } + return sb; + } + + private static StringBuilder ID_0xXY75(ByteBuf data){ + StringBuilder sb = new StringBuilder(); + sb.append("It is not implemeted yet!"); + return sb; + } + + private static StringBuilder ID_0xXY90(ByteBuf data){ + StringBuilder sb = new StringBuilder(); + sb.append("It is not implemeted yet!"); + return sb; + } + + private static StringBuilder ID_0xXY91(ByteBuf data){ + StringBuilder sb = new StringBuilder(); + sb.append("It is not implemeted yet!"); + return sb; + } + + private static StringBuilder ID_0xXY92(ByteBuf data){ + StringBuilder sb = new StringBuilder(); + sb.append("It is not implemeted yet!"); + return sb; + } + + private static StringBuilder ID_0xXY94(ByteBuf data){ + StringBuilder sb = new StringBuilder(); + sb.append("It is not implemeted yet!"); + return sb; + } + + private static StringBuilder ID_0xXY95(ByteBuf data){ + StringBuilder sb = new StringBuilder(); + sb.append("It is not implemeted yet!"); + return sb; + } + + private static StringBuilder ID_0xXY96(ByteBuf data){ + StringBuilder sb = new StringBuilder(); + sb.append("It is not implemeted yet!"); + return sb; + } + + private static StringBuilder ID_0xXY9C(ByteBuf data){ + StringBuilder sb = new StringBuilder(); + sb.append("It is not implemeted yet!"); + return sb; + } + + private static StringBuilder ID_0xXYA0(ByteBuf data){ + StringBuilder sb = new StringBuilder(); + int ssl_length = data.readShort(); + int ssl_count = data.readShort(); + + try{ + sb.append("SSL partial list length in bytes: ").append(ssl_length).append("\r\n"); + sb.append("SSL partial list count: ").append(ssl_count).append("\r\n"); + int i = 1; + while(data.isReadable()){ + sb.append("Data Record: ").append(i).append("\r\n"); + Short id = data.readShort(); + + sb.append("ID: ").append(id).append("\r\n"); + ByteBuf infobytes = data.readSlice(10); + sb.append("Info: ").append(ByteBufUtil.hexDump(infobytes)).append("\r\n"); + infobytes = data.readSlice(8); + sb.append("Timestamp: ").append(readDateAndTime(infobytes).toString()).append("\r\n"); + sb.append("Desc: ").append(S7DiagnosticEventId.valueOf(id).getDescription()).append("\r\n"); + i++; + } + } catch (Exception ex){ + sb.append(ex.toString()); + } + + return sb; + } + + private static StringBuilder ID_0xXYB1(ByteBuf data){ + StringBuilder sb = new StringBuilder(); + sb.append("It is not implemeted yet!"); + return sb; + } + + private static StringBuilder ID_0xXYB2(ByteBuf data){ + StringBuilder sb = new StringBuilder(); + sb.append("It is not implemeted yet!"); + return sb; + } + + private static StringBuilder ID_0xXYB3(ByteBuf data){ + StringBuilder sb = new StringBuilder(); + sb.append("It is not implemeted yet!"); + return sb; + } + + private static StringBuilder ID_0xXYB4(ByteBuf data){ + StringBuilder sb = new StringBuilder(); + sb.append("It is not implemeted yet!"); + return sb; + } + + /* + * Date and time of day (BCD coded). + * +----------------+ + * Byte n | Year 0 to 99 | + * +----------------+ + * Byte n+1 | Month 1 to 12 | + * +----------------+ + * Byte n+2 | Day 1 to 31 | + * +----------------+ + * Byte n+3 | Hour 0 to 23 | + * +----------------+ + * Byte n+4 | Minute 0 to 59 | + * +----------------+ + * Byte n+5 | Second 0 to 59 | + * +----------------+ + * Byte n+6 | ms 0 to 999 | + * Byte n+7 | X X X X X D O W| + * +----------------+ + * DOW: Day of weed (last 3 bits) + */ + private static LocalDateTime readDateAndTime(ByteBuf data) { + //from Plc4XS7Protocol + int year=convertByteToBcd(data.readByte()); + byte themonth = data.readByte(); + int month=convertByteToBcd(themonth==0x00?0x01:themonth); + byte theday = data.readByte(); + int day=convertByteToBcd(theday==0x00?0x01:theday); + int hour=convertByteToBcd(data.readByte()); + int minute=convertByteToBcd(data.readByte()); + int second=convertByteToBcd(data.readByte()); + int milliseconds = (data.readShort() & 0xfff0) >> 4; + + int cen = ((milliseconds & 0x0f00) >> 8) * 100; + int dec = ((milliseconds & 0x00f0) >> 4) * 10; + milliseconds = cen + dec + (milliseconds & 0x000f); + int nanoseconds = milliseconds * 1000000; + + //data-type ranges from 1990 up to 2089 + if(year>=90){ + year+=1900; + } + else{ + year+=2000; + } + + return LocalDateTime.of(year,month,day,hour,minute,second, nanoseconds); + } + + + /** + * converts incoming byte to an integer regarding used BCD format + * @param incomingByte + * @return converted BCD number + */ + private static int convertByteToBcd(byte incomingByte) { + int dec = (incomingByte >> 4) * 10; + return dec + (incomingByte & 0x0f); + } + + +} + + + + } From d81d405ab5c9e66a9ae1e06a2da026cf88d29e10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Mon, 9 Mar 2020 15:08:19 -0400 Subject: [PATCH 10/17] Modified the message delivery. STRINGS management, BITS fixes and missing S7 types. --- .../java/api/messages/PlcReadResponse.java | 11 + .../java/api/messages/PlcWriteRequest.java | 3 + .../java/s7/connection/S7PlcConnection.java | 5 +- .../connection/DefaultPlcFieldHandler.java | 5 + .../java/base/connection/PlcFieldHandler.java | 2 + .../base/messages/DefaultPlcReadResponse.java | 34 + .../base/messages/DefaultPlcWriteRequest.java | 41 +- .../messages/items/BaseDefaultFieldItem.java | 14 +- .../messages/items/DefaultByteFieldItem.java | 3 +- .../items/DefaultDurationFieldItem.java | 54 ++ .../items/DefaultIntegerFieldItem.java | 15 +- .../items/DefaultLocalDateFieldItem.java | 8 +- .../items/DefaultLocalTimeFieldItem.java | 8 +- .../items/DefaultStringFieldItem.java | 11 + .../apache/plc4x/java/s7/model/S7Field.java | 22 +- .../plc4x/java/s7/netty/Plc4XS7Protocol.java | 584 +++++++++++----- .../plc4x/java/s7/netty/S7Protocol.java | 67 +- .../plc4x/java/s7/netty/events/S7Alarm.java | 29 + .../model/messages/S7RequestMessage.java | 33 +- .../s7/netty/model/types/TransportSize.java | 24 +- .../strategies/DefaultS7MessageProcessor.java | 44 +- .../LongS7MessageProcessorCodec.java | 655 ++++++++++++++++++ .../java/s7/netty/util/S7PlcFieldHandler.java | 122 +++- .../netty/util/S7ResponseSizeEstimator.java | 14 +- .../java/s7/netty/util/S7SizeHelper.java | 6 + .../java/s7/protocol/S7ByteReadResponse.java | 26 + .../java/s7/protocol/event/S7AlarmEvent.java | 29 + .../java/s7/protocol/event/S7ModeEvent.java | 26 + .../java/s7/protocol/event/S7SysEvent.java | 26 + .../utils/{S7SslHelper.java => S7Helper.java} | 203 +++++- 30 files changed, 1882 insertions(+), 242 deletions(-) create mode 100644 plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultDurationFieldItem.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/strategies/LongS7MessageProcessorCodec.java rename plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/{S7SslHelper.java => S7Helper.java} (87%) diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcReadResponse.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcReadResponse.java index e160b166708..82d6e655335 100644 --- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcReadResponse.java +++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcReadResponse.java @@ -20,6 +20,7 @@ Licensed to the Apache Software Foundation (ASF) under one import java.math.BigDecimal; import java.math.BigInteger; +import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; @@ -170,6 +171,16 @@ public interface PlcReadResponse extends PlcFieldResponse { LocalDateTime getDateTime(String name, int index); Collection getAllDateTimes(String name); + + boolean isValidDuration(String name); + + boolean isValidDuration(String name, int index); + + Duration getDuration(String name); + + Duration getDuration(String name, int index); + + Collection getAllDuration(String name); boolean isValidByteArray(String name); diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcWriteRequest.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcWriteRequest.java index 95de45872eb..5d5a494299f 100644 --- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcWriteRequest.java +++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/messages/PlcWriteRequest.java @@ -20,6 +20,7 @@ Licensed to the Apache Software Foundation (ASF) under one import java.math.BigDecimal; import java.math.BigInteger; +import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; @@ -62,6 +63,8 @@ interface Builder extends PlcRequestBuilder { PlcWriteRequest.Builder addItem(String name, String fieldQuery, LocalDate... values); PlcWriteRequest.Builder addItem(String name, String fieldQuery, LocalDateTime... values); + + PlcWriteRequest.Builder addItem(String name, String fieldQuery, Duration... values); PlcWriteRequest.Builder addItem(String name, String fieldQuery, byte[]... values); diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java index 0a214df8187..4e3b8c589d2 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java @@ -78,7 +78,7 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.netty.model.types.CpuServicesParameterSubFunctionGroup; import org.apache.plc4x.java.s7.netty.model.types.MemoryArea; import org.apache.plc4x.java.s7.netty.model.types.SubscribedEventType; -import org.apache.plc4x.java.s7.netty.strategies.DefaultS7MessageProcessor; +import org.apache.plc4x.java.s7.netty.strategies.LongS7MessageProcessorCodec; import org.apache.plc4x.java.s7.netty.util.S7PlcFieldEventHandler; import org.apache.plc4x.java.s7.netty.util.S7PlcFieldHandler; import org.apache.plc4x.java.s7.protocol.S7CyclicServicesSubscriptionHandle; @@ -263,7 +263,8 @@ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exc pipeline.addLast(new IsoOnTcpProtocol()); pipeline.addLast(new IsoTPProtocol(callingTsapId, calledTsapId, TpduSize.valueForGivenSize(paramPduSize))); pipeline.addLast(new S7Protocol(paramMaxAmqCaller, paramMaxAmqCallee, paramPduSize, paramControllerType, - new DefaultS7MessageProcessor())); + null)); //null <-> new DefaultS7MessageProcessor() + pipeline.addLast(new LongS7MessageProcessorCodec()); pipeline.addLast(new Plc4XS7Protocol(alarmsqueue)); } }; diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/connection/DefaultPlcFieldHandler.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/connection/DefaultPlcFieldHandler.java index 6b90bab98a5..70dcd03633e 100644 --- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/connection/DefaultPlcFieldHandler.java +++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/connection/DefaultPlcFieldHandler.java @@ -93,6 +93,11 @@ public BaseDefaultFieldItem encodeDate(PlcField field, Object[] values) { public BaseDefaultFieldItem encodeDateTime(PlcField field, Object[] values) { throw new PlcRuntimeException("Invalid encoder for type " + field); } + + @Override + public BaseDefaultFieldItem encodeDuration(PlcField field, Object[] values) { + throw new PlcRuntimeException("Invalid encoder for type " + field); + } @Override public BaseDefaultFieldItem encodeByteArray(PlcField field, Object[] values) { diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/connection/PlcFieldHandler.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/connection/PlcFieldHandler.java index 146e6850bc4..b83d29f90b8 100644 --- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/connection/PlcFieldHandler.java +++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/connection/PlcFieldHandler.java @@ -54,6 +54,8 @@ public interface PlcFieldHandler { BaseDefaultFieldItem encodeDate(PlcField field, Object[] values); BaseDefaultFieldItem encodeDateTime(PlcField field, Object[] values); + + BaseDefaultFieldItem encodeDuration(PlcField field, Object[] values); BaseDefaultFieldItem encodeByteArray(PlcField field, Object[] values); diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcReadResponse.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcReadResponse.java index 42dacf137b8..035cf89b524 100644 --- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcReadResponse.java +++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcReadResponse.java @@ -20,6 +20,7 @@ Licensed to the Apache Software Foundation (ASF) under one import java.math.BigDecimal; import java.math.BigInteger; +import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; @@ -531,6 +532,39 @@ public Collection getAllDateTimes(String name) { return values; } + @Override + public boolean isValidDuration(String name) { + return isValidDuration(name, 0); + } + + @Override + public boolean isValidDuration(String name, int index) { + BaseDefaultFieldItem fieldInternal = getFieldInternal(name); + return fieldInternal.isValidDateTime(index); + } + + @Override + public Duration getDuration(String name) { + return getDuration(name, 0); + } + + @Override + public Duration getDuration(String name, int index) { + BaseDefaultFieldItem fieldInternal = getFieldInternal(name); + return fieldInternal.getDuration(index); + } + + @Override + public Collection getAllDuration(String name) { + BaseDefaultFieldItem fieldInternal = getFieldInternal(name); + int num = fieldInternal.getNumberOfValues(); + List values = new ArrayList<>(num); + for (int i = 0; i < num; i++) { + values.add(fieldInternal.getDuration(i)); + } + return values; + } + @Override public boolean isValidByteArray(String name) { BaseDefaultFieldItem fieldInternal = getFieldInternal(name); diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcWriteRequest.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcWriteRequest.java index 641bc7eb5f0..af74e05d2b5 100644 --- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcWriteRequest.java +++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/DefaultPlcWriteRequest.java @@ -18,18 +18,9 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.base.messages; -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.commons.lang3.tuple.Triple; -import org.apache.plc4x.java.api.exceptions.PlcRuntimeException; -import org.apache.plc4x.java.api.messages.PlcWriteRequest; -import org.apache.plc4x.java.api.messages.PlcWriteResponse; -import org.apache.plc4x.java.api.model.PlcField; -import org.apache.plc4x.java.base.connection.PlcFieldHandler; -import org.apache.plc4x.java.base.messages.items.BaseDefaultFieldItem; - import java.math.BigDecimal; import java.math.BigInteger; +import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; @@ -37,6 +28,15 @@ Licensed to the Apache Software Foundation (ASF) under one import java.util.concurrent.CompletableFuture; import java.util.function.BiFunction; import java.util.stream.Collectors; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.commons.lang3.tuple.Triple; +import org.apache.plc4x.java.api.exceptions.PlcRuntimeException; +import org.apache.plc4x.java.api.messages.PlcWriteRequest; +import org.apache.plc4x.java.api.messages.PlcWriteResponse; +import org.apache.plc4x.java.api.model.PlcField; +import org.apache.plc4x.java.base.connection.PlcFieldHandler; +import org.apache.plc4x.java.base.messages.items.BaseDefaultFieldItem; public class DefaultPlcWriteRequest implements InternalPlcWriteRequest, InternalPlcFieldRequest { @@ -126,20 +126,23 @@ public Builder(PlcWriter writer, PlcFieldHandler fieldHandler) { fields = new TreeMap<>(); handlerMap = new HashMap<>(); handlerMap.put(Boolean.class, fieldHandler::encodeBoolean); - handlerMap.put(Byte.class, fieldHandler::encodeByte); + handlerMap.put(Byte.class, fieldHandler::encodeByte); handlerMap.put(Short.class, fieldHandler::encodeShort); - handlerMap.put(Integer.class, fieldHandler::encodeInteger); + handlerMap.put(Integer.class, fieldHandler::encodeInteger); handlerMap.put(BigInteger.class, fieldHandler::encodeBigInteger); handlerMap.put(Long.class, fieldHandler::encodeLong); handlerMap.put(Float.class, fieldHandler::encodeFloat); handlerMap.put(Double.class, fieldHandler::encodeDouble); handlerMap.put(BigDecimal.class, fieldHandler::encodeBigDecimal); + handlerMap.put(Character.class, fieldHandler::encodeString); handlerMap.put(String.class, fieldHandler::encodeString); handlerMap.put(LocalTime.class, fieldHandler::encodeTime); handlerMap.put(LocalDate.class, fieldHandler::encodeDate); handlerMap.put(LocalDateTime.class, fieldHandler::encodeDateTime); - handlerMap.put(byte[].class, fieldHandler::encodeByteArray); - handlerMap.put(Byte[].class, fieldHandler::encodeByteArray); + handlerMap.put(Duration.class, fieldHandler::encodeDuration); + //handlerMap.put(byte[].class, fieldHandler::encodeByteArray); + //handlerMap.put(Byte[].class, fieldHandler::encodeByteArray); + //handlerMap.put(Object[].class, fieldHandler::encodeByteArray); } @Override @@ -186,7 +189,7 @@ public Builder addItem(String name, String fieldQuery, Double... values) { public Builder addItem(String name, String fieldQuery, BigDecimal... values) { return addItem(name, fieldQuery, values, fieldHandler::encodeBigDecimal); } - + @Override public Builder addItem(String name, String fieldQuery, String... values) { return addItem(name, fieldQuery, values, fieldHandler::encodeString); @@ -206,6 +209,11 @@ public Builder addItem(String name, String fieldQuery, LocalDate... values) { public Builder addItem(String name, String fieldQuery, LocalDateTime... values) { return addItem(name, fieldQuery, values, fieldHandler::encodeDateTime); } + + @Override + public Builder addItem(String name, String fieldQuery, Duration... values) { + return addItem(name, fieldQuery, values, fieldHandler::encodeDuration); + } @Override public Builder addItem(String name, String fieldQuery, byte[]... values) { @@ -216,6 +224,9 @@ public Builder addItem(String name, String fieldQuery, byte[]... values) { public Builder addItem(String name, String fieldQuery, Byte[]... values) { return addItem(name, fieldQuery, values, fieldHandler::encodeByteArray); } + + //@Override + @Override public Builder addItem(String name, String fieldQuery, T... values) { diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/BaseDefaultFieldItem.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/BaseDefaultFieldItem.java index 4abcda54689..24c6d2868be 100644 --- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/BaseDefaultFieldItem.java +++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/BaseDefaultFieldItem.java @@ -18,16 +18,16 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.base.messages.items; -import org.apache.plc4x.java.api.exceptions.PlcFieldRangeException; -import org.apache.plc4x.java.api.exceptions.PlcIncompatibleDatatypeException; - import java.math.BigDecimal; import java.math.BigInteger; +import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.Arrays; import java.util.Objects; +import org.apache.plc4x.java.api.exceptions.PlcFieldRangeException; +import org.apache.plc4x.java.api.exceptions.PlcIncompatibleDatatypeException; public abstract class BaseDefaultFieldItem { @@ -146,6 +146,14 @@ public boolean isValidDateTime(int index) { public LocalDateTime getDateTime(int index) { throw new PlcIncompatibleDatatypeException(LocalDateTime.class, index); } + + public boolean isValidDuration(int index) { + return false; + } + + public Duration getDuration(int index) { + throw new PlcIncompatibleDatatypeException(LocalDateTime.class, index); + } public boolean isValidByteArray(int index) { return false; diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultByteFieldItem.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultByteFieldItem.java index 6e00e83f29e..2eb7ccf4050 100644 --- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultByteFieldItem.java +++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultByteFieldItem.java @@ -18,10 +18,9 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.base.messages.items; -import org.apache.plc4x.java.api.exceptions.PlcIncompatibleDatatypeException; - import java.math.BigDecimal; import java.math.BigInteger; +import org.apache.plc4x.java.api.exceptions.PlcIncompatibleDatatypeException; public class DefaultByteFieldItem extends BaseDefaultFieldItem { diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultDurationFieldItem.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultDurationFieldItem.java new file mode 100644 index 00000000000..542fd70496f --- /dev/null +++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultDurationFieldItem.java @@ -0,0 +1,54 @@ +/* +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.base.messages.items; + +import java.time.Duration; +import org.apache.plc4x.java.api.exceptions.PlcIncompatibleDatatypeException; +import org.apache.plc4x.java.base.messages.items.BaseDefaultFieldItem; + +/** + * + * @author cgarcia + */ +public class DefaultDurationFieldItem extends BaseDefaultFieldItem { + + public DefaultDurationFieldItem(Duration... values) { + super(values); + } + + @Override + public Object getObject(int index) { + return getValue(index); + } + + @Override + public boolean isValidDuration(int index) { + return getValue(index) != null; + } + + @Override + public Duration getDuration(int index) { + if (!isValidDuration(index)) { + throw new PlcIncompatibleDatatypeException(Duration.class, index); + } + return getValue(index); + } + + +} diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultIntegerFieldItem.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultIntegerFieldItem.java index f998a7bdfdf..6d59c102756 100644 --- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultIntegerFieldItem.java +++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultIntegerFieldItem.java @@ -18,17 +18,17 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.base.messages.items; -import org.apache.plc4x.java.api.exceptions.PlcIncompatibleDatatypeException; - import java.math.BigDecimal; import java.math.BigInteger; +import java.time.LocalTime; +import org.apache.plc4x.java.api.exceptions.PlcIncompatibleDatatypeException; public class DefaultIntegerFieldItem extends BaseDefaultFieldItem { public DefaultIntegerFieldItem(Integer... values) { super(values); } - + @Override public Object getObject(int index) { return getValue(index); @@ -149,5 +149,14 @@ public BigDecimal getBigDecimal(int index) { return new BigDecimal(getValue(index)); } + @Override + public LocalTime getTime(int index) { + System.out.println("DefaultIntegerFieldItem: getTime"); + return super.getTime(index); //To change body of generated methods, choose Tools | Templates. + } + + + + } diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultLocalDateFieldItem.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultLocalDateFieldItem.java index 70cb68c7ef8..aaf6f215696 100644 --- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultLocalDateFieldItem.java +++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultLocalDateFieldItem.java @@ -18,9 +18,8 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.base.messages.items; -import org.apache.plc4x.java.api.exceptions.PlcIncompatibleDatatypeException; - import java.time.LocalDate; +import org.apache.plc4x.java.api.exceptions.PlcIncompatibleDatatypeException; public class DefaultLocalDateFieldItem extends BaseDefaultFieldItem { @@ -38,6 +37,11 @@ public boolean isValidDate(int index) { return getValue(index) != null; } + @Override + public Short getShort(int index) { + return super.getShort(index); + } + @Override public LocalDate getDate(int index) { if (!isValidDate(index)) { diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultLocalTimeFieldItem.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultLocalTimeFieldItem.java index 59c7d8b57b2..15f45930ec6 100644 --- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultLocalTimeFieldItem.java +++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultLocalTimeFieldItem.java @@ -18,9 +18,8 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.base.messages.items; -import org.apache.plc4x.java.api.exceptions.PlcIncompatibleDatatypeException; - import java.time.LocalTime; +import org.apache.plc4x.java.api.exceptions.PlcIncompatibleDatatypeException; public class DefaultLocalTimeFieldItem extends BaseDefaultFieldItem { @@ -38,6 +37,11 @@ public boolean isValidTime(int index) { return getValue(index) != null; } + @Override + public Integer getInteger(int index) { + return super.getInteger(index); + } + @Override public LocalTime getTime(int index) { if (!isValidTime(index)) { diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultStringFieldItem.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultStringFieldItem.java index ee443196e5a..35b5ded4439 100644 --- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultStringFieldItem.java +++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/messages/items/DefaultStringFieldItem.java @@ -31,11 +31,22 @@ public Object getObject(int index) { return getValue(index); } + @Override + public boolean isValidByte(int index) { + return getValue(index) != null; + } + @Override public boolean isValidString(int index) { return getValue(index) != null; } + @Override + public Byte getByte(int index) { + return (byte) ((String) getValue(index)).charAt(0); + } + + @Override public String getString(int index) { if (!isValidString(index)) { diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java index f3a3de06da1..d132c6fc02b 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java @@ -18,6 +18,7 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.s7.model; +import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; @@ -33,11 +34,12 @@ public class S7Field implements PlcField { //byteOffset theoretically can reach up to 2097151 ... see checkByteOffset() below --> 7digits private static final Pattern ADDRESS_PATTERN = - Pattern.compile("^%(?.)(?[XBWD]?)(?\\d{1,7})(.(?[0-7]))?:(?[a-zA-Z_]+)(\\[(?\\d+)])?"); + Pattern.compile("^%(?.)(?[XBWD]?)(?\\d{1,7})(.(?[0-7]))?:(?[a-zA-Z_5][S5TIME]+)(\\[(?\\d+)])?"); //blockNumber usually has its max hat around 64000 --> 5digits + //TODO: S5TIME non include; private static final Pattern DATA_BLOCK_ADDRESS_PATTERN = - Pattern.compile("^%DB(?\\d{1,5}).DB(?[XBWD]?)(?\\d{1,7})(.(?[0-7]))?:(?[a-zA-Z_]+)(\\[(?\\d+)])?"); + Pattern.compile("^%DB(?\\d{1,5}).DB(?[XBWD]?)(?\\d{1,7})(.(?[0-7]))?:(?[a-zA-Z_5]+)(\\[(?\\d+)])?"); private static final String DATA_TYPE = "dataType"; private static final String TRANSFER_SIZE_CODE = "transferSizeCode"; @@ -121,8 +123,13 @@ public Class getDefaultJavaType() { return LocalDateTime.class; case DATE: return LocalDate.class; + case S5TIME: + return Duration.class; + case TIME: + return Duration.class; + case TOD: case TIME_OF_DAY: - return LocalTime.class; + return LocalTime.class; default: throw new NotImplementedException("The response type for datatype " + dataType + " is not yet implemented"); } @@ -174,7 +181,12 @@ public static S7Field of(String fieldString) { if(matcher.group(NUM_ELEMENTS) != null) { numElements = Integer.parseInt(matcher.group(NUM_ELEMENTS)); } + numElements = calcNumberOfElementsForIndividualTypes(numElements,dataType); + if(dataType.equals(TransportSize.STRING)){ + numElements = 1; + } + if(!transferSizeCode.isEmpty() && !dataType.getSizeCode().equals(transferSizeCode)) { throw new PlcInvalidFieldException("Transfer size code '" + transferSizeCode + "' doesn't match specified data type '" + dataType.name() + "'"); @@ -219,8 +231,10 @@ private static int checkByteOffset(int byteOffset){ * @param dataType detected Transport-Size that represents the data-type * @return corrected numElements if nessesary */ + //TODO: private static int calcNumberOfElementsForIndividualTypes(int numElements, TransportSize dataType){ - + + //TODO: for this version STRING is write like CHAR if(dataType.equals(TransportSize.STRING)){ //on valid String-length add two byte because of S7-representation of Strings if(numElements>1 && numElements<=254){ 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 1140cc941ed..a33b6d63dc2 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 @@ -19,10 +19,11 @@ Licensed to the Apache Software Foundation (ASF) under one package org.apache.plc4x.java.s7.netty; import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; +import io.netty.buffer.PooledByteBufAllocator; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; +import io.netty.util.AttributeKey; import java.io.IOException; import java.lang.reflect.Array; import java.math.BigInteger; @@ -32,7 +33,6 @@ Licensed to the Apache Software Foundation (ASF) under one import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; -import java.time.temporal.ChronoUnit; import java.util.*; import java.util.concurrent.BlockingQueue; import java.util.concurrent.atomic.AtomicInteger; @@ -90,6 +90,7 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.protocol.S7ByteReadResponse; import org.apache.plc4x.java.s7.protocol.S7CyclicServicesSubscriptionHandle; import org.apache.plc4x.java.s7.protocol.S7DiagnosticSubscriptionHandle; +import org.apache.plc4x.java.s7.utils.S7Helper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -105,14 +106,25 @@ Licensed to the Apache Software Foundation (ASF) under one public class Plc4XS7Protocol extends PlcMessageToMessageCodec { private static final Logger logger = LoggerFactory.getLogger( Plc4XS7Protocol.class ); - private static final AtomicInteger tpduGenerator = new AtomicInteger(10); + public static final AtomicInteger tpduGenerator = new AtomicInteger(10); + private final AttributeKey tpduGeneratorKey = AttributeKey.valueOf("tpduGeneratorKey"); private Map requests; + /* + * Each layer of Netty must do its work, it sends the Requests and must + * verify the answers. + * Special case of the array bits, I need to know if additional messages + * were created. + * Key:Tpdu, Left:Item row, Rigth: Num of Items created-1 + */ + private final Map> requestBitArray; + private final BlockingQueue alarmsqueue; public Plc4XS7Protocol() { this.requests = new HashMap<>(); + this.requestBitArray = new HashMap<>(); this.alarmsqueue = null; } /* @@ -121,12 +133,11 @@ public Plc4XS7Protocol() { */ public Plc4XS7Protocol(BlockingQueue alarmsqueue) { this.requests = new HashMap<>(); + this.requestBitArray = new HashMap<>(); //We need check the device here this.alarmsqueue = alarmsqueue; } - - - + /** * If this protocol layer catches an {@link S7ConnectedEvent} from the protocol layer beneath, * the connection establishment is finished. @@ -137,6 +148,7 @@ public Plc4XS7Protocol(BlockingQueue alarmsqueue) { */ @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + ctx.channel().attr(tpduGeneratorKey).set(tpduGenerator); if (evt instanceof S7ConnectedEvent) { ctx.channel().pipeline().fireUserEventTriggered(new ConnectedEvent()); } else { @@ -566,6 +578,9 @@ private void encodeReadRequest(PlcRequestContainer msg, List out) throws PlcReadRequest readRequest = (PlcReadRequest) msg.getRequest(); + Short itemRow = 0; + Short tpdu = (short) tpduGenerator.getAndIncrement(); + for (String fieldName : readRequest.getFieldNames()) { PlcField field = readRequest.getField(fieldName); @@ -579,19 +594,36 @@ private void encodeReadRequest(PlcRequestContainer msg, List out) throws } S7Field s7Field = (S7Field) field; + if(!(readRequest instanceof DefaultPlcReadRequest)) { + throw new PlcException("The writeRequest should have been of type DefaultPlcWriteRequest"); + } + + if (s7Field.getDataType() == TransportSize.BOOL){ + encodeWriteRequestBitFieldAndArray( tpdu, + itemRow, + null, + s7Field, + parameterItems, + Collections.EMPTY_LIST); + } else { + + VarParameterItem varParameterItem = new S7AnyVarParameterItem( + SpecificationType.VARIABLE_SPECIFICATION, s7Field.getMemoryArea(), + s7Field.getDataType(), + s7Field.getNumElements(), s7Field.getBlockNumber(), s7Field.getByteOffset(), (byte) s7Field.getBitOffset()); + parameterItems.add(varParameterItem); + } + - VarParameterItem varParameterItem = new S7AnyVarParameterItem( - SpecificationType.VARIABLE_SPECIFICATION, s7Field.getMemoryArea(), - s7Field.getDataType(), - s7Field.getNumElements(), s7Field.getBlockNumber(), s7Field.getByteOffset(), (byte) s7Field.getBitOffset()); - parameterItems.add(varParameterItem); } + itemRow++; } + VarParameter readVarParameter = new VarParameter(ParameterType.READ_VAR, parameterItems); // Assemble the request. S7RequestMessage s7ReadRequest = new S7RequestMessage(MessageType.JOB, - (short) tpduGenerator.getAndIncrement(), Collections.singletonList(readVarParameter), + tpdu, Collections.singletonList(readVarParameter), Collections.emptyList(), msg); requests.put(s7ReadRequest.getTpduReference(), msg); @@ -614,12 +646,15 @@ private void encodeSslReadRequest(PlcRequestContainer msg, S7SslField sslfield, out.add(szlRequestMessage); } - + // TODO: private void encodeWriteRequest(PlcRequestContainer msg, List out) throws PlcException { List parameterItems = new LinkedList<>(); List payloadItems = new LinkedList<>(); PlcWriteRequest writeRequest = (PlcWriteRequest) msg.getRequest(); + + Short itemRow = 0; + Short tpdu = (short) tpduGenerator.getAndIncrement(); for (String fieldName : writeRequest.getFieldNames()) { PlcField field = writeRequest.getField(fieldName); if (!(field instanceof S7Field)) { @@ -634,106 +669,206 @@ private void encodeWriteRequest(PlcRequestContainer msg, List out) throw // The number of elements provided in the request must match the number defined in the field, or // bad things are going to happen. // An exception is STRINGS, as they are implemented as byte arrays + // TODO: Calculate the number of correct elements for a "STRING", + // since it will be written to the PLC as a string of "CHAR" elements. if (s7Field.getDataType() != TransportSize.STRING && writeRequest.getNumberOfValues(fieldName) != s7Field.getNumElements()) { throw new PlcException("The number of values provided doesn't match the number specified by the field."); } - VarParameterItem varParameterItem = new S7AnyVarParameterItem( - SpecificationType.VARIABLE_SPECIFICATION, s7Field.getMemoryArea(), - s7Field.getDataType(), - s7Field.getNumElements(), s7Field.getBlockNumber(), s7Field.getByteOffset(), (byte) s7Field.getBitOffset()); - parameterItems.add(varParameterItem); + + //TODO: Bit Arrays: One item request for every bit + + if (s7Field.getDataType() == TransportSize.BOOL) { + + encodeWriteRequestBitFieldAndArray( tpdu, + itemRow, + fieldItem, + s7Field, + parameterItems, + payloadItems); + + } else { - DataTransportSize dataTransportSize = s7Field.getDataType().getDataTransportSize(); + VarParameterItem varParameterItem = new S7AnyVarParameterItem( + SpecificationType.VARIABLE_SPECIFICATION, s7Field.getMemoryArea(), + s7Field.getDataType(), + (s7Field.getDataType() == TransportSize.STRING)?fieldItem.getString(0).length()+2:s7Field.getNumElements(), + s7Field.getBlockNumber(), + s7Field.getByteOffset(), + (byte) s7Field.getBitOffset()); - // TODO: Checkout if the payload items are sort of a flatMap of all request items. - byte[] byteData; - switch(s7Field.getDataType()) { - // ----------------------------------------- - // Bit - // ----------------------------------------- - case BOOL: - byteData = encodeWriteRequestBitField(fieldItem); - break; - // ----------------------------------------- - // Signed integer values - // ----------------------------------------- - case BYTE: - case SINT: - case CHAR: // 1 byte - byteData = encodeWriteRequestByteField(fieldItem, true); - break; - case WORD: - case INT: - case WCHAR: // 2 byte (16 bit) - byteData = encodeWriteRequestShortField(fieldItem, true); - break; - case DWORD: - case DINT: // 4 byte (32 bit) - byteData = encodeWriteRequestIntegerField(fieldItem, true); - break; - case LWORD: - case LINT: // 8 byte (64 bit) - byteData = encodeWriteRequestLongField(fieldItem, true); - break; - // ----------------------------------------- - // Unsigned integer values - // ----------------------------------------- - // 8 bit: - case USINT: - byteData = encodeWriteRequestByteField(fieldItem, false); - break; - // 16 bit: - case UINT: - byteData = encodeWriteRequestShortField(fieldItem, false); - break; - // 32 bit: - case UDINT: - byteData = encodeWriteRequestIntegerField(fieldItem, false); - break; - // 64 bit: - case ULINT: - byteData = encodeWriteRequestLongField(fieldItem, false); - break; - // ----------------------------------------- - // Floating point values - // ----------------------------------------- - case REAL: - byteData = encodeWriteRequestFloatField(fieldItem); - break; - case LREAL: - byteData = encodeWriteRequestDoubleField(fieldItem); - break; - // ----------------------------------------- - // Characters & Strings - // ----------------------------------------- - case STRING: - byteData = encodeWriteRequestStringField(fieldItem, false); - break; - case WSTRING: - byteData = encodeWriteRequestStringField(fieldItem, true); - break; - default: - throw new PlcProtocolException("Unsupported type " + s7Field.getDataType()); - } + parameterItems.add(varParameterItem); - VarPayloadItem varPayloadItem = new VarPayloadItem( + DataTransportSize dataTransportSize = s7Field.getDataType().getDataTransportSize(); + + // TODO: Checkout if the payload items are sort of a flatMap of all request items. + byte[] byteData = null; + switch(s7Field.getDataType()) { + // ----------------------------------------- + // Bit + // ----------------------------------------- + case BOOL: + //byteData = encodeWriteRequestBitField(fieldItem); + break; + // ----------------------------------------- + // Signed integer values + // ----------------------------------------- + case BYTE: + case SINT: + case CHAR: // 1 byte + byteData = encodeWriteRequestByteField(fieldItem, true); + break; + case WORD: + case INT: + case WCHAR: // 2 byte (16 bit) + byteData = encodeWriteRequestShortField(fieldItem, true); + break; + case DWORD: + case DINT: // 4 byte (32 bit) + byteData = encodeWriteRequestIntegerField(fieldItem, true); + break; + case LWORD: + case LINT: // 8 byte (64 bit) + byteData = encodeWriteRequestLongField(fieldItem, true); + break; + // ----------------------------------------- + // Unsigned integer values + // ----------------------------------------- + // 8 bit: + case USINT: + byteData = encodeWriteRequestByteField(fieldItem, false); + break; + // 16 bit: + case UINT: + byteData = encodeWriteRequestShortField(fieldItem, false); + break; + // 32 bit: + case UDINT: + byteData = encodeWriteRequestIntegerField(fieldItem, false); + break; + // 64 bit: + case ULINT: + byteData = encodeWriteRequestLongField(fieldItem, false); + break; + // ----------------------------------------- + // Floating point values + // ----------------------------------------- + case REAL: + byteData = encodeWriteRequestFloatField(fieldItem); + break; + case LREAL: + byteData = encodeWriteRequestDoubleField(fieldItem); + break; + // ----------------------------------------- + // Characters & Strings + // ----------------------------------------- + case STRING: + byteData = encodeWriteRequestStringField(fieldItem, false); + break; + case WSTRING: + byteData = encodeWriteRequestStringField(fieldItem, true); + break; + // ----------------------------------------- + // Date & Time + // ----------------------------------------- + case S5TIME: + byteData = encodeWriteRequestS5TimeField(fieldItem, false); + break; + case TIME: // 4 byte (32 bit) + byteData = encodeWriteRequestTimeField(fieldItem, false); + break; + case TOD: + case TIME_OF_DAY: + byteData = encodeWriteRequestTodField(fieldItem, true); + break; + case DATE: // 2 byte (16 bit) + byteData = encodeWriteRequestDateField(fieldItem, true); + break; + case DT: + case DATE_AND_TIME: // 8 byte (64 bit) + byteData = encodeWriteRequestDateTimeField(fieldItem, true); + break; + default: + throw new PlcProtocolException("Unsupported type.. " + s7Field.getDataType()); + } + + VarPayloadItem varPayloadItem = new VarPayloadItem( DataTransportErrorCode.RESERVED, dataTransportSize, byteData); - payloadItems.add(varPayloadItem); - } + payloadItems.add(varPayloadItem); + } + itemRow++; + }; + VarParameter writeVarParameter = new VarParameter(ParameterType.WRITE_VAR, parameterItems); VarPayload writeVarPayload = new VarPayload(ParameterType.WRITE_VAR, payloadItems); // Assemble the request. S7RequestMessage s7WriteRequest = new S7RequestMessage(MessageType.JOB, - (short) tpduGenerator.getAndIncrement(), Collections.singletonList(writeVarParameter), + tpdu, Collections.singletonList(writeVarParameter), Collections.singletonList(writeVarPayload), msg); requests.put(s7WriteRequest.getTpduReference(), msg); out.add(s7WriteRequest); } + + + void encodeWriteRequestBitFieldAndArray(Short tpdu, + Short itemRow, + BaseDefaultFieldItem fieldItem, + S7Field s7Field, + List parameterItems, + List payloadItems){ + + int curParameterByteOffset = s7Field.getByteOffset(); + byte curParameterBitOffset = (byte) s7Field.getBitOffset(); + byte curPayloadBitOffset = 0; + + //Only BITS arrays + if (s7Field.getNumElements() > 1) { + requestBitArray.computeIfAbsent(tpdu, + k->new HashMap()).put(itemRow,s7Field.getNumElements()-1); + } + + for (int i = 0; i < s7Field.getNumElements(); i++) { + + VarParameterItem varParameterItem = new S7AnyVarParameterItem( + SpecificationType.VARIABLE_SPECIFICATION, s7Field.getMemoryArea(), + s7Field.getDataType(), + (short) 1, + s7Field.getBlockNumber(), + curParameterByteOffset, + curParameterBitOffset); + + // Create a one-byte byte array and set it to 0x01, if the corresponding bit + // was 1 else set it to 0x00. + byte[] elementData = new byte[1]; + + parameterItems.add(varParameterItem); + + if (!(payloadItems == Collections.EMPTY_LIST)){ + elementData[0] = (byte) (fieldItem.getBoolean(i)?0x01:0x00); + VarPayloadItem itemPayload = new VarPayloadItem( + DataTransportErrorCode.RESERVED, + s7Field.getDataType().getDataTransportSize(), + elementData); + payloadItems.add(itemPayload); + } + + // Calculate the new memory and bit offset. + curParameterBitOffset++; + if ((i > 0) && ((curParameterBitOffset % 8) == 0)) { + curParameterByteOffset++; + curParameterBitOffset = 0; + } + curPayloadBitOffset++; + if ((i > 0) && ((curPayloadBitOffset % 8) == 0)) { + curPayloadBitOffset = 0; + } + } + } + byte[] encodeWriteRequestBitField(BaseDefaultFieldItem fieldItem) { int numBytes = fieldItem.getNumberOfValues() >> 3 / 8; @@ -816,12 +951,62 @@ byte[] encodeWriteRequestDoubleField(BaseDefaultFieldItem fieldItem) { } return buffer.array(); } - + byte[] encodeWriteRequestStringField(BaseDefaultFieldItem fieldItem, boolean isUtf16) { // TODO: Implement this ... - return new byte[0]; + String str = fieldItem.getString(0); + ByteBuffer buffer = ByteBuffer.allocate(str.length()+2); + buffer.put((byte)254); + buffer.put((byte)str.length()); + buffer.put(str.getBytes()); + return buffer.array(); } + byte[] encodeWriteRequestS5TimeField(BaseDefaultFieldItem fieldItem, boolean signed) { + int numBytes = fieldItem.getNumberOfValues() * 2; + ByteBuffer buffer = ByteBuffer.allocate(numBytes); + for (int i = 0; i < fieldItem.getNumberOfValues(); i++) { + buffer.putShort(S7Helper.DurationToS5Time(fieldItem.getDuration(i))); + } + return buffer.array(); + } + + byte[] encodeWriteRequestTimeField(BaseDefaultFieldItem fieldItem, boolean signed) { + int numBytes = fieldItem.getNumberOfValues() * 4; + ByteBuffer buffer = ByteBuffer.allocate(numBytes); + for (int i = 0; i < fieldItem.getNumberOfValues(); i++) { + buffer.putInt(S7Helper.DurationToS7Time(fieldItem.getDuration(i))); + } + return buffer.array(); + } + + byte[] encodeWriteRequestTodField(BaseDefaultFieldItem fieldItem, boolean signed) { + int numBytes = fieldItem.getNumberOfValues() * 4; + ByteBuffer buffer = ByteBuffer.allocate(numBytes); + for (int i = 0; i < fieldItem.getNumberOfValues(); i++) { + buffer.putInt(S7Helper.LocalTimeToS7Tod(fieldItem.getTime(i))); + } + return buffer.array(); + } + + byte[] encodeWriteRequestDateField(BaseDefaultFieldItem fieldItem, boolean signed) { + int numBytes = fieldItem.getNumberOfValues() * 2; + ByteBuffer buffer = ByteBuffer.allocate(numBytes); + for (int i = 0; i < fieldItem.getNumberOfValues(); i++) { + buffer.putShort(S7Helper.LocalDateToS7Date(fieldItem.getDate(i))); + } + return buffer.array(); + } + + byte[] encodeWriteRequestDateTimeField(BaseDefaultFieldItem fieldItem, boolean signed) { + int numBytes = fieldItem.getNumberOfValues() * 8; + ByteBuffer buffer = ByteBuffer.allocate(numBytes); + for (int i = 0; i < fieldItem.getNumberOfValues(); i++) { + buffer.put(S7Helper.LocalDateTimeToS7DateTime(fieldItem.getDateTime(i))); + } + return buffer.array(); + } + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Decoding //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -838,6 +1023,7 @@ protected void decode(ChannelHandlerContext ctx, S7Message msg, List out S7ResponseMessage responseMessage = (S7ResponseMessage) msg; short tpduReference = responseMessage.getTpduReference(); + if (requests.containsKey(tpduReference)) { // As every response has a matching request, get this request based on the tpdu. PlcRequestContainer requestContainer = requests.remove(tpduReference); @@ -955,7 +1141,8 @@ public void operationComplete(ChannelFuture future) { @SuppressWarnings("unchecked") private PlcResponse decodeReadResponse(S7ResponseMessage responseMessage, PlcRequestContainer requestContainer) throws PlcProtocolException { InternalPlcReadRequest plcReadRequest = (InternalPlcReadRequest) requestContainer.getRequest(); - + Map splitItems = null; + if (responseMessage.getPayloads().get(0) instanceof CpuServicesPayload){ return decodeSslReadResponse(responseMessage, requestContainer); } @@ -968,45 +1155,80 @@ private PlcResponse decodeReadResponse(S7ResponseMessage responseMessage, PlcReq // If the numbers of items don't match, we're in big trouble as the only // way to know how to interpret the responses is by aligning them with the // items from the request as this information is not returned by the PLC. - if (plcReadRequest.getNumberOfFields() != payload.getItems().size()) { + + short tpdu = responseMessage.getTpduReference(); + + int[] fieldOffset= new int[1]; + fieldOffset[0] = 0; + if (requestBitArray.containsKey(tpdu)){ + splitItems = requestBitArray.remove(tpdu); + splitItems.forEach((key,length) -> { + fieldOffset[0] += length; + }); + } + + if ((plcReadRequest.getNumberOfFields()+fieldOffset[0]) != payload.getItems().size()) { logger.info("Excepcion: " + plcReadRequest.getFieldNames().toString()); throw new PlcProtocolException( - "The number of requested items doesn't match the number of returned items"); + "The number of requested items doesn't match the number of returned items Request: " + + (plcReadRequest.getNumberOfFields()+fieldOffset[0]) + + " Payload: " + + payload.getItems().size()); } + + Map> values = new HashMap<>(); List payloadItems = payload.getItems(); - int index = 0; + short index = 0; + short itemRow = 0; for (String fieldName : plcReadRequest.getFieldNames()) { S7Field field = (S7Field) plcReadRequest.getField(fieldName); - VarPayloadItem payloadItem = payloadItems.get(index); + VarPayloadItem payloadItem = payloadItems.get(itemRow); PlcResponseCode responseCode = decodeResponseCode(payloadItem.getReturnCode()); BaseDefaultFieldItem fieldItem = null; - ByteBuf data = Unpooled.wrappedBuffer(payloadItem.getData()); + + //ByteBuf data = Unpooled.copiedBuffer(payloadItem.getData()); + ByteBuf data = PooledByteBufAllocator.DEFAULT.buffer(); + if (payloadItem.getData() != null){ + data.writeBytes(payloadItem.getData()); + } + if (responseCode == PlcResponseCode.OK) { try { switch (field.getDataType()) { // ----------------------------------------- // Bit + // 1 responseMessage // ----------------------------------------- case BOOL: - fieldItem = decodeReadResponseBitField(field, data); + if (splitItems != null){ + if (splitItems.containsKey(index)){ + short endRow = (short)(itemRow + splitItems.get(index)); + for(short i=itemRow; i<=endRow; i++){ + payloadItem = payloadItems.get(i); + data.writeBytes(payloadItem.getData()); + } + itemRow = endRow; + } + } + fieldItem = decodeReadResponseBitField(field, data); break; // ----------------------------------------- // Bit-strings // ----------------------------------------- case BYTE: // 1 byte - fieldItem = decodeReadResponseByteBitStringField(field, data); + fieldItem = decodeReadResponseSignedByteField(field, data); break; case WORD: // 2 byte (16 bit) - fieldItem = decodeReadResponseShortBitStringField(field, data); + fieldItem = decodeReadResponseSignedShortField(field, data); break; case DWORD: // 4 byte (32 bit) - fieldItem = decodeReadResponseIntegerBitStringField(field, data); + fieldItem = decodeReadResponseSignedIntegerField(field, data); break; case LWORD: // 8 byte (64 bit) - fieldItem = decodeReadResponseLongBitStringField(field, data); + fieldItem = decodeReadResponseSignedLongField(field, data); break; // ----------------------------------------- // Integers @@ -1025,7 +1247,13 @@ private PlcResponse decodeReadResponse(S7ResponseMessage responseMessage, PlcReq case UINT: fieldItem = decodeReadResponseUnsignedShortField(field, data); break; + case S5TIME: + fieldItem = decodeReadResponseS5Time(field, data); + break; // 32 bit: + case TIME: + fieldItem = decodeReadResponseTime(field, data); + break; case DINT: fieldItem = decodeReadResponseSignedIntegerField(field, data); break; @@ -1066,11 +1294,13 @@ private PlcResponse decodeReadResponse(S7ResponseMessage responseMessage, PlcReq // ----------------------------------------- // TIA Date-Formats // ----------------------------------------- + case DT: case DATE_AND_TIME: fieldItem = decodeReadResponseDateAndTime(field, data); break; + case TOD: case TIME_OF_DAY: - fieldItem = decodeReadResponseTimeOfDay(field, data); + fieldItem = decodeReadResponseTimeOfDay(field, data); break; case DATE: fieldItem = decodeReadResponseDate(field, data); @@ -1089,6 +1319,7 @@ private PlcResponse decodeReadResponse(S7ResponseMessage responseMessage, PlcReq Pair result = new ImmutablePair<>(responseCode, fieldItem); values.put(fieldName, result); index++; + itemRow++; } return new DefaultPlcReadResponse(plcReadRequest, values); @@ -1234,20 +1465,30 @@ BaseDefaultFieldItem decodeReadResponseVarLengthStringField(boolean isUtf16, Byt return decodeReadResponseFixedLengthStringField(currentLength, isUtf16, data); } - BaseDefaultFieldItem decodeReadResponseDateAndTime(S7Field field,ByteBuf data) { - LocalDateTime[] localDateTimes = readAllValues(LocalDateTime.class,field, i -> readDateAndTime(data)); - return new DefaultLocalDateTimeFieldItem(localDateTimes); + BaseDefaultFieldItem decodeReadResponseS5Time(S7Field field,ByteBuf data) { + Duration[] durations = readAllValues(Duration.class,field, i -> readS5TimeToDuration(data)); + return new DefaultDurationFieldItem(durations); } - + + BaseDefaultFieldItem decodeReadResponseTime(S7Field field,ByteBuf data) { + Duration[] durations = readAllValues(Duration.class,field, i -> readS7TimeToDuration(data)); + return new DefaultDurationFieldItem(durations); + } + BaseDefaultFieldItem decodeReadResponseTimeOfDay(S7Field field,ByteBuf data) { LocalTime[] localTimes = readAllValues(LocalTime.class,field, i -> readTimeOfDay(data)); return new DefaultLocalTimeFieldItem(localTimes); } BaseDefaultFieldItem decodeReadResponseDate(S7Field field,ByteBuf data) { - LocalDate[] localTimes = readAllValues(LocalDate.class,field, i -> readDate(data)); - return new DefaultLocalDateFieldItem(localTimes); + LocalDate[] localDates = readAllValues(LocalDate.class,field, i -> readDate(data)); + return new DefaultLocalDateFieldItem(localDates); } + + BaseDefaultFieldItem decodeReadResponseDateAndTime(S7Field field,ByteBuf data) { + LocalDateTime[] localDateTimes = readAllValues(LocalDateTime.class,field, i -> readDateAndTime(data)); + return new DefaultLocalDateTimeFieldItem(localDateTimes); + } // Returns a 32 bit unsigned value : from 0 to 4294967295 (2^32-1) public static int getUDIntAt(byte[] buffer, int pos) { @@ -1276,31 +1517,81 @@ private static T[] readAllValues(Class clazz, S7Field field, Function splitItems = null; + + + //TODO: if the PLC Send a error, It send only the Header with PDUR and error code. + // in this condition we send a error to the client, no a exception. VarPayload payload = responseMessage.getPayload(VarPayload.class) .orElseThrow(() -> new PlcProtocolException("No VarPayload supplied")); // TODO: Checkout if the payload items are sort of a flatMap of all request items. + // TODO: Check for array response, no payload items presents, Why? // If the numbers of items don't match, we're in big trouble as the only // way to know how to interpret the responses is by aligning them with the // items from the request as this information is not returned by the PLC. - if (plcWriteRequest.getNumberOfFields() != payload.getItems().size()) { - throw new PlcProtocolException( - "The number of requested items doesn't match the number of returned items"); + // If we write BitsArray -> We need to add the number of items created + // for individual requests. + int[] numberOfFields = new int[1]; + numberOfFields[0] = 0; + short tpdu = responseMessage.getTpduReference(); + if (requestBitArray.containsKey(tpdu)) { + splitItems = requestBitArray.remove(tpdu); + splitItems.forEach((key,length)->{ + numberOfFields[0] += length; + }); + numberOfFields[0] += plcWriteRequest.getNumberOfFields(); + } else { + numberOfFields[0] = plcWriteRequest.getNumberOfFields(); } + if (numberOfFields[0] != payload.getItems().size()) { + throw new PlcProtocolException( + "The number of requested items doesn't match the number of returned items Request: " + + numberOfFields[0] + + " " + + payload.getItems().size()); + } + Map values = new HashMap<>(); List payloadItems = payload.getItems(); - int index = 0; - for (String fieldName : plcWriteRequest.getFieldNames()) { - VarPayloadItem payloadItem = payloadItems.get(index); - // A write response contains only the return code for every item. - PlcResponseCode responseCode = decodeResponseCode(payloadItem.getReturnCode()); + short sFieldCount = 0; + short sPayloadCount = 0; + + for (String fieldName : plcWriteRequest.getFieldNames()) { + + VarPayloadItem payloadItem = payloadItems.get(sPayloadCount); + PlcResponseCode responseCode = decodeResponseCode(payloadItem.getReturnCode()); + + if (splitItems != null) { + + if (splitItems.containsKey(sFieldCount)) { + + int numberOfItems = splitItems.get(sFieldCount); + responseCode = decodeResponseCode(payloadItem.getReturnCode()); + for (short i=sPayloadCount; i<=(short)(sPayloadCount+numberOfItems); i++){ + if (payloadItem.getReturnCode() != DataTransportErrorCode.OK) { + responseCode = decodeResponseCode(payloadItem.getReturnCode()); + }; + payloadItem = payloadItems.get(i); + } + sPayloadCount += (short) numberOfItems+1; + } else { + responseCode = decodeResponseCode(payloadItem.getReturnCode()); + sPayloadCount++; + } + + } else { + sPayloadCount++; + } values.put(fieldName, responseCode); - index++; + + sFieldCount++; } + return new DefaultPlcWriteResponse(plcWriteRequest, values); } @@ -1447,6 +1738,8 @@ private PlcResponseCode decodeResponseCode(DataTransportErrorCode dataTransportE return PlcResponseCode.INVALID_ADDRESS; case DATA_TYPE_NOT_SUPPORTED: return PlcResponseCode.INVALID_DATATYPE; + case ACCESS_DENIED: + return PlcResponseCode.ACCESS_DENIED; default: return PlcResponseCode.INTERNAL_ERROR; } @@ -1481,48 +1774,25 @@ private static BigInteger readUnsigned64BitInteger(ByteBuf data) { return new BigInteger(bytes); } + //TODO: millisoconds LocalDateTime readDateAndTime(ByteBuf data) { - //per definition for Date_And_Time only the first 6 bytes are used - - int year=convertByteToBcd(data.readByte()); - int month=convertByteToBcd(data.readByte()); - int day=convertByteToBcd(data.readByte()); - int hour=convertByteToBcd(data.readByte()); - int minute=convertByteToBcd(data.readByte()); - int second=convertByteToBcd(data.readByte()); - //skip the last 2 bytes no information present - data.readByte(); - data.readByte(); - - //data-type ranges from 1990 up to 2089 - if(year>=90){ - year+=1900; - } - else{ - year+=2000; - } - - return LocalDateTime.of(year,month,day,hour,minute,second); + return S7Helper.S7DateTimeToLocalDateTime(data); } + Duration readS5TimeToDuration(ByteBuf data){ + return S7Helper.S5TimeToDuration(data.readShort()); + }; + + Duration readS7TimeToDuration(ByteBuf data){ + return S7Helper.S7TimeToDuration(data.readInt()); + }; + LocalTime readTimeOfDay(ByteBuf data) { - //per definition for Date_And_Time only the first 6 bytes are used - - int millisSinsMidnight = data.readInt(); - - - return LocalTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0).plus(millisSinsMidnight, ChronoUnit.MILLIS); - + return S7Helper.S7TodToLocalTime(data.readInt()); } LocalDate readDate(ByteBuf data) { - //per definition for Date_And_Time only the first 6 bytes are used - - int daysSince1990 = data.readUnsignedShort(); - - System.out.println(daysSince1990); - return LocalDate.now().withYear(1990).withDayOfMonth(1).withMonth(1).plus(daysSince1990, ChronoUnit.DAYS); - + return S7Helper.S7DateToLocalDate(data.readShort()); } /** 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 ad3591c5bc4..78f1c446d89 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 @@ -23,6 +23,7 @@ Licensed to the Apache Software Foundation (ASF) under one import io.netty.buffer.Unpooled; import io.netty.channel.*; import io.netty.handler.codec.MessageToMessageDecoder; +import io.netty.util.AttributeKey; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.PromiseCombiner; import java.lang.reflect.Field; @@ -103,6 +104,7 @@ protected void decode(ChannelHandlerContext ctx, Object msg, List out) { private short maxAmqCaller; private short maxAmqCallee; private short pduSize; + private final AttributeKey pduSizeKey = AttributeKey.valueOf("pduSizeKey"); private S7ControllerType controllerType; // For detecting the lower layers. @@ -113,6 +115,11 @@ protected void decode(ChannelHandlerContext ctx, Object msg, List out) { private PendingWriteQueue queue; private Map sentButUnacknowledgedTpdus; + /* + * All fragmentsof data send by PLC are stored here, + * until the PLC indicates that it is the last one, + * then a single message is assembled. + */ private Map>> fragmentedData; public S7Protocol(short requestedMaxAmqCaller, short requestedMaxAmqCallee, short requestedPduSize, @@ -129,6 +136,8 @@ public S7Protocol(short requestedMaxAmqCaller, short requestedMaxAmqCallee, shor @Override public void channelRegistered(ChannelHandlerContext ctx) { this.queue = new PendingWriteQueue(ctx); + ctx.channel().attr(pduSizeKey).set(pduSize); + try { Field prevField = FieldUtils.getField(ctx.getClass(), "prev", true); if(prevField != null) { @@ -188,6 +197,7 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) S7Message in = (S7Message) msg; // Give message processors to process the incoming message. + //TODO: messageProcessor move to netty next layer, no a plugin code Collection messages; if ((messageProcessor != null) && (in instanceof S7RequestMessage)) { messages = messageProcessor.processRequest((S7RequestMessage) in, pduSize); @@ -226,7 +236,7 @@ private void writeS7Message(Channel channel, PromiseCombiner promiseCombiner, // Check if the message doesn't exceed the negotiated maximum size. if (buf.writerIndex() > pduSize) { - throw new PlcProtocolPayloadTooBigException("s7", pduSize, buf.writerIndex(), message); + throw new PlcProtocolPayloadTooBigException("s7:"+message.getTpduReference(), pduSize, buf.writerIndex(), message); } else { ChannelPromise subPromise = new DefaultChannelPromise(channel); // The tpduRef was 0x01 but had to be changed to 0x00 in order to support Siemens LOGO devices. @@ -244,7 +254,7 @@ private void encodePayloads(S7Message in, ByteBuf buf) throws PlcProtocolExcepti S7Payload payload = payloadIterator.next(); switch (payload.getType()) { case WRITE_VAR: - encodeWriteVarPayload((VarPayload) payload, buf, !payloadIterator.hasNext()); + encodeWriteVarPayload((VarPayload) payload, buf, payloadIterator.hasNext()); break; case CPU_SERVICES: if (payload instanceof CpuServicesPayload) { @@ -269,7 +279,10 @@ private void encodePayloads(S7Message in, ByteBuf buf) throws PlcProtocolExcepti * */ private void encodeWriteVarPayload(VarPayload varPayload, ByteBuf buf, boolean lastItem) { - for (VarPayloadItem payloadItem : varPayload.getItems()) { + + //All payloads for the request come here + int i=1; + for (VarPayloadItem payloadItem : varPayload.getItems()) { buf.writeByte(payloadItem.getReturnCode().getCode()); buf.writeByte(payloadItem.getDataTransportSize().getCode()); //TODO: Check if this is correct?!?! Might be problems with sizeInBits = true/false @@ -293,14 +306,16 @@ private void encodeWriteVarPayload(VarPayload varPayload, ByteBuf buf, boolean l buf.writeShort(payloadItem.getData().length); break; } - buf.writeBytes(payloadItem.getData()); + buf.writeBytes(payloadItem.getData()); + // if this is not the last item and it's payload is exactly one byte, we need to output a fill-byte. - if((payloadItem.getData().length == 1) && !lastItem) { - buf.writeByte(0x00); - } - - System.out.println("encodeWriteVarPayload ByteBuf:... \r\n" + ByteBufUtil.prettyHexDump(buf)); + //if((payloadItem.getData().length == 1) && (!lastItem)) { + + if((payloadItem.getData().length == 1) && (varPayload.getItems().size() > i) || (payloadItem.getData().length % 2 != 0)) { + buf.writeByte(0x00); + } + i++; } } @@ -581,7 +596,9 @@ private void encodeS7AnyParameterItem(ByteBuf buf, S7AnyVarParameterItem s7AnyRe // Length of this item (excluding spec type and length) buf.writeByte((byte) 0x0a); buf.writeByte(s7AnyRequestItem.getAddressingMode().getCode()); - buf.writeByte(s7AnyRequestItem.getDataType().getTypeCode()); + //buf.writeByte(s7AnyRequestItem.getDataType().getTypeCode()); + + buf.writeByte(s7AnyRequestItem.getDataType().getBaseType().getTypeCode()); buf.writeShort(encodeNumElements(s7AnyRequestItem)); buf.writeShort(s7AnyRequestItem.getDataBlockNumber()); @@ -603,7 +620,8 @@ private void encodeS7AnyPayloadItem(S7AnyVarPayloadItem s7AnyRequestItem, ByteBu // Length of this item (excluding spec type and length) buf.writeByte((byte) 0x0a); buf.writeByte(s7AnyRequestItem.getAddressingMode().getCode()); - buf.writeByte(s7AnyRequestItem.getDataType().getTypeCode()); + //buf.writeByte(s7AnyRequestItem.getDataType().getTypeCode()); + buf.writeByte(s7AnyRequestItem.getDataType().getBaseType().getTypeCode()); buf.writeShort(encodeNumElements(s7AnyRequestItem)); buf.writeShort(s7AnyRequestItem.getDataBlockNumber()); @@ -626,7 +644,9 @@ private void encodeS7AnyPayloadItem(S7AnyVarPayloadItem s7AnyRequestItem, ByteBu //TODO: Refactor S7AnyVarParameterItem to S7AnyVarItem private short encodeNumElements(S7AnyVarParameterItem s7AnyVarParameterItem){ switch (s7AnyVarParameterItem.getDataType()){ + case DT: case DATE_AND_TIME: + case TOD: case TIME_OF_DAY: case DATE: return (short) (s7AnyVarParameterItem.getNumElements()*s7AnyVarParameterItem.getDataType().getSizeInBytes()); @@ -644,13 +664,17 @@ private short encodeNumElements(S7AnyVarParameterItem s7AnyVarParameterItem){ private short encodeNumElements(S7AnyVarPayloadItem s7AnyVarParameterItem){ switch (s7AnyVarParameterItem.getDataType()){ case DATE_AND_TIME: + case TOD: case TIME_OF_DAY: case DATE: - return (short) (s7AnyVarParameterItem.getNumElements()*s7AnyVarParameterItem.getDataType().getSizeInBytes()); + case DT: + return (short) (s7AnyVarParameterItem.getNumElements()*s7AnyVarParameterItem.getDataType().getSizeInBytes()); + case STRING: + break; default: return (short) s7AnyVarParameterItem.getNumElements(); } - + return 0; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -671,7 +695,7 @@ protected void decode(ChannelHandlerContext ctx, IsoTPMessage in, List o if (userData.readableBytes() == 0) { return; } - + if (userData.readByte() != S7_PROTOCOL_MAGIC_NUMBER) { logger.warn("Expecting S7 protocol magic number."); if (logger.isDebugEnabled()) { @@ -679,11 +703,14 @@ protected void decode(ChannelHandlerContext ctx, IsoTPMessage in, List o } return; } - + MessageType messageType = MessageType.valueOf(userData.readByte()); //Some response maybe USER_DATA //Header: Userdata. Parameter:(Response)->(CPU functions)->(ALARM ack) - boolean isResponse = messageType == MessageType.ACK_DATA; + + //The driver freezes if it does not recognize + //the MessageType.ACK type in response + boolean isResponse = (messageType == MessageType.ACK_DATA) || (messageType == MessageType.ACK); userData.readShort(); // Reserved (is always constant 0x0000) short tpduReference = userData.readShort(); short headerParametersLength = userData.readShort(); @@ -691,7 +718,8 @@ protected void decode(ChannelHandlerContext ctx, IsoTPMessage in, List o byte errorClass = 0; byte errorCode = 0; - if (isResponse) { + //If the PLC response qith error then messagetype == MessageType.ACK + if (isResponse) { errorClass = userData.readByte(); errorCode = userData.readByte(); } @@ -807,6 +835,8 @@ private void handleSetupCommunications(ChannelHandlerContext ctx, SetupCommunica maxAmqCaller = setupCommunicationParameter.getMaxAmqCaller(); maxAmqCallee = setupCommunicationParameter.getMaxAmqCallee(); pduSize = setupCommunicationParameter.getPduLength(); + + ctx.channel().attr(pduSizeKey).set(pduSize); if(logger.isInfoEnabled()) { logger.info("S7Connection established pdu-size {}, max-amq-caller {}, " + @@ -900,6 +930,7 @@ private VarPayload decodeVarPayload(ByteBuf userData, boolean isResponse, short int i = 0; while (i < userDataLength) { DataTransportErrorCode dataTransportErrorCode = DataTransportErrorCode.valueOf(userData.readByte()); + // This is a response to a WRITE_VAR request (It only contains the return code for every sent item. if ((readWriteVarParameter.getType() == ParameterType.WRITE_VAR) && isResponse) { // Initialize a rudimentary payload (This is updated in the Plc4XS7Protocol class @@ -1702,7 +1733,7 @@ private CpuCyclicServicesResponsePayload decodeCyclicServiceResponsePayload(CpuC private synchronized void trySendingMessages(ChannelHandlerContext ctx) { //logger.info("trySendingMessages {} < {}",sentButUnacknowledgedTpdus.size(),maxAmqCaller); - while(sentButUnacknowledgedTpdus.size() <= maxAmqCaller) { + while(sentButUnacknowledgedTpdus.size() < maxAmqCaller) { // Get the TPDU that is up next in the queue. DataTpdu curTpdu = (DataTpdu) queue.current(); diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/events/S7Alarm.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/events/S7Alarm.java index 3f429779c98..a368ffc9405 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/events/S7Alarm.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/events/S7Alarm.java @@ -23,6 +23,7 @@ Licensed to the Apache Software Foundation (ASF) under one import static io.netty.buffer.Unpooled.buffer; import java.math.BigDecimal; import java.math.BigInteger; +import java.time.Duration; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; @@ -485,6 +486,34 @@ public PlcResponseCode getResponseCode(String name) { public ByteBuf getData(String name) { return s7alarm.getComingValues().get(0).getData(); } + + @Override + public boolean isValidDuration(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidDuration(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Duration getDuration(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Duration getDuration(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllDuration(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + + public ByteBuf getAllData() { ByteBuf copy = buffer(12); diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/messages/S7RequestMessage.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/messages/S7RequestMessage.java index 1fcd0efd712..a06bebd4541 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/messages/S7RequestMessage.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/messages/S7RequestMessage.java @@ -18,12 +18,13 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.s7.netty.model.messages; +import java.util.List; import org.apache.plc4x.java.base.messages.PlcProtocolMessage; import org.apache.plc4x.java.s7.netty.model.params.S7Parameter; import org.apache.plc4x.java.s7.netty.model.payloads.S7Payload; import org.apache.plc4x.java.s7.netty.model.types.MessageType; - -import java.util.List; +import org.apache.plc4x.java.s7.netty.util.S7ResponseSizeEstimator; +import org.apache.plc4x.java.s7.netty.util.S7SizeHelper; /** * Container Object for Requests to S7 which additionally stores information if the request was acknowledged (by the PLC?). @@ -33,11 +34,14 @@ Licensed to the Apache Software Foundation (ASF) under one public class S7RequestMessage extends S7Message { private boolean acknowledged; + private int requestSize; public S7RequestMessage(MessageType messageType, short tpduReference, List s7Parameters, List s7Payloads, PlcProtocolMessage parent) { super(messageType, tpduReference, s7Parameters, s7Payloads, parent); acknowledged = false; + + this.requestSize = CalcSize(); } public boolean isAcknowledged() { @@ -47,5 +51,30 @@ public boolean isAcknowledged() { public void setAcknowledged(boolean acknowledged) { this.acknowledged = acknowledged; } + + public int getRequestSize() { + return this.requestSize; + } + + private int CalcSize(){ + int size = 0; + S7Parameter parameter = this.getParameters().get(0); + switch (parameter.getType()) { + case READ_VAR: + size = S7ResponseSizeEstimator.getEstimatedResponseMessageSize(this); + break; + case WRITE_VAR: + size = 10 + + S7SizeHelper.getParametersLength(this.getParameters()) + + S7SizeHelper.getPayloadsLength(this.getPayloads()); + break; + case SETUP_COMMUNICATION: + return 8; + default: + ; + } + return size; + } + } diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/TransportSize.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/TransportSize.java index 93e96462069..9e4b11144f4 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/TransportSize.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/TransportSize.java @@ -36,7 +36,7 @@ public enum TransportSize { // ----------------------------------------- BYTE(0x02, "B", 1, null, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.ANY), WORD(0x04, "W", 2, null, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.ANY), - DWORD(0x06, "D", 4, WORD, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.ANY), + DWORD(0x06, "D", 4, null, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.ANY), // Only got a basic TIA license (S7-1500 needed to find this out) // TODO: Find the code LWORD(0x00, "X", 8, null, null, S7ControllerType.S7_1200, S7ControllerType.S7_1500), @@ -53,7 +53,7 @@ public enum TransportSize { // Unsigned Small Int USINT(0x02, "B", 1, INT, DataTransportSize.INTEGER, S7ControllerType.S7_1200, S7ControllerType.S7_1500), // Double Precision Int - DINT(0x07, "D", 4, INT, DataTransportSize.INTEGER, S7ControllerType.ANY), + DINT(0x07, "D", 4, null, DataTransportSize.INTEGER, S7ControllerType.ANY), // Unsigned Double Precision Int UDINT(0x07, "D", 4, INT, DataTransportSize.INTEGER, S7ControllerType.S7_1200, S7ControllerType.S7_1500), // Only got a basic TIA license (S7-1500 needed to find this out) @@ -74,7 +74,7 @@ public enum TransportSize { // Durations // ----------------------------------------- // IEC time - TIME(0x0B, "D", 4, null, DataTransportSize.INTEGER, S7ControllerType.ANY), + TIME(0x0B, "D", 1, DWORD, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.ANY), // TODO: Find the code LTIME(0x00, "X", 8, TIME, null, S7ControllerType.S7_1500), @@ -82,18 +82,26 @@ public enum TransportSize { // Date // ----------------------------------------- // IEC date (yyyy-m-d) - DATE(0x02, "W", 2, null, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.ANY), + DATE(0x02, "W", 1, WORD, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.ANY), // ----------------------------------------- // Time of day // ----------------------------------------- // Time (hh:mm:ss.S) - TIME_OF_DAY(0x02, "D", 4, null, DataTransportSize.INTEGER, S7ControllerType.ANY), + TOD(0x02, "D", 4, BYTE, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.ANY), + TIME_OF_DAY(0x02, "D", 4, BYTE, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.ANY), + + // ----------------------------------------- + // Simatic S5 time + // Base time 10,100,1000,10000 mseg. + // ----------------------------------------- + S5TIME(0x0C, "W", 1, WORD, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.ANY), // ----------------------------------------- // Date and time of day // ----------------------------------------- - DATE_AND_TIME(0x02, "X", 8, null, DataTransportSize.INTEGER, S7ControllerType.S7_1500, S7ControllerType.S7_300, S7ControllerType.S7_400), + DT(0x02, "X", 8, BYTE, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.S7_1500, S7ControllerType.S7_300, S7ControllerType.S7_400), + DATE_AND_TIME(0x02, "X", 8, BYTE, DataTransportSize.BYTE_WORD_DWORD, S7ControllerType.S7_1500, S7ControllerType.S7_300, S7ControllerType.S7_400), // ----------------------------------------- // ASCII Strings @@ -160,7 +168,7 @@ public boolean isBaseType() { return baseType == null; } - TransportSize getBaseType() { + public TransportSize getBaseType() { // If this is a base-type itself, the baseType is null, in all // other cases it is set. if (baseType == null) { @@ -170,7 +178,7 @@ TransportSize getBaseType() { } } - TransportSize getSubType(String sizeCode) { + public TransportSize getSubType(String sizeCode) { // Try to find a sub-type with this base type for which the size code matches. for (TransportSize value : values()) { if ((value.baseType == this) && (value.sizeCode != null) && (value.sizeCode.equals(sizeCode))) { diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/strategies/DefaultS7MessageProcessor.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/strategies/DefaultS7MessageProcessor.java index 4e83e14f5cc..5e1e77e36df 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/strategies/DefaultS7MessageProcessor.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/strategies/DefaultS7MessageProcessor.java @@ -18,6 +18,8 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.s7.netty.strategies; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.lang3.NotImplementedException; import org.apache.plc4x.java.api.exceptions.PlcException; import org.apache.plc4x.java.api.exceptions.PlcProtocolException; @@ -39,9 +41,6 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.netty.util.S7RequestSizeCalculator; import org.apache.plc4x.java.s7.netty.util.S7ResponseSizeEstimator; -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; - /** * While a SetupCommunication message is no problem, when reading or writing data, * situations could arise that have to be handled. The following situations have to @@ -286,21 +285,51 @@ private void processBooleanWriteVarParameter(S7RequestMessage request, VarParame } } + //TODO: STRING: S7 native string (kmVENEZUELA) where k=254 & m=9 + //TODO: %MB200:BYTE[250] -> %MB200..%MB299, %MB300..%MB399, %MB400..%MB449, private void processNonBooleanWriteVarParameter(S7RequestMessage request, VarParameter varParameter, VarPayload varPayload, S7AnyVarParameterItem s7AnyVarParameterItem, VarPayloadItem varPayloadItem, int byteOffset, S7CompositeRequestMessage compositeRequestMessage) { int curByteOffset = byteOffset; int payloadPosition = 0; - for (int i = 0; i < s7AnyVarParameterItem.getNumElements(); i++) { - int elementSize = s7AnyVarParameterItem.getDataType().getSizeInBytes(); - + int numElements = 1; + + //Check for size + if (varPayloadItem.getData().length > 100){ + numElements = s7AnyVarParameterItem.getNumElements(); + }; + + for (int i = 0; i < numElements; i++) { + + int elementSize = 1; + elementSize = (s7AnyVarParameterItem.getDataType() == TransportSize.STRING)? + varPayloadItem.getData().length:s7AnyVarParameterItem.getDataType().getSizeInBytes(); + + short auxElements = 1; + /* + auxElements = (s7AnyVarParameterItem.getDataType() == TransportSize.STRING)? + (short) varPayloadItem.getData().length:(short) 0x01; + */ // Create a new message with only one single value item in the var parameter. + //TODO: For ARRAYs, check the size, for break the message + int divisor = (s7AnyVarParameterItem.getDataType().getBaseType()== null)? + s7AnyVarParameterItem.getDataType().getSizeInBytes(): + s7AnyVarParameterItem.getDataType().getSizeInBytes()* + s7AnyVarParameterItem.getDataType().getBaseType().getSizeInBytes(); + + auxElements = (short) (varPayloadItem.getData().length / divisor); + + if (auxElements != 1){ + elementSize = varPayloadItem.getData().length; + } + VarParameterItem itemParameter = new S7AnyVarParameterItem( s7AnyVarParameterItem.getSpecificationType(), s7AnyVarParameterItem.getMemoryArea(), - s7AnyVarParameterItem.getDataType(), (short) 1, + s7AnyVarParameterItem.getDataType(), auxElements, s7AnyVarParameterItem.getDataBlockNumber(), curByteOffset, (byte) 0); + S7Parameter subVarParameter = new VarParameter(varParameter.getType(), Collections.singletonList(itemParameter)); @@ -354,6 +383,7 @@ public S7ResponseMessage processResponse(S7RequestMessage request, S7ResponseMes } } + //TODO: bad S7ResponseMessage when write ARRAYS, the payload is not the ReturnCode private S7ResponseMessage getMergedResponseMessage(S7RequestMessage requestMessage, Collection responses) { MessageType messageType = null; diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/strategies/LongS7MessageProcessorCodec.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/strategies/LongS7MessageProcessorCodec.java new file mode 100644 index 00000000000..c89beb459dc --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/strategies/LongS7MessageProcessorCodec.java @@ -0,0 +1,655 @@ +/* +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.netty.strategies; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageCodec; +import io.netty.util.AttributeKey; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import org.apache.plc4x.java.base.messages.PlcProtocolMessage; +import org.apache.plc4x.java.s7.netty.model.messages.S7RequestMessage; +import org.apache.plc4x.java.s7.netty.model.messages.S7ResponseMessage; +import org.apache.plc4x.java.s7.netty.model.params.S7Parameter; +import org.apache.plc4x.java.s7.netty.model.params.VarParameter; +import org.apache.plc4x.java.s7.netty.model.params.items.S7AnyVarParameterItem; +import org.apache.plc4x.java.s7.netty.model.params.items.VarParameterItem; +import org.apache.plc4x.java.s7.netty.model.payloads.S7Payload; +import org.apache.plc4x.java.s7.netty.model.payloads.VarPayload; +import org.apache.plc4x.java.s7.netty.model.payloads.items.VarPayloadItem; +import org.apache.plc4x.java.s7.netty.model.types.DataTransportErrorCode; +import org.apache.plc4x.java.s7.netty.model.types.MessageType; +import org.apache.plc4x.java.s7.netty.model.types.ParameterType; +import org.apache.plc4x.java.s7.netty.model.types.TransportSize; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * @author cgarcia + */ +public class LongS7MessageProcessorCodec extends + MessageToMessageCodec{ + + private static final Logger LOGGER = LoggerFactory.getLogger(LongS7MessageProcessorCodec.class ); + private final AttributeKey pduSizeKey = AttributeKey.valueOf("pduSizeKey"); + private final AttributeKey tpduGeneratorKey = AttributeKey.valueOf("tpduGeneratorKey"); + + private final Map compRequestMessages; + + private Short pduSize = 0; + private AtomicInteger tpduGenerator; + + public LongS7MessageProcessorCodec() { + this.compRequestMessages = new LinkedHashMap<>(10); + } + + @Override + protected void encode(ChannelHandlerContext ctx, S7RequestMessage request, List out) throws Exception { + pduSize = ctx.channel().attr(pduSizeKey).get(); + tpduGenerator = ctx.channel().attr(tpduGeneratorKey).get(); + + Optional varParameterOptional = request.getParameter(VarParameter.class); + if (varParameterOptional.isPresent()) { + VarParameter varParameter = varParameterOptional.get(); + /* Requests whose size is larger than the psuSize should be + *processed or if it is smaller than this but contains a number + *of elements greater than 18 */ + if ((pduSize < 1024) && (tpduGenerator != null) && ( + (request.getRequestSize() > pduSize) || + ((request.getRequestSize() < pduSize) && (varParameter.getItems().size() > 18)))){ + if (varParameter.getType() == ParameterType.READ_VAR){ + LinkedHashMap splitRequest = SplitLongReadRequestMessageGroup(request); + out.addAll(splitRequest.values()); + return; + } else if(varParameter.getType() == ParameterType.WRITE_VAR){ + LinkedHashMap splitRequest = SplitLongWriteRequestMessageGroup(request); + out.addAll(splitRequest.values()); + return; + } + } + } + out.add(request); + } + + @Override + protected void decode(ChannelHandlerContext ctx, S7ResponseMessage response, List out) throws Exception { + S7CompositeRequestMessage compRequestMessage = compRequestMessages.get(response.getTpduReference()); + if (compRequestMessage != null) { + compRequestMessage.addResponseMessage(response); + if (compRequestMessage.isCompleted()){ + S7ResponseMessage res = AssemblyResponseMessage(compRequestMessage, response); + out.add(res); + return; + } + } + out.add(response); + } + + /************************************************************************ + * SPLIT SECTION + ************************************************************************/ + + /* + * This method split original S7RequestMessage using 80% rule. + * Another problem when tpduGenerator returns to zero (short type). + * TODO: split for individual item when item.size > pduSize + */ + private LinkedHashMap SplitLongWriteRequestMessageGroup(S7RequestMessage request){ + + boolean firtsRow = true; + S7CompositeRequestMessage compRequestMessage = new S7CompositeRequestMessage(request); + + compRequestMessages.put(request.getTpduReference(), compRequestMessage); + + List splitRequests = new LinkedList<>(); + + Optional varParameterOptional = request.getParameter(VarParameter.class); + VarParameter parameters = varParameterOptional.get(); + + Optional varPayloadOptional = request.getPayload(VarPayload.class); + VarPayload payloads = varPayloadOptional.get(); + + short itemSize = 0; + short actualSize = 0; + short maxItemSize = (short) Math.round(pduSize * 0.8); + + S7Parameter parameter = null; + S7Payload payload = null; + + List parameterItems = (LinkedList)parameters.getItems(); + List payloadItems = (LinkedList)payloads.getItems(); + List splitParameters = new LinkedList<>(); + List splitPayloads = new LinkedList<>(); + + S7AnyVarParameterItem s7AnyVarParameterItem = null; + + //No se estan generando en orden + Iterator itParameter = parameterItems.iterator(); + Iterator itPayload = payloadItems.iterator(); + int i = 0; + while (itParameter.hasNext()) { + + VarParameterItem varParameterItem = itParameter.next(); + VarPayloadItem varPayloadItem = itPayload.next(); + + if (varParameterItem instanceof S7AnyVarParameterItem) { + s7AnyVarParameterItem = (S7AnyVarParameterItem) varParameterItem; + } + + //TODO: for odd size count the fill 0x00 byte + itemSize = (short)(28 + varPayloadItem.getData().length); //Header+Parameter+data + actualSize = (short)(28 + 14*(splitPayloads.size()));//Header+Parameter + for(VarPayloadItem item:splitPayloads){ + actualSize = (short) (actualSize +item.getData().length); //+=data.length + }; + + LOGGER.debug("SplitLongWriteRequestMessageGroup itemSize: " + itemSize + " actualSize: " + actualSize); + + //TODO: Item size is > pduSize the Split is in the user layer. + if (itemSize > pduSize){ + //TODO: Evaluate that the fractional message should be blocked + // by the next layer. The response message indicating poor + // quality must also be generated at this point. + if (!splitParameters.isEmpty()){ + PrepareMessagesToNextLayer(request.getMessageType(), + parameters.getType(), + splitParameters, + splitPayloads, + compRequestMessage); + + splitParameters = new LinkedList<>(); + splitPayloads = new LinkedList<>(); + } + + short tpdu = PrepareMessagesToNextLayer(request.getMessageType(), + parameters.getType(), + Collections.singletonList(varParameterItem), + Collections.singletonList(varPayloadItem), + compRequestMessage); + + VarParameter writeVarParameter = new VarParameter(parameters.getType(), + Collections.singletonList(varParameterItem)); + VarPayload writeVarPayload = new VarPayload(parameters.getType(), + Collections.singletonList(varPayloadItem)); + //This message generates an "error" from the PLC, which is discarded. + S7RequestMessage splitRequest = new S7RequestMessage(request.getMessageType(), + tpdu, Collections.singletonList(writeVarParameter), + Collections.EMPTY_LIST, compRequestMessage); + + VarParameter ackVarParameter = new VarParameter(parameters.getType(), + Collections.singletonList( + new S7AnyVarParameterItem(null, null, null, 0x01, (short) 0, (short) 0, (byte) 0))); + VarPayload ackVarPayload = new VarPayload(parameters.getType(), + Collections.singletonList( new VarPayloadItem(DataTransportErrorCode.ACCESS_DENIED, null, null))); + + S7ResponseMessage responseMessage = new S7ResponseMessage( + MessageType.ACK_DATA, + splitRequest.getTpduReference(), + Collections.singletonList(ackVarParameter), + Collections.singletonList(ackVarPayload), + (byte) 0x81, //Application relationship + (byte) 0x04); //Service no implemented or frame error + /* + compRequestMessage.getResponseMessages().put( + responseMessage.getTpduReference(), + responseMessage); + */ + + compRequestMessage.getRequestMessages().put(splitRequest.getTpduReference(),splitRequest); + compRequestMessages.put(splitRequest.getTpduReference(), compRequestMessage); + //A fault response is generated, with poor quality, allowing + //to follow the writing process for the other Items. + + //throw new Plc4XNettyException("Write item request size bigger than " + pduSize+ + // " bytes. Split the Item in smaller units."); + + } else if ((itemSize > maxItemSize) && ((itemSize < pduSize))){ + //TODO: Add a S7RequestMessage to the list + PrepareMessagesToNextLayer(request.getMessageType(), + parameters.getType(), + splitParameters, + splitPayloads, + compRequestMessage); + + } else if (!firtsRow){ + + if ((((itemSize + actualSize) >= maxItemSize) && + ((itemSize + actualSize) <= pduSize)) || + (!itParameter.hasNext())){ + splitParameters.add(varParameterItem); + splitPayloads.add(varPayloadItem); + + PrepareMessagesToNextLayer(request.getMessageType(), + parameters.getType(), + splitParameters, + splitPayloads, + compRequestMessage); + + splitParameters = new LinkedList<>(); + splitPayloads = new LinkedList<>(); + } else if (((itemSize + actualSize) >= pduSize)){ + PrepareMessagesToNextLayer(request.getMessageType(), + parameters.getType(), + splitParameters, + splitPayloads, + compRequestMessage); + splitParameters = new LinkedList<>(); + splitPayloads = new LinkedList<>(); + splitParameters.add(varParameterItem); + splitPayloads.add(varPayloadItem); + } + else { + splitParameters.add(varParameterItem); + splitPayloads.add(varPayloadItem); + } + } else { + splitParameters.add(varParameterItem); + splitPayloads.add(varPayloadItem); + } + firtsRow = false; + } + + if (!splitParameters.isEmpty()){ + PrepareMessagesToNextLayer(request.getMessageType(), + parameters.getType(), + splitParameters, + splitPayloads, + compRequestMessage); + } + + return compRequestMessage.getRequestMessages(); + }; + + private LinkedHashMap SplitLongReadRequestMessageGroup(S7RequestMessage request){ + + S7CompositeRequestMessage compRequestMessage = new S7CompositeRequestMessage(request); + compRequestMessages.put(request.getTpduReference(), compRequestMessage); + + Optional varParameterOptional = request.getParameter(VarParameter.class); + VarParameter parameters = varParameterOptional.get(); + + boolean firtsRow = true; + short itemSize = 0; + short actualSize = 0; + short maxItemSize = (short) Math.round(pduSize * 0.8); + + + List parameterItems = parameters.getItems(); + + List splitParameters = new LinkedList<>(); + List splitPayloads = new LinkedList<>(); + + for (int i = 0; i < parameterItems.size(); i++) { + + VarParameterItem varParameterItem = parameterItems.get(i); + + itemSize = (short)(2 + getEstimatedResponseReadVarPayloadItemSize(varParameterItem)); + actualSize = 0; + for(VarParameterItem item:splitParameters){ + actualSize = (short) (actualSize + getEstimatedResponseReadVarPayloadItemSize(item)); //+=data.length + }; + + //TODO: Item size is > pduSize the Split is in the user layer. + if (itemSize > pduSize){ + //TODO: Evaluate that the fractional message should be blocked + // by the next layer. The response message indicating poor + // quality must also be generated at this point. + if (!splitParameters.isEmpty()){ + PrepareMessagesToNextLayer(request.getMessageType(), + parameters.getType(), + splitParameters, + Collections.EMPTY_LIST, + compRequestMessage); + + splitParameters = new LinkedList<>(); + splitPayloads = new LinkedList<>(); + } + + short tpdu = PrepareMessagesToNextLayer(request.getMessageType(), + parameters.getType(), + Collections.singletonList(varParameterItem), + Collections.EMPTY_LIST, + compRequestMessage); + + //throw new Plc4XNettyException("Read item request size bigger than " + pduSize+ + // " bytes. Split the Item in smaller units."); + + } else if ((itemSize > maxItemSize) && ((itemSize < pduSize))){ + + if (!splitParameters.isEmpty()){ + PrepareMessagesToNextLayer(request.getMessageType(), + parameters.getType(), + splitParameters, + Collections.EMPTY_LIST, + compRequestMessage); + + splitParameters = new LinkedList<>(); + splitPayloads = new LinkedList<>(); + } + + VarParameter writeVarParameter = new VarParameter(parameters.getType(), + Collections.singletonList(varParameterItem )); + + S7RequestMessage splitRequest = new S7RequestMessage(request.getMessageType(), + (short) tpduGenerator.getAndIncrement(), Collections.singletonList(writeVarParameter), + Collections.EMPTY_LIST, compRequestMessage); + + compRequestMessage.getRequestMessages().put(splitRequest.getTpduReference(),splitRequest); + compRequestMessages.put(splitRequest.getTpduReference(), compRequestMessage); + itemSize = 0; + + } else if (!firtsRow){ + + if ((((itemSize + actualSize) >= maxItemSize) && + ((itemSize + actualSize) <= pduSize)) || + (splitParameters.size() > 16) ){ + + splitParameters.add(varParameterItem); + + VarParameter writeVarParameter = new VarParameter(parameters.getType(), splitParameters); + + S7RequestMessage splitRequest = new S7RequestMessage(request.getMessageType(), + (short) tpduGenerator.getAndIncrement(), Collections.singletonList(writeVarParameter), + Collections.EMPTY_LIST, compRequestMessage); + + compRequestMessage.getRequestMessages().put(splitRequest.getTpduReference(),splitRequest); + compRequestMessages.put(splitRequest.getTpduReference(), compRequestMessage); + + splitParameters = new LinkedList<>(); + splitPayloads = new LinkedList<>(); + itemSize = 0; + + } else if ((((itemSize + actualSize) >= maxItemSize) && + ((itemSize + actualSize) > pduSize))){ + + if (!splitParameters.isEmpty()){ + PrepareMessagesToNextLayer(request.getMessageType(), + parameters.getType(), + splitParameters, + Collections.EMPTY_LIST, + compRequestMessage); + + splitParameters = new LinkedList<>(); + splitPayloads = new LinkedList<>(); + } + + VarParameter writeVarParameter = new VarParameter(parameters.getType(), + Collections.singletonList(varParameterItem )); + + S7RequestMessage splitRequest = new S7RequestMessage(request.getMessageType(), + (short) tpduGenerator.getAndIncrement(), Collections.singletonList(writeVarParameter), + Collections.EMPTY_LIST, compRequestMessage); + + compRequestMessage.getRequestMessages().put(splitRequest.getTpduReference(),splitRequest); + compRequestMessages.put(splitRequest.getTpduReference(), compRequestMessage); + itemSize = 0; + + } else { + splitParameters.add(varParameterItem); + } + + } else { + splitParameters.add(varParameterItem); + } + + if((i == (parameterItems.size() - 1)) && (splitParameters.size() !=0)){ + VarParameter writeVarParameter = new VarParameter(parameters.getType(), splitParameters); + + S7RequestMessage splitRequest = new S7RequestMessage(request.getMessageType(), + (short) tpduGenerator.getAndIncrement(), Collections.singletonList(writeVarParameter), + Collections.EMPTY_LIST, compRequestMessage); + + compRequestMessage.getRequestMessages().put(splitRequest.getTpduReference(),splitRequest); + compRequestMessages.put(splitRequest.getTpduReference(), compRequestMessage); + + splitParameters = new LinkedList<>(); + splitPayloads = new LinkedList<>(); + itemSize = 0; + } + + firtsRow = false; + + } + + return compRequestMessage.getRequestMessages(); + } + + + /************************************************************************ + * ASSEMBLY RESPONSE MESSAGE + ************************************************************************/ + + /* + * Try to assemble a response message from the response fragments. + * Since the PLC can handle at least two requests and depending on + * the load of its CPUs, the response order is not granted. + * TODO: If the connection is lost, the queue is invalid and must be deleted. + * TODO: The PLC reporta error, only the header is send. + * Example Error Class 0x81, Error code 0x04 + */ + private S7ResponseMessage AssemblyResponseMessage(S7CompositeRequestMessage compRequestMessage, + S7ResponseMessage response){ + + List splitParameters = new LinkedList<>(); + List splitPayloads = new LinkedList<>(); + List payloadItems = new LinkedList<>(); + + ParameterType parameterType = ParameterType.WRITE_VAR; + int numParameters = 0x000; + short tpduReference = 0x0000; + + LinkedHashMap requestMessages = + compRequestMessage.getRequestMessages(); + + LinkedHashMap responseMessages = + compRequestMessage.getResponseMessages(); + + tpduReference =((S7RequestMessage) compRequestMessage.getParent()).getTpduReference(); + //Always the firts element is the response the pdu number + Iterator> iterRequest = requestMessages.entrySet().iterator(); + + while(iterRequest.hasNext()){ + + Entry itemRequest = iterRequest.next(); + S7ResponseMessage msgResponse = (S7ResponseMessage) responseMessages.get(itemRequest.getKey()); + + //If no present we have a error code in the Header + Optional varParameterOptional = msgResponse.getParameter(VarParameter.class); + if (varParameterOptional.isPresent()){ + VarParameter parameters = varParameterOptional.get(); + parameterType = parameters.getType(); + //Como extraer los parametros del mensaje de respuesta + List varParameterItems = parameters.getItems(); + + S7AnyVarParameterItem s7AnyVarParameterItem = (S7AnyVarParameterItem) varParameterItems.get(0); + + numParameters += s7AnyVarParameterItem.getNumElements(); + + List payloads = msgResponse.getPayloads(); + + splitPayloads.addAll(payloads); + } else { + //Error from PLC + LOGGER.info("Error for tpud " + msgResponse.getTpduReference() + + " Error class: " + msgResponse.getErrorClass() + + " Error code" + msgResponse.getErrorCode()); + S7RequestMessage msgRequest = (S7RequestMessage) requestMessages.get(msgResponse.getTpduReference()); + + VarParameter requestParameters = (VarParameter) msgRequest.getParameters().get(0); + parameterType = requestParameters.getType(); + List varParameterItems = requestParameters.getItems(); + S7AnyVarParameterItem s7AnyVarParameterItem = (S7AnyVarParameterItem) varParameterItems.get(0); + numParameters += s7AnyVarParameterItem.getNumElements(); + VarPayload ackVarPayload = new VarPayload(requestParameters.getType(), + Collections.singletonList( new VarPayloadItem(DataTransportErrorCode.ACCESS_DENIED, null, null))); + splitPayloads.addAll(Collections.singletonList(ackVarPayload)); + + } + + } + + //Clean request messages + Set setKeys = requestMessages.keySet(); + setKeys.forEach(key->{compRequestMessages.remove(key);}); + compRequestMessages.remove(tpduReference); + + List varParameterItems; + varParameterItems = Collections.singletonList( + new S7AnyVarParameterItem(null, null, null, numParameters , (short) 0, (short) 0, (byte) 0)); + + S7Parameter s7Parameter = new VarParameter(parameterType, varParameterItems); + + splitParameters.add(s7Parameter); + + for(S7Payload s7Payload:splitPayloads){ + VarPayload varPayload = (VarPayload) s7Payload; + payloadItems.addAll(varPayload.getItems()); + } + + S7ResponseMessage res = new S7ResponseMessage(response.getMessageType(), + tpduReference, + splitParameters, + Collections.singletonList(new VarPayload(parameterType, payloadItems)), + (byte)0x00, (byte)0x00); + + return res; + } + + /************************************************************************ + * UTILITYS + ************************************************************************/ + + + static class S7CompositeRequestMessage implements PlcProtocolMessage { + + private S7RequestMessage originalRequest; + private LinkedHashMap requestMessages; + private LinkedHashMap responseMessages; + + S7CompositeRequestMessage(S7RequestMessage originalRequest) { + this.originalRequest = originalRequest; + this.requestMessages = new LinkedHashMap<>(); + this.responseMessages = new LinkedHashMap<>(); + } + + @Override + public PlcProtocolMessage getParent() { + return originalRequest; + } + + /** + * A {@link S7CompositeRequestMessage} is only acknowledged, if all children are acknowledged. + * + * @return true if all children are acknowledged. + */ + private boolean isAcknowledged() { + /* + for (S7RequestMessage requestMessage : requestMessages) { + if(!requestMessage.isAcknowledged()) { + return false; + } + }*/ + return true; + } + + void addRequestMessage(S7RequestMessage requestMessage) { + requestMessages.put(requestMessage.getTpduReference(),requestMessage); + } + + public LinkedHashMap getRequestMessages() { + return requestMessages; + } + + private void addResponseMessage(S7ResponseMessage responseMessage) { + responseMessages.putIfAbsent(responseMessage.getTpduReference(),responseMessage); + } + + public LinkedHashMap getResponseMessages() { + return responseMessages; + } + + public boolean isCompleted(){ + return ((requestMessages.size() - responseMessages.size()) == 0) ; + } + } + + //TODO: Use BaseType for length calculation. (Ok) + //TODO: For S7 STRING, maximum length is 254 -> One STRING request -> S7RequestMessage. HMI used CHAR array's + private static short getEstimatedResponseReadVarPayloadItemSize(VarParameterItem varParameterItem) { + // A var payload item always has a minimum size of 4 bytes (return code, transport size, size (two bytes)) + short length = 4; + short base =0; + S7AnyVarParameterItem s7AnyVarParameterItem = (S7AnyVarParameterItem) varParameterItem; + + base = (s7AnyVarParameterItem.getDataType().getBaseType() == null)? + (short) s7AnyVarParameterItem.getDataType().getSizeInBytes(): + (short)(s7AnyVarParameterItem.getDataType().getSizeInBytes() * + s7AnyVarParameterItem.getDataType().getBaseType().getSizeInBytes()); + + length += + s7AnyVarParameterItem.getNumElements() * base; + // It seems that bit payloads need a additional separating 0x00 byte. + if(s7AnyVarParameterItem.getDataType() == TransportSize.BOOL) { + length += 1; + } + return length; + } + + + private short PrepareMessagesToNextLayer(MessageType msgType, + ParameterType parameter, + List splitParameters, + List splitPayloads, + S7CompositeRequestMessage compMsg){ + + VarParameter writeVarParameter = new VarParameter(parameter, splitParameters); + VarPayload writeVarPayload = new VarPayload(parameter, splitPayloads); + + short tpdu = (short) tpduGenerator.getAndIncrement(); + + LOGGER.debug("SendMessagesToNextLayer tpdu: " + tpdu + + " Parameters:" + splitParameters.size() + + " Payloads: " + splitPayloads.size()); + + S7RequestMessage splitRequest = new S7RequestMessage(msgType, + tpdu, + Collections.singletonList(writeVarParameter), + (splitPayloads == Collections.EMPTY_LIST)? + Collections.EMPTY_LIST: + Collections.singletonList(writeVarPayload), + compMsg); + + compMsg.getRequestMessages().put(splitRequest.getTpduReference(),splitRequest); + compRequestMessages.put(splitRequest.getTpduReference(), compMsg); + + return tpdu; + } + + + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7PlcFieldHandler.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7PlcFieldHandler.java index 2799e49ce6f..bc52e72d390 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7PlcFieldHandler.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7PlcFieldHandler.java @@ -21,6 +21,10 @@ Licensed to the Apache Software Foundation (ASF) under one import java.lang.reflect.InvocationTargetException; import java.math.BigInteger; import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; import java.util.BitSet; import java.util.LinkedList; import java.util.List; @@ -41,7 +45,7 @@ public PlcField createField(String fieldQuery) { } if (S7SslField.matches(fieldQuery)) { return S7SslField.of(fieldQuery); - } + } throw new PlcInvalidFieldException(fieldQuery); } @@ -83,6 +87,7 @@ public BaseDefaultFieldItem encodeShort(PlcField field, Object[] values) { case WORD: case INT: case UINT: + case DATE: //TODO: Check for S71200/S71500 return internalEncodeInteger(field, values); default: throw new PlcRuntimeException("Invalid encoder for type " + s7Field.getDataType().name()); @@ -96,9 +101,10 @@ public BaseDefaultFieldItem encodeInteger(PlcField field, Object[] values) { case DWORD: case DINT: case UDINT: + case TIME: //TODO: Check for S71200/S71500 return internalEncodeInteger(field, values); default: - throw new PlcRuntimeException("Invalid encoder for type " + s7Field.getDataType().name()); + throw new PlcRuntimeException("encodeInteger: Invalid encoder for type " + s7Field.getDataType().name()); } } @@ -122,6 +128,8 @@ public BaseDefaultFieldItem encodeLong(PlcField field, Object[] values) { case LWORD: case LINT: case ULINT: + case DT: + case DATE_AND_TIME: return internalEncodeInteger(field, values); default: throw new PlcRuntimeException("Invalid encoder for type " + s7Field.getDataType().name()); @@ -160,7 +168,7 @@ public BaseDefaultFieldItem encodeString(PlcField field, Object[] values) { case WSTRING: return internalEncodeString(field, values); default: - throw new PlcRuntimeException("Invalid encoder for type " + s7Field.getDataType().name()); + throw new PlcRuntimeException("encodeString: Invalid encoder for type " + s7Field.getDataType().name()); } } @@ -169,9 +177,11 @@ public BaseDefaultFieldItem encodeTime(PlcField field, Object[] values) { S7Field s7Field = (S7Field) field; switch (s7Field.getDataType()) { case TIME: + case TOD: + case TIME_OF_DAY: return internalEncodeTemporal(field, values); default: - throw new PlcRuntimeException("Invalid encoder for type " + s7Field.getDataType().name()); + throw new PlcRuntimeException("encodeTime: Invalid encoder for type " + s7Field.getDataType().name()); } } @@ -182,7 +192,7 @@ public BaseDefaultFieldItem encodeDate(PlcField field, Object[] values) { case DATE: return internalEncodeTemporal(field, values); default: - throw new PlcRuntimeException("Invalid encoder for type " + s7Field.getDataType().name()); + throw new PlcRuntimeException("encodeDate: Invalid encoder for type " + s7Field.getDataType().name()); } } @@ -190,12 +200,25 @@ public BaseDefaultFieldItem encodeDate(PlcField field, Object[] values) { public BaseDefaultFieldItem encodeDateTime(PlcField field, Object[] values) { S7Field s7Field = (S7Field) field; switch (s7Field.getDataType()) { + case DT: case DATE_AND_TIME: return internalEncodeTemporal(field, values); default: - throw new PlcRuntimeException("Invalid encoder for type " + s7Field.getDataType().name()); + throw new PlcRuntimeException("encodeDateTime: Invalid encoder for type " + s7Field.getDataType().name()); } } + + @Override + public BaseDefaultFieldItem encodeDuration(PlcField field, Object[] values) { + S7Field s7Field = (S7Field) field; + switch (s7Field.getDataType()) { + case TIME: + case S5TIME: + return internalEncodeTemporal(field, values); + default: + throw new PlcRuntimeException("encodeDuration: Invalid encoder for type " + s7Field.getDataType().name()); + } + } private BaseDefaultFieldItem internalEncodeBoolean(PlcField field, Object[] values) { S7Field s7Field = (S7Field) field; @@ -265,6 +288,7 @@ private BaseDefaultFieldItem internalEncodeInteger(PlcField field, Object[] valu valueType = Byte[].class; castedValues = new Byte[values.length]; break; + case DATE: case WORD: minValue = BigInteger.valueOf((long) Short.MIN_VALUE); maxValue = BigInteger.valueOf((long) Short.MAX_VALUE); @@ -272,6 +296,9 @@ private BaseDefaultFieldItem internalEncodeInteger(PlcField field, Object[] valu valueType = Short[].class; castedValues = new Short[values.length]; break; + case TIME: + case TOD: + case TIME_OF_DAY: case DWORD: minValue = BigInteger.valueOf((long) Integer.MIN_VALUE); maxValue = BigInteger.valueOf((long) Integer.MAX_VALUE); @@ -279,6 +306,8 @@ private BaseDefaultFieldItem internalEncodeInteger(PlcField field, Object[] valu valueType = Integer[].class; castedValues = new Integer[values.length]; break; + case DT: + case DATE_AND_TIME: case LWORD: minValue = BigInteger.valueOf(Long.MIN_VALUE); maxValue = BigInteger.valueOf(Long.MAX_VALUE); @@ -489,7 +518,7 @@ private BaseDefaultFieldItem internalEncodeString(PlcField field, Object[] value List stringValues = new LinkedList<>(); for (Object value : values) { if (value instanceof String) { - String stringValue = (String) value; + String stringValue = (String) value; if (stringValue.length() > maxLength) { throw new IllegalArgumentException( "String length " + stringValue.length() + " exceeds allowed maximum for type " @@ -506,6 +535,14 @@ else if (value instanceof Byte) { } else { stringValues.add(new String(stringBytes, StandardCharsets.UTF_8)); } + } else if (value instanceof Character) { + Character characterValue = (Character) value; + byte[] stringBytes = new byte[]{(byte) characterValue.charValue()}; + if (encoding16Bit) { + stringValues.add(new String(stringBytes, StandardCharsets.UTF_16)); + } else { + stringValues.add(new String(stringBytes, StandardCharsets.UTF_8)); + } } else if (value instanceof Short) { Short shortValue = (Short) value; byte[] stringBytes = new byte[2]; @@ -557,17 +594,84 @@ else if (value instanceof Byte) { private BaseDefaultFieldItem internalEncodeTemporal(PlcField field, Object[] values) { S7Field s7Field = (S7Field) field; + BigInteger minValue; + BigInteger maxValue; + Class fieldType = null; + Class valueType = null; + Object[] castedValues = null; switch (s7Field.getDataType()) { + case S5TIME: + // TODO: Check new type + minValue = BigInteger.valueOf(0x0000); + maxValue = BigInteger.valueOf(0x3999); + fieldType = DefaultDurationFieldItem.class; + valueType = Duration[].class; + castedValues = new Duration[values.length]; + for (int i=0; i One STRING request -> S7RequestMessage. HMI used CHAR array's private static short getEstimatedResponseReadVarPayloadItemSize(VarParameterItem varParameterItem) { // A var payload item always has a minimum size of 4 bytes (return code, transport size, size (two bytes)) short length = 4; + short base =0; S7AnyVarParameterItem s7AnyVarParameterItem = (S7AnyVarParameterItem) varParameterItem; + + base = (s7AnyVarParameterItem.getDataType().getBaseType() == null)? + (short) s7AnyVarParameterItem.getDataType().getSizeInBytes(): + (short)(s7AnyVarParameterItem.getDataType().getSizeInBytes() * + s7AnyVarParameterItem.getDataType().getBaseType().getSizeInBytes()); + length += - s7AnyVarParameterItem.getNumElements() * s7AnyVarParameterItem.getDataType().getSizeInBytes(); + s7AnyVarParameterItem.getNumElements() * base; // It seems that bit payloads need a additional separating 0x00 byte. if(s7AnyVarParameterItem.getDataType() == TransportSize.BOOL) { length += 1; diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7SizeHelper.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7SizeHelper.java index f1f5849666a..47505d11be2 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7SizeHelper.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/util/S7SizeHelper.java @@ -65,8 +65,14 @@ public static short getPayloadsLength(List payloads) { for (S7Payload payload : payloads) { if(payload instanceof VarPayload) { VarPayload varPayload = (VarPayload) payload; + int i=1; for (VarPayloadItem payloadItem : varPayload.getItems()) { + //Check for "Fill Byte" + if((payloadItem.getData().length == 1) && (varPayload.getItems().size() > i) || (payloadItem.getData().length % 2 != 0)) { + l += 1; + } l += getPayloadLength(payloadItem); + i++; } } else if(payload instanceof CpuServicesPayload) { CpuServicesPayload cpuServicesPayload = (CpuServicesPayload) payload; diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7ByteReadResponse.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7ByteReadResponse.java index 655cd21945d..5c43374836b 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7ByteReadResponse.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7ByteReadResponse.java @@ -22,6 +22,7 @@ Licensed to the Apache Software Foundation (ASF) under one import io.netty.buffer.ByteBuf; import java.math.BigDecimal; import java.math.BigInteger; +import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; @@ -462,6 +463,31 @@ public PlcResponseCode getResponseCode(String name) { } return values.get(name).getKey(); } + + @Override + public boolean isValidDuration(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidDuration(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Duration getDuration(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Duration getDuration(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllDuration(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } protected ByteBuf getByteBufInternal(String name) { Objects.requireNonNull(name, "Name argument required"); diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmEvent.java index 93affa6aa31..ed1f0144fa1 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmEvent.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmEvent.java @@ -21,6 +21,7 @@ Licensed to the Apache Software Foundation (ASF) under one import java.math.BigDecimal; import java.math.BigInteger; +import java.time.Duration; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; @@ -632,6 +633,34 @@ public PlcResponseCode getResponseCode(String name) { throw new UnsupportedOperationException("Not supported yet."); } + @Override + public boolean isValidDuration(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidDuration(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Duration getDuration(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Duration getDuration(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllDuration(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + + + @Override public Map getMap() { return map; diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7ModeEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7ModeEvent.java index 2493925e08a..c3eeb4557ef 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7ModeEvent.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7ModeEvent.java @@ -21,6 +21,7 @@ Licensed to the Apache Software Foundation (ASF) under one import java.math.BigDecimal; import java.math.BigInteger; +import java.time.Duration; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; @@ -485,6 +486,31 @@ public PlcResponseCode getResponseCode(String name) { throw new UnsupportedOperationException("Not supported yet."); } + @Override + public boolean isValidDuration(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidDuration(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Duration getDuration(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Duration getDuration(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllDuration(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + @Override public String toString() { return "S7ModeEvent{" + "timeStamp=" + timeStamp + ", map=" + map + '}'; diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7SysEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7SysEvent.java index 30890622f28..7bb537da9a3 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7SysEvent.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7SysEvent.java @@ -21,6 +21,7 @@ Licensed to the Apache Software Foundation (ASF) under one import java.math.BigDecimal; import java.math.BigInteger; +import java.time.Duration; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; @@ -479,6 +480,31 @@ public PlcResponseCode getResponseCode(String name) { throw new UnsupportedOperationException("Not supported yet."); } + @Override + public boolean isValidDuration(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isValidDuration(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Duration getDuration(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Duration getDuration(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Collection getAllDuration(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + @Override public String toString() { return "S7SysEvent{" + "timeStamp=" + timeStamp + ", map=" + map + '}'; diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7SslHelper.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7Helper.java similarity index 87% rename from plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7SslHelper.java rename to plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7Helper.java index d667769f698..7d5e80bdf7c 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7SslHelper.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7Helper.java @@ -21,7 +21,11 @@ Licensed to the Apache Software Foundation (ASF) under one import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; +import java.time.Duration; +import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.temporal.ChronoUnit; import java.util.HashMap; import java.util.Map; @@ -103,7 +107,7 @@ Licensed to the Apache Software Foundation (ASF) under one * @author cgarcia */ -public class S7SslHelper { +public class S7Helper { /** * @@ -1123,7 +1127,7 @@ private static LocalDateTime readDateAndTime(ByteBuf data) { return LocalDateTime.of(year,month,day,hour,minute,second, nanoseconds); } - + /** * converts incoming byte to an integer regarding used BCD format @@ -1133,12 +1137,201 @@ private static LocalDateTime readDateAndTime(ByteBuf data) { private static int convertByteToBcd(byte incomingByte) { int dec = (incomingByte >> 4) * 10; return dec + (incomingByte & 0x0f); - } - + } + + /** + * converts incoming Short to an integer regarding used BCD format + * @param incomingShort + * @return converted BCD number + */ + private static short convertShortToBcd(short incomingShort) { -} + short res =(short) ((incomingShort >> 8) * 100 + + (incomingShort >> 4) * 10 + + (incomingShort & 0x0f)); + return res; + } + + } + + /* + * + */ + public static Duration S5TimeToDuration(Short data) { + Duration res; + short t = data; + long tv = (short)(((t & 0x000F))+((t & 0x00F0)>>4)*10+((t & 0x0F00) >> 8)*100); + long tb = (short)(10*Math.pow(10,((t & 0xF000) >> 12))); + long totalms = tv*tb; + if (totalms <= 9990000 ){ + res = Duration.ofMillis(totalms); + } else { + res = Duration.ofMillis(9990000); + } + return res; + } + + /* + * + */ + public static Short DurationToS5Time(Duration data) { + short tv = 0; + short tb = 0x0000_0000; + short s5time = 0x0000; + long totalms = data.toMillis(); + + if ((totalms >= 0) && (totalms <= 9990000)) { + + if ((totalms>=0) && ((totalms<=9990))){ + tb = 0x0000_0000; //10 ms + tv = (short)(totalms / 10); + } else if ((totalms>9990) && ((totalms<=99900))){ + tb = 0x0000_0001;// 100 ms + tv = (short)(totalms / 100); + } else if ((totalms>99900) && ((totalms<=999000))){ + tb = 0x0000_0002;//1000 ms + tv = (short)(totalms / 1000); + } else if ((totalms>999000) && ((totalms<=9990000))){ + tb = 0x0000_0003;//10000 ms + tv = (short)(totalms / 10000); + } + + short uni = (short)(tv % 10); + short dec = (short)((tv / 10) % 10); + short cen = (short)((tv / 100) % 10); + s5time = (short)(((tb)<<12) | (cen << 8) | (dec << 4) | (uni)); + } + return s5time; + } + public static Duration S7TimeToDuration(Integer data) { + Duration res = Duration.ZERO; + if (data>= 0){ + res = res.plusMillis((long) data); + } else { + long ms = 0x8000_0000 - (data & 0x8000_0000); + res = res.minusMillis((long) data); + } + + return res; + } + + public static Integer DurationToS7Time(Duration data) { + Integer res = 0x0000_0000; + if (data.isNegative()){ + res = (int) data.toMillis() + 0x8000_0000; + } else { + res = (int) data.toMillis(); + } + return res; + } + public static LocalTime S7TodToLocalTime(Integer data) { + if (data > 0x0526_5bff) data=0x0526_5bff; + if (data < 0) data=0x0000_0000; + LocalTime res = LocalTime.MIDNIGHT.plusNanos((long)data*1_000_000); + return res; + } + public static Integer LocalTimeToS7Tod(LocalTime data) { + return (int)(data.toNanoOfDay() / 1_000_000); + } + + public static LocalDate S7DateToLocalDate(Short data) { + LocalDate res = LocalDate.of(1990, 1, 1); + res = res.plusDays((long) data); + return res; + } + + public static Short LocalDateToS7Date(LocalDate data) { + LocalDate ini = LocalDate.of(1990, 1, 1); + long resl = ChronoUnit.DAYS.between(ini, data); + short res = (short) resl; + return res; + } + + /* + * Date and time of day (BCD coded). + * +----------------+ + * Byte n | Year 0 to 99 | + * +----------------+ + * Byte n+1 | Month 1 to 12 | + * +----------------+ + * Byte n+2 | Day 1 to 31 | + * +----------------+ + * Byte n+3 | Hour 0 to 23 | + * +----------------+ + * Byte n+4 | Minute 0 to 59 | + * +----------------+ + * Byte n+5 | Second 0 to 59 | + * +----------------+ + * Byte n+6 | ms 0 to 999 | + * Byte n+7 | X X X X X D O W| + * +----------------+ + * DOW: Day of weed (last 3 bits) + */ + public static LocalDateTime S7DateTimeToLocalDateTime(ByteBuf data) { + //from Plc4XS7Protocol + int year= byteBCDToInt(data.readByte()); + int month= byteBCDToInt(data.readByte()); + int day = byteBCDToInt(data.readByte()); + int hour= byteBCDToInt(data.readByte()); + int minute= byteBCDToInt(data.readByte()); + int second= byteBCDToInt(data.readByte()); + int millih= byteBCDToInt(data.readByte()) * 10; + + int milll= (data.readByte() >> 4); + + int milliseconds = millih + milll; + int nanoseconds = milliseconds * 1000000; + //At this point a dont need the day of week + //data-type ranges from 1990 up to 2089 + if(year>=90){ + year+=1900; + } + else{ + year+=2000; + } + + return LocalDateTime.of(year,month,day,hour,minute,second, nanoseconds); + } + + public static byte[] LocalDateTimeToS7DateTime(LocalDateTime data) { + byte[] res = new byte[8]; + + res[0] = convertByteToBcd((data.getYear() % 100)); + res[1] = convertByteToBcd(data.getMonthValue()); + res[2] = convertByteToBcd(data.getDayOfMonth()); + res[3] = convertByteToBcd(data.getHour()); + res[4] = convertByteToBcd(data.getMinute()); + res[5] = convertByteToBcd(data.getSecond()); + + long ms = (long)(data.getNano() / 1_000_000); + res[6] = (byte)((int)(((ms / 100) << 4) | ((ms / 10)%10))) ; + //Java:1 (Monday) to 7 (Sunday)->S7:1 (Sunday) to 7 (Saturday) + byte dayofweek = (byte)((data.getDayOfWeek().getValue()<7)? + data.getDayOfWeek().getValue()+1: + (byte)0x01); + res[7] = (byte)(((ms % 10) << 4) | ((byte)(dayofweek))); + + return res; + } + + + /** + * converts incoming byte to an integer regarding used BCD format + * @param incomingByte + * @return converted BCD number + */ + private static byte convertByteToBcd(int incomingByte) { + byte dec = (byte)((incomingByte / 10) % 10); + return (byte)((dec << 4) | (incomingByte % 10)); + } + + private static int byteBCDToInt(byte bcd){ + int res=(bcd>>4)*10 + (bcd & 0x0f); + return res; + } + } From 1f4acc3bc8fb2fd7c8c47866b08a430d07f6c268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Wed, 11 Mar 2020 13:08:29 -0400 Subject: [PATCH 11/17] Fix Read CHAR[] only read one char. --- .../java/org/apache/plc4x/java/s7/netty/Plc4XS7Protocol.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 a33b6d63dc2..cf9ffd27cfb 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 @@ -1280,7 +1280,7 @@ private PlcResponse decodeReadResponse(S7ResponseMessage responseMessage, PlcReq // Characters & Strings // ----------------------------------------- case CHAR: // 1 byte (8 bit) - fieldItem = decodeReadResponseFixedLengthStringField(1, false, data); + fieldItem = decodeReadResponseFixedLengthStringField(field.getNumElements(), false, data); break; case WCHAR: // 2 byte fieldItem = decodeReadResponseFixedLengthStringField(1, true, data); From 0df720a539b0a79dd7bd47ee25a6da62677ff3e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Wed, 11 Mar 2020 19:35:43 -0400 Subject: [PATCH 12/17] Fix S7Field parsing. --- .../src/main/java/org/apache/plc4x/java/s7/model/S7Field.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java index d132c6fc02b..b72722348a0 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java @@ -34,7 +34,7 @@ public class S7Field implements PlcField { //byteOffset theoretically can reach up to 2097151 ... see checkByteOffset() below --> 7digits private static final Pattern ADDRESS_PATTERN = - Pattern.compile("^%(?.)(?[XBWD]?)(?\\d{1,7})(.(?[0-7]))?:(?[a-zA-Z_5][S5TIME]+)(\\[(?\\d+)])?"); + Pattern.compile("^%(?.)(?[XBWD]?)(?\\d{1,7})(.(?[0-7]))?:(?[a-zA-Z_5]+)(\\[(?\\d+)])?"); //blockNumber usually has its max hat around 64000 --> 5digits //TODO: S5TIME non include; From 8ff17709b93a9c36ff00c5c33372f7a57253d903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Tue, 24 Mar 2020 00:25:40 -0400 Subject: [PATCH 13/17] ALARM_S type alarm acknowledgment reception fixed. --- plc4j/drivers/pom.xml | 1 - .../apache/plc4x/java/s7/model/S7Field.java | 3 ++ .../plc4x/java/s7/netty/Plc4XS7Protocol.java | 8 ++- .../plc4x/java/s7/netty/S7Protocol.java | 53 ++++++++++++++----- .../java/s7/netty/model/types/SslId.java | 6 ++- .../java/s7/protocol/event/S7AlarmEvent.java | 10 +++- plc4j/utils/pom.xml | 2 - 7 files changed, 63 insertions(+), 20 deletions(-) diff --git a/plc4j/drivers/pom.xml b/plc4j/drivers/pom.xml index d346db205b2..611ed29d3cb 100644 --- a/plc4j/drivers/pom.xml +++ b/plc4j/drivers/pom.xml @@ -39,7 +39,6 @@ ethernet-ip modbus s7 - simulated opcua diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java index b72722348a0..58ac2387ac8 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java @@ -102,6 +102,9 @@ public static boolean matches(String fieldString) { @Override public Class getDefaultJavaType() { switch (dataType){ + case BYTE: + return Byte.class; + case CHAR: case STRING: return String.class; case USINT: 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 cf9ffd27cfb..e4377debc8c 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 @@ -1669,7 +1669,13 @@ private PlcResponse decodeSubscriptionResponse(S7ResponseMessage responseMessage if (!alarmsqueue.offer((S7PushMessage) payload)){ logger.info("decodeSubscriptionResponse: Alarm queue buffer is full."); }; - }; + } + PlcResponseCode responseCode = decodeResponseCode(((AlarmMessagePayload) payload).getReturnCode()); + LinkedHashSet fieldnames = subsRequest.getFieldNames(); + fieldnames.forEach((fieldname)->{ + values.put(fieldname, new ImmutablePair(responseCode, null)); + }); + } else { logger.debug("Check for ALARM_QUERY not attended: " + payloadItem); } 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 78f1c446d89..1a3c8653a47 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 @@ -964,6 +964,7 @@ else if ((readWriteVarParameter.getType() == ParameterType.READ_VAR) && isRespon private S7Payload decodeCpuServicesPayload(CpuServicesParameter parameter, ByteBuf userData) { if (parameter.getFunctionGroup() == CpuServicesParameterFunctionGroup.CPU_FUNCTIONS) { + logger.info("decodeCpuServicesPayload: " + parameter.getSubFunctionGroup()); switch(parameter.getSubFunctionGroup()){ case READ_SSL: { CpuServicesPayload payload = decodeReadSslPayload(parameter, userData); @@ -1327,21 +1328,23 @@ else if((length >= 8) || ((length == 0) && lastdataunit)) { } private AlarmMessagePayload decodeMessageServicePayload(CpuServicesParameter parameter, ByteBuf userData){ - + //logger.info(ByteBufUtil.prettyHexDump(userData)); + AlarmType alarmtype = null; DataTransportErrorCode returnCode = DataTransportErrorCode.valueOf(userData.readByte()); DataTransportSize dataTransportSize = DataTransportSize.valueOf(userData.readByte()); int length = userData.readShort(); - byte result = userData.readByte(); - byte unknown = userData.readByte(); - AlarmType alarmtype = null; - - if (length>2) { - alarmtype = AlarmType.valueOf(userData.readByte()); - unknown = userData.readByte(); - unknown = userData.readByte(); - } else { - //Free dummy byte + if (length != 0){ + byte result = userData.readByte(); + byte unknown = userData.readByte(); + + if (length>2) { + alarmtype = AlarmType.valueOf(userData.readByte()); + unknown = userData.readByte(); + unknown = userData.readByte(); + } else { + //Free dummy byte + } } return new AlarmMessagePayload(returnCode, @@ -1484,7 +1487,7 @@ private AlarmMessagePayload decodeMessageServicePushPayload(CpuServicesParameter }; private AlarmMessagePayload decodeMessageServiceQueryPayload(CpuServicesParameter parameter, ByteBuf userData){ - + List MessageObjects = new LinkedList<>(); CpuServicesResponseParameter thisparameter = null; int length; @@ -1507,9 +1510,33 @@ private AlarmMessagePayload decodeMessageServiceQueryPayload(CpuServicesParamete lastdataunit = thisparameter.isLastDataUnit(); } + //Response to query + if ((length == 6) && + lastdataunit && + (thisparameter.getSubFunctionGroup() == CpuServicesParameterSubFunctionGroup.ALARM_QUERY)){ + //Alarm message information + FunctionID = userData.readByte(); + NumberOfMessageObjects = userData.readByte(); + AlarmReturnCode = DataTransportErrorCode.valueOf(userData.readByte()); + AlarmTransportSize = DataTransportSize.valueOf(userData.readByte()); + CompleteDataLength = userData.readShort(); + + return new AlarmMessagePayload(returnCode, + dataTransportSize, + CpuServicesParameterSubFunctionGroup.ALARM_QUERY, + length, + new AlarmMessageItem(FunctionID, + NumberOfMessageObjects, + AlarmReturnCode, + AlarmTransportSize, + CompleteDataLength, + MessageObjects)); + + } + //Fragmente code //The next Level query again. - + if ((length > 2) && (!lastdataunit)){ //Is alway a CpuServicesResponseParameter instance? diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/SslId.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/SslId.java index 9dbf00a9bcb..26d42c27175 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/SslId.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/SslId.java @@ -43,7 +43,11 @@ public enum SslId { USER_MEMORY_AREAS((short) 0x0013), SYSTEM_AREAS((short) 0x0014), BLOCK_TYPES((short) 0x0015), - COMPONENT_IDENTIFICATION((short) 0x001c), + COMPONENT_IDENTIFICATION_ALL((short) 0x001c), + COMPONENT_IDENTIFICATION_INDV((short) 0x0011c), + COMPONENT_IDENTIFICATION_ALL_H((short) 0x0021c), + COMPONENT_IDENTIFICATION_INDV_H((short) 0x0031c), + COMPONENT_IDENTIFICATION_PARTIAL((short) 0x00F1c), INTERRUPT_STATUS((short) 0x0022), ASSIGNMENT_BETWEEN_PROCESS_IMAGE_PARTITIONS_AND_OBS((short) 0x0025), COMPUTATION_STATUS_DATA((short) 0x0032), diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmEvent.java index ed1f0144fa1..4c9785f4932 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmEvent.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmEvent.java @@ -174,8 +174,7 @@ private static S7AlarmEvent createAlarmEvent(CpuServicesParameterSubFunctionGrou map.put(Fields.SIG_1_DATA_COMING.name(), datos); break; - case ALARM_8: - + case ALARM_8: map.put(Fields.TYPE.toString(), CpuServicesParameterSubFunctionGroup.ALARM8); break; case SCAN: @@ -189,6 +188,13 @@ private static S7AlarmEvent createAlarmEvent(CpuServicesParameterSubFunctionGrou } break; case ALARM_ACK_IND:; + map.put(Fields.TYPE.toString(), CpuServicesParameterSubFunctionGroup.ALARM_S_IND.getCode()); + map.put(Fields.TIMESTAMP.name(), msgItem.getTimestamp().toInstant(ZoneOffset.UTC)); + map.put(Fields.EVENT_ID.name(), message.getEventID()); + map.put(Fields.EVENT_STATE.name(), message.getEventState()); + map.put(Fields.STATE.name(), message.getState()); + map.put(Fields.ACKSTATE_GOING.name(), message.getAckStateGoing()); + map.put(Fields.ACKSTATE_COMING.name(), message.getAckStateComming()); break; case ALARM_SQ_IND: case ALARM_S_IND:{ diff --git a/plc4j/utils/pom.xml b/plc4j/utils/pom.xml index c9fa3701ccf..658966f7f91 100644 --- a/plc4j/utils/pom.xml +++ b/plc4j/utils/pom.xml @@ -45,8 +45,6 @@ connection-pool - opm - scraper From e96609de6712fa1f0223636b786883b9baa864cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Sat, 28 Mar 2020 21:39:41 -0400 Subject: [PATCH 14/17] Fix S7 cyclic subscription. --- .../java/s7/connection/S7PlcConnection.java | 106 ++-- plc4j/pom.xml | 1 - .../plc4x/java/s7/netty/Plc4XS7Protocol.java | 22 +- .../plc4x/java/s7/netty/S7Protocol.java | 41 +- .../CpuServicesParameterSubFunctionGroup.java | 4 +- .../S7CyclicServicesSubscriptionHandle.java | 16 +- .../java/s7/protocol/event/S7AlarmEvent.java | 29 +- .../s7/protocol/event/S7CyclicValueEvent.java | 475 ++++++++++++++++++ .../apache/plc4x/java/s7/utils/S7Helper.java | 22 + 9 files changed, 633 insertions(+), 83 deletions(-) create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7CyclicValueEvent.java diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java index 4e3b8c589d2..9ef18d53747 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/connection/S7PlcConnection.java @@ -18,7 +18,6 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.s7.connection; -import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.*; import java.net.InetAddress; @@ -38,7 +37,6 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.commons.configuration2.Configuration; import org.apache.commons.configuration2.SystemConfiguration; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.tuple.Pair; import org.apache.plc4x.java.api.exceptions.PlcConnectionException; import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; import org.apache.plc4x.java.api.messages.PlcReadRequest; @@ -53,7 +51,6 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.api.model.PlcConsumerRegistration; import org.apache.plc4x.java.api.model.PlcField; import org.apache.plc4x.java.api.model.PlcSubscriptionHandle; -import org.apache.plc4x.java.api.types.PlcResponseCode; import org.apache.plc4x.java.base.connection.ChannelFactory; import org.apache.plc4x.java.base.connection.NettyPlcConnection; import org.apache.plc4x.java.base.events.ConnectEvent; @@ -84,6 +81,7 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.s7.protocol.S7CyclicServicesSubscriptionHandle; import org.apache.plc4x.java.s7.protocol.S7DiagnosticSubscriptionHandle; import org.apache.plc4x.java.s7.protocol.event.S7AlarmEvent; +import org.apache.plc4x.java.s7.protocol.event.S7CyclicValueEvent; import org.apache.plc4x.java.s7.protocol.event.S7Event; import org.apache.plc4x.java.s7.protocol.event.S7ModeEvent; import org.apache.plc4x.java.s7.protocol.event.S7SysEvent; @@ -134,7 +132,7 @@ public class S7PlcConnection extends NettyPlcConnection implements PlcReader, Pl Map> cyclicServicesSubscriptions = new HashMap(); Map> pushEventHandles = new HashMap(); - Map cyclicServicesHandles = new HashMap(); + Map> cyclicServicesHandles = new HashMap(); private EventLoop alarmsloopthread; @@ -445,14 +443,21 @@ public CompletableFuture unsubscribe(PlcUnsubscriptio @Override public PlcConsumerRegistration register(Consumer consumer, Collection handles) { //Add any handler to - handles.forEach(handle ->{ - if (handle instanceof S7CyclicServicesSubscriptionHandle) { - S7CyclicServicesSubscriptionHandle s7handle = (S7CyclicServicesSubscriptionHandle) handle; - if (!cyclicServicesHandles.containsKey(s7handle.getJobId())){ - cyclicServicesHandles.put((short) s7handle.getJobId(), s7handle); - } + Object objHandle = handles.toArray()[0]; + + if (objHandle instanceof S7CyclicServicesSubscriptionHandle) { + S7CyclicServicesSubscriptionHandle firtsHandle = (S7CyclicServicesSubscriptionHandle) objHandle; + handles.forEach(handle ->{ + S7CyclicServicesSubscriptionHandle s7handle = (S7CyclicServicesSubscriptionHandle) handle; + s7handle.getConsumers().add(consumer); + }); + + if (!cyclicServicesHandles.containsKey(firtsHandle.getJobId())){ + cyclicServicesHandles.put((short) firtsHandle.getJobId(), handles); } + } + handles.forEach(handle ->{ if (handle instanceof S7DiagnosticSubscriptionHandle) { S7DiagnosticSubscriptionHandle s7handle = (S7DiagnosticSubscriptionHandle) handle; s7handle.getConsumers().add(consumer); @@ -482,14 +487,14 @@ private class EventLoop extends Thread { private int delay; private final Map> cyclicServicesSubscriptions; private final Map> pushEventHandles; - private final Map cyclicServicesHandles; + private final Map> cyclicServicesHandles; private final BlockingQueue alarmsqueue; EventLoop(Channel channel, BlockingQueue alarmsqueue, Map> cyclicServicesSubscriptions, Map> pushEventHandles, - Map cyclicServicesHandles) { + Map> cyclicServicesHandles) { this.channel = channel; this.alarmsqueue = alarmsqueue; this.cyclicServicesSubscriptions = cyclicServicesSubscriptions; @@ -528,16 +533,45 @@ public void run() { } else if (msg instanceof CpuServicesPushParameter) { CpuServicesPushParameter themsg = (CpuServicesPushParameter) msg; - logger.info("CpuServicesPushParameter: " + themsg); + logger.debug("CpuServicesPushParameter: " + themsg); } else if (msg instanceof CpuCyclicServicesResponsePayload) { CpuCyclicServicesResponsePayload themsg = (CpuCyclicServicesResponsePayload) msg; logger.debug("CpuCyclicServicesResponsePayload: " + themsg + " JobId:" + themsg.getJobId()); - S7CyclicServicesSubscriptionHandle handle = - (S7CyclicServicesSubscriptionHandle) cyclicServicesHandles.get(themsg.getJobId()); - if (handle != null) { - UpdateCyclicServicesData(handle, themsg); + Collection handles = cyclicServicesHandles.get((short)themsg.getJobId()); + if (handles != null) { + int i=0; + for(PlcSubscriptionHandle handle:handles) { + AssociatedValueItem itemValue = ((S7CyclicServicesSubscriptionHandle) handle).getValueItem(); + AssociatedValueItem newValue = themsg.getItems().get(i); + synchronized(newValue) { + itemValue.getData().setBytes(0, newValue.getData()); + } + i++; + }; + + if (cyclicServicesSubscriptions.containsValue(handles)){ + Map eventData = new HashMap(); + synchronized(handles){ + for (PlcSubscriptionHandle handle:handles){ + S7CyclicServicesSubscriptionHandle s7Handle = (S7CyclicServicesSubscriptionHandle) handle; + AssociatedValueItem newItem = new AssociatedValueItem(s7Handle.getValueItem().getReturnCode(), + s7Handle.getValueItem().getDataTransportSize(), + s7Handle.getValueItem().getLength(), + s7Handle.getValueItem().getData().copy()); + eventData.put(s7Handle.getFieldName(), newItem); + } + }; + + S7CyclicServicesSubscriptionHandle s7Handle = + (S7CyclicServicesSubscriptionHandle) handles.toArray()[0]; + Consumer consumer = + (Consumer )s7Handle.getConsumers().toArray()[0]; + S7CyclicValueEvent event = new S7CyclicValueEvent(eventData); + consumer.accept(event); + }; + }; } else { @@ -603,38 +637,20 @@ private void dispathModeEvents(Map handles, CpuDia }); } - private void UpdateCyclicServicesData(S7CyclicServicesSubscriptionHandle handle,CpuCyclicServicesResponsePayload themsg){ - - Map items = handle.getItems(); - Collection values = items.values(); - List newvalues = themsg.getItems(); - int i = 0; - synchronized(values) { - for (AssociatedValueItem value:values){ - AssociatedValueItem newvalue = newvalues.get(i); - value.getData().setBytes(0, newvalue.getData()); - i++; - } + private void UpdateCyclicServicesData(S7CyclicServicesSubscriptionHandle handle, AssociatedValueItem newValue){ + AssociatedValueItem itemValue = handle.getValueItem(); + + synchronized(newValue) { + itemValue.getData().setBytes(0, newValue.getData()); } cyclicServicesSubscriptions.forEach((consumer,handles)->{ if (handles.contains(handle)){ - handles.forEach((exehandle)->{ - Map> fields = new HashMap<>(); - S7CyclicServicesSubscriptionHandle exe2handle = (S7CyclicServicesSubscriptionHandle) exehandle; - Map values2consumer = exe2handle.getItems(); - - //PlcSubscriptionEvent event = new DefaultPlcSubscriptionEvent(Instant.now(), fields); - - values2consumer.forEach((index, itemvalue)->{ - if (consumer != null) { - consumer.accept(null); - }; - //logger.info("Procesando valores : " + index + "\r\n" + ByteBufUtil.prettyHexDump(itemvalue.getData())); - }); - //Pair newPair = new ImmutablePair<>(PlcResponseCode, stringItem); - //exehandle - }); + + if (consumer != null) { + consumer.accept(null); + }; + } }); diff --git a/plc4j/pom.xml b/plc4j/pom.xml index 58645bd9d7f..62f2f98442a 100644 --- a/plc4j/pom.xml +++ b/plc4j/pom.xml @@ -40,7 +40,6 @@ utils examples - integrations karaf-features 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 e4377debc8c..dee0b1a99cc 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 @@ -1696,22 +1696,24 @@ private PlcResponse decodeSubscriptionResponse(S7ResponseMessage responseMessage if (parameter.getError().getCode() == 0x0000){ for (String fieldname:subsRequest.getFieldNames()){ items.put(fieldname, valueitems.get(i)); + S7CyclicServicesSubscriptionHandle handler = new S7CyclicServicesSubscriptionHandle(fieldname, + parameter.getSequenceNumber(), + parameter.getError().getCode(), + valueitems.get(i)); + values.put(fieldname, + new ImmutablePair(decodeResponseCode(valueitems.get(i).getReturnCode()), + handler)); i++; }; }; - - S7CyclicServicesSubscriptionHandle handler = new S7CyclicServicesSubscriptionHandle("UNO", - parameter.getSequenceNumber(), - parameter.getError().getCode(), - items); + + } else { + logger.info("At least one wrong address was requested."); // Return quality code for alarm for (String fieldname:subsRequest.getFieldNames()){ - values.put(fieldname, new ImmutablePair(decodeResponseCode(items.get(fieldname).getReturnCode()), handler)); + values.put(fieldname, new ImmutablePair(PlcResponseCode.INVALID_ADDRESS, null)); } - - - } else { - logger.info("Must return values...?"); + } } else { 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 1a3c8653a47..ba3168304ae 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 @@ -419,7 +419,7 @@ private void encodeAlarmMessagePayload(AlarmMessagePayload payload, ByteBuf buf) logger.debug("encodeAlarmMessagePayload: ALARM_LOCKFREE no supportesd"); break; case ALARM_IND:; - logger.debug("encodeAlarmMessagePayload: ALARM_IND no supportesd"); + logger.debug("encodeAlarmMessagePayload: ALARM no supportesd"); break; case ALARM_ACK:{ logger.debug("encodeAlarmMessagePayload: ALARM_ACK"); @@ -924,6 +924,7 @@ private List decodePayloads(ByteBuf userData, boolean isResponse, sho private VarPayload decodeVarPayload(ByteBuf userData, boolean isResponse, short userDataLength, VarParameter readWriteVarParameter) { + //System.out.println("decodeVarPayload:\r\n" + ByteBufUtil.prettyHexDump(userData)); List payloadItems = new LinkedList<>(); // Just keep on reading payloads until the provided length is read. @@ -962,9 +963,7 @@ else if ((readWriteVarParameter.getType() == ParameterType.READ_VAR) && isRespon } private S7Payload decodeCpuServicesPayload(CpuServicesParameter parameter, ByteBuf userData) { - if (parameter.getFunctionGroup() == CpuServicesParameterFunctionGroup.CPU_FUNCTIONS) { - logger.info("decodeCpuServicesPayload: " + parameter.getSubFunctionGroup()); switch(parameter.getSubFunctionGroup()){ case READ_SSL: { CpuServicesPayload payload = decodeReadSslPayload(parameter, userData); @@ -1024,6 +1023,10 @@ private S7Payload decodeCpuServicesPayload(CpuServicesParameter parameter, ByteB AlarmMessagePayload payload = decodeMessageServicePushPayload(parameter, userData); return payload; } + case ALARM: { + AlarmMessagePayload payload = decodeMessageServicePushPayload(parameter, userData); + return payload; + } default:; break; } @@ -1135,9 +1138,8 @@ private CpuServicesParameter decodeCpuServicesParameter(ByteBuf in) { byte dataUnitReferenceNumber = in.readByte(); boolean lastDataUnit = in.readByte() == 0x00; ParameterError error = ParameterError.valueOf(in.readShort()); - logger.info("decodeParameter.: " + error); - - return new CpuCyclicServicesResponseParameter(functionGroup, subCycFunctionGroup, sequenceNumber, + + return new CpuCyclicServicesResponseParameter(functionGroup, subCycFunctionGroup, sequenceNumber, dataUnitReferenceNumber, lastDataUnit, error); } else { return new CpuServicesPushParameter(functionGroup, subFunctionGroup, sequenceNumber); @@ -1386,6 +1388,7 @@ private CpuDiagnosticMessagePayload decodeCpuDiagnosticMessagePayload(CpuService } private AlarmMessagePayload decodeMessageServicePushPayload(CpuServicesParameter parameter, ByteBuf userData){ + List MessageObjects = new LinkedList<>(); List values = new LinkedList<>(); int length; @@ -1491,11 +1494,11 @@ private AlarmMessagePayload decodeMessageServiceQueryPayload(CpuServicesParamete List MessageObjects = new LinkedList<>(); CpuServicesResponseParameter thisparameter = null; int length; - byte FunctionID; - byte NumberOfMessageObjects; //Say 1, but I have 2 messages? Why? - DataTransportErrorCode AlarmReturnCode; - DataTransportSize AlarmTransportSize; - int CompleteDataLength; + byte FunctionID = 0x00; + byte NumberOfMessageObjects = 0x00; //Say 1, but I have 2 messages? Why? + DataTransportErrorCode AlarmReturnCode = DataTransportErrorCode.RESERVED; + DataTransportSize AlarmTransportSize = DataTransportSize.NULL; + int CompleteDataLength = 0x0000; short dataUnitReferenceNumber = 0x0000; boolean lastdataunit = true; @@ -1510,6 +1513,22 @@ private AlarmMessagePayload decodeMessageServiceQueryPayload(CpuServicesParamete lastdataunit = thisparameter.isLastDataUnit(); } + //Response to query from S7-1500 + if ((length == 0) && + lastdataunit && + (thisparameter.getSubFunctionGroup() == CpuServicesParameterSubFunctionGroup.ALARM_QUERY)){ + return new AlarmMessagePayload(returnCode, + dataTransportSize, + CpuServicesParameterSubFunctionGroup.ALARM_QUERY, + length, + new AlarmMessageItem(FunctionID, + NumberOfMessageObjects, + AlarmReturnCode, + AlarmTransportSize, + CompleteDataLength, + MessageObjects)); + } + //Response to query if ((length == 6) && lastdataunit && diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuServicesParameterSubFunctionGroup.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuServicesParameterSubFunctionGroup.java index 10ebcfd48c2..e388e91f76d 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuServicesParameterSubFunctionGroup.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/model/types/CpuServicesParameterSubFunctionGroup.java @@ -28,12 +28,12 @@ public enum CpuServicesParameterSubFunctionGroup { READ_SSL((byte) 0x01), MESSAGE_SERVICE((byte) 0x02), DIAG_MESSAGE((byte) 0x03), - ALARM_S((byte) 0x04), + ALARM((byte) 0x04), ALARM8((byte) 0x05), NOTIFY((byte) 0x06), ALARM8_LOCK((byte) 0x07), ALARM8_UNLOCK((byte) 0x08), - SCAN((byte) 0x04), + SCAN((byte) 0x09), ALARM_ACK((byte) 0x0b), ALARM_ACK_IND((byte) 0x0c), ALARM8_LOCK_IND((byte) 0x0d), diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7CyclicServicesSubscriptionHandle.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7CyclicServicesSubscriptionHandle.java index c0137eb577d..11dbf684c06 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7CyclicServicesSubscriptionHandle.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/S7CyclicServicesSubscriptionHandle.java @@ -19,7 +19,6 @@ Licensed to the Apache Software Foundation (ASF) under one package org.apache.plc4x.java.s7.protocol; import java.util.HashSet; -import java.util.Map; import java.util.Set; import java.util.function.Consumer; import org.apache.plc4x.java.api.messages.PlcSubscriptionEvent; @@ -32,22 +31,23 @@ Licensed to the Apache Software Foundation (ASF) under one * @author cgarcia */ public class S7CyclicServicesSubscriptionHandle implements InternalPlcSubscriptionHandle { + Set> consumers = new HashSet<>(); //CyClic Services information hanler private final String fieldName; //Subscription id from the request private final byte jobId; //Job-Id from cyclic subscriotion private final short error; //Register the error from the suscription. - private Map items; + private final AssociatedValueItem item; public S7CyclicServicesSubscriptionHandle(String fieldName, byte jobId, short error, - Map items) { + AssociatedValueItem item) { this.fieldName = fieldName; this.jobId = jobId; this.error = error; - this.items = items; + this.item = item; } public Set> getConsumers() { @@ -66,12 +66,8 @@ public short getError() { return error; } - public AssociatedValueItem getValueItem(String index){ - return items.get(index); - } - - public Map getItems() { - return items; + public AssociatedValueItem getValueItem(){ + return item; } @Override diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmEvent.java index 4c9785f4932..cb16056e89a 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmEvent.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7AlarmEvent.java @@ -144,12 +144,11 @@ private static S7AlarmEvent createAlarmEvent(CpuServicesParameterSubFunctionGrou Map map = new HashMap(); AssociatedValueItem itemValue; byte[] datos; - - switch(subFunction){ + switch(subFunction){ case ALARM_QUERY:{ switch(message.getAlarmtype()){ case ALARM_S: - map.put(Fields.TYPE.toString(), CpuServicesParameterSubFunctionGroup.ALARM_S.getCode()); + map.put(Fields.TYPE.toString(), CpuServicesParameterSubFunctionGroup.ALARM_S_IND.getCode()); map.put(Fields.EVENT_ID.name(), message.getEventID()); map.put(Fields.EVENT_STATE.name(), message.getEventState()); map.put(Fields.ACKSTATE_GOING.name(), message.getAckStateGoing()); @@ -188,7 +187,7 @@ private static S7AlarmEvent createAlarmEvent(CpuServicesParameterSubFunctionGrou } break; case ALARM_ACK_IND:; - map.put(Fields.TYPE.toString(), CpuServicesParameterSubFunctionGroup.ALARM_S_IND.getCode()); + map.put(Fields.TYPE.toString(), CpuServicesParameterSubFunctionGroup.ALARM_ACK_IND.getCode()); map.put(Fields.TIMESTAMP.name(), msgItem.getTimestamp().toInstant(ZoneOffset.UTC)); map.put(Fields.EVENT_ID.name(), message.getEventID()); map.put(Fields.EVENT_STATE.name(), message.getEventState()); @@ -233,6 +232,28 @@ private static S7AlarmEvent createAlarmEvent(CpuServicesParameterSubFunctionGrou } } break; + case ALARM: { + map.put(Fields.TYPE.toString(), CpuServicesParameterSubFunctionGroup.ALARM.getCode()); + map.put(Fields.TIMESTAMP.name(), msgItem.getTimestamp().toInstant(ZoneOffset.UTC)); + map.put(Fields.EVENT_ID.name(), message.getEventID()); + map.put(Fields.EVENT_STATE.name(), message.getEventState()); + map.put(Fields.STATE.name(), message.getState()); + map.put(Fields.ACKSTATE_GOING.name(), message.getAckStateGoing()); + map.put(Fields.ACKSTATE_COMING.name(), message.getAckStateComming()); + for(int i = 0; i < message.getNumberOfValues(); i++){ + itemValue = message.getComingValues().get(i); + datos = new byte[itemValue.getLength()]; + map.put("SIG_"+ (i+1) +"_STATE", itemValue.getReturnCode().getCode()); + itemValue.getData().getBytes(0, datos); + map.put("SIG_"+ (i+1) +"_DATA", datos); + } + } + break; + case ALARM8: { + System.out.println("PROCESANDO ALARM 8"); + } + break; + } return new S7AlarmEvent(map); diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7CyclicValueEvent.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7CyclicValueEvent.java new file mode 100644 index 00000000000..a5a51d4c7a5 --- /dev/null +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/protocol/event/S7CyclicValueEvent.java @@ -0,0 +1,475 @@ +/* +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.protocol.event; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.Collection; +import java.util.Map; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.plc4x.java.api.messages.PlcReadRequest; +import org.apache.plc4x.java.api.messages.PlcSubscriptionEvent; +import org.apache.plc4x.java.api.model.PlcField; +import org.apache.plc4x.java.api.types.PlcResponseCode; +import org.apache.plc4x.java.s7.netty.model.payloads.items.AssociatedValueItem; +import static org.apache.plc4x.java.s7.utils.S7Helper.decodeResponseCode; + +/** + * + * @author cgarcia + */ +public class S7CyclicValueEvent implements PlcSubscriptionEvent { + + private final Map items; + private final Instant instant; + + public S7CyclicValueEvent(Map items) { + this.items = items; + this.instant = Instant.now(); + } + + @Override + public Instant getTimestamp() { + return instant; + } + + @Override + public PlcReadRequest getRequest() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getNumberOfValues(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Object getObject(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Object getObject(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllObjects(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBoolean(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBoolean(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Boolean getBoolean(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Boolean getBoolean(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllBooleans(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidByte(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidByte(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Byte getByte(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Byte getByte(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllBytes(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidShort(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidShort(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Short getShort(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Short getShort(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllShorts(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Integer getInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Integer getInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllIntegers(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBigInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBigInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BigInteger getBigInteger(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BigInteger getBigInteger(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllBigIntegers(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidLong(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidLong(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Long getLong(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Long getLong(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllLongs(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidFloat(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidFloat(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Float getFloat(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Float getFloat(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllFloats(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDouble(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDouble(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Double getDouble(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Double getDouble(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllDoubles(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBigDecimal(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidBigDecimal(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BigDecimal getBigDecimal(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public BigDecimal getBigDecimal(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllBigDecimals(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidString(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidString(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getString(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getString(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllStrings(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalTime getTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalTime getTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllTimes(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDate(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDate(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalDate getDate(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalDate getDate(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllDates(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDateTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDateTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalDateTime getDateTime(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public LocalDateTime getDateTime(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllDateTimes(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDuration(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidDuration(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Duration getDuration(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Duration getDuration(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllDuration(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidByteArray(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isValidByteArray(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Byte[] getByteArray(String name) { + byte[] bytes = new byte[items.get(name).getData().readableBytes()]; + items.get(name).getData().duplicate().readBytes(bytes); + return ArrayUtils.toObject(bytes); + } + + @Override + public Byte[] getByteArray(String name, int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getAllByteArrays(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Collection getFieldNames() { + return items.keySet(); + } + + @Override + public PlcField getField(String name) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public PlcResponseCode getResponseCode(String name) { + return decodeResponseCode(items.get(name).getReturnCode()); + } + +} diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7Helper.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7Helper.java index 7d5e80bdf7c..66fbf405c1f 100644 --- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7Helper.java +++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7Helper.java @@ -28,6 +28,8 @@ Licensed to the Apache Software Foundation (ASF) under one import java.time.temporal.ChronoUnit; import java.util.HashMap; import java.util.Map; +import org.apache.plc4x.java.api.types.PlcResponseCode; +import org.apache.plc4x.java.s7.netty.model.types.DataTransportErrorCode; /** * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ @@ -1334,4 +1336,24 @@ private static int byteBCDToInt(byte bcd){ return res; } + public static PlcResponseCode decodeResponseCode(DataTransportErrorCode dataTransportErrorCode) { + if (dataTransportErrorCode == null) { + return PlcResponseCode.INTERNAL_ERROR; + } + switch (dataTransportErrorCode) { + case OK: + return PlcResponseCode.OK; + case NOT_FOUND: + return PlcResponseCode.NOT_FOUND; + case INVALID_ADDRESS: + return PlcResponseCode.INVALID_ADDRESS; + case DATA_TYPE_NOT_SUPPORTED: + return PlcResponseCode.INVALID_DATATYPE; + case ACCESS_DENIED: + return PlcResponseCode.ACCESS_DENIED; + default: + return PlcResponseCode.INTERNAL_ERROR; + } + } + } From a64f0358384b63dd1cca9cf2b74c37d640b79450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Garc=C3=ADa?= Date: Mon, 4 May 2020 23:37:38 -0400 Subject: [PATCH 15/17] Some PR in Modbus driver for compatibility of S7 driver. --- .../connection/BaseModbusPlcConnection.java | 10 + .../connection/ModbusTcpPlcConnection.java | 2 +- .../SingleItemToSingleRequestProtocol.java | 19 +- .../DefaultModbusByteArrayFieldItem.java | 155 ++++++-- .../java/modbus/model/CoilModbusField.java | 7 +- .../plc4x/java/modbus/model/ModbusField.java | 7 +- .../model/ReadDiscreteInputsModbusField.java | 9 +- .../ReadHoldingRegistersModbusField.java | 7 +- .../model/ReadInputRegistersModbusField.java | 7 +- .../modbus/model/RegisterModbusField.java | 7 +- .../modbus/netty/Plc4XModbusProtocol.java | 45 ++- .../modbus/util/ModbusPlcFieldHandler.java | 334 +++++++++++++++++- .../modbus/netty/Plc4XModbusProtocolTest.java | 2 +- 13 files changed, 539 insertions(+), 72 deletions(-) diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/connection/BaseModbusPlcConnection.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/connection/BaseModbusPlcConnection.java index 713acd5cd91..bac1c3862ab 100644 --- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/connection/BaseModbusPlcConnection.java +++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/connection/BaseModbusPlcConnection.java @@ -36,6 +36,9 @@ public abstract class BaseModbusPlcConnection extends NettyPlcConnection impleme private static final Logger logger = LoggerFactory.getLogger(BaseModbusPlcConnection.class); + // This slaveId defaults to 0 which is a broadcast. + private short slaveId = 0; + BaseModbusPlcConnection(ChannelFactory channelFactory, String params) { super(channelFactory); @@ -46,6 +49,9 @@ public abstract class BaseModbusPlcConnection extends NettyPlcConnection impleme if (paramElements.length == 2) { String paramValue = paramElements[1]; switch (paramName) { + case "slaveId": { + slaveId = Short.parseShort(paramValue); + } default: logger.debug("Unknown parameter {} with value {}", paramName, paramValue); } @@ -104,4 +110,8 @@ public CompletableFuture write(PlcWriteRequest writeRequest) { .thenApply(PlcWriteResponse.class::cast); } + public short getSlaveId() { + return slaveId; + } + } diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/connection/ModbusTcpPlcConnection.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/connection/ModbusTcpPlcConnection.java index da2c99f6e23..3fb196b4597 100644 --- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/connection/ModbusTcpPlcConnection.java +++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/connection/ModbusTcpPlcConnection.java @@ -69,7 +69,7 @@ protected ChannelHandler getChannelHandler(CompletableFuture sessionSetupC @Override protected void initChannel(Channel channel) { channel.pipeline().addLast(new ModbusTcpCodec(new ModbusRequestEncoder(), new ModbusResponseDecoder())); - channel.pipeline().addLast(new Plc4XModbusProtocol()); + channel.pipeline().addLast(new Plc4XModbusProtocol(getSlaveId())); channel.pipeline().addLast(new SingleItemToSingleRequestProtocol(ModbusTcpPlcConnection.this, ModbusTcpPlcConnection.this, null, timer, null, false)); } }; diff --git a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/protocol/SingleItemToSingleRequestProtocol.java b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/protocol/SingleItemToSingleRequestProtocol.java index 69f7f646681..99c4781e0b0 100644 --- a/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/protocol/SingleItemToSingleRequestProtocol.java +++ b/plc4j/protocols/driver-bases/base/src/main/java/org/apache/plc4x/java/base/protocol/SingleItemToSingleRequestProtocol.java @@ -23,6 +23,11 @@ Licensed to the Apache Software Foundation (ASF) under one import io.netty.util.Timer; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.PromiseCombiner; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Collectors; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; import org.apache.plc4x.java.api.exceptions.PlcProtocolException; @@ -37,12 +42,6 @@ Licensed to the Apache Software Foundation (ASF) under one import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import java.util.stream.Collectors; - /** * This layer can be used to split a {@link org.apache.plc4x.java.api.messages.PlcRequest} which addresses multiple {@link PlcField}s into multiple subsequent {@link org.apache.plc4x.java.api.messages.PlcRequest}s. */ @@ -160,7 +159,7 @@ public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { public void channelInactive(ChannelHandlerContext ctx) throws Exception { // Send everything so we get a proper failure for those pending writes this.queue.removeAndWriteAll(); - this.timer.stop(); + //this.timer.stop(); this.scheduledTimeouts.clear(); this.sentButUnacknowledgedSubContainer.clear(); this.correlationToParentContainer.clear(); @@ -181,7 +180,7 @@ public void channelInactive(ChannelHandlerContext ctx) throws Exception { protected void tryFinish(Integer currentTdpu, InternalPlcResponse msg, CompletableFuture originalResponseFuture) { deliveredItems.incrementAndGet(); PlcRequestContainer subPlcRequestContainer = sentButUnacknowledgedSubContainer.remove(currentTdpu); - LOGGER.info("{} got acknowledged", subPlcRequestContainer); + LOGGER.debug("{} got acknowledged", subPlcRequestContainer); PlcRequestContainer originalPlcRequestContainer = correlationToParentContainer.remove(currentTdpu); if (originalPlcRequestContainer == null) { LOGGER.warn("Unrelated package received {}", msg); @@ -325,7 +324,9 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) ChannelPromise subPromise = new DefaultChannelPromise(promise.channel()); Integer tdpu = correlationIdGenerator.getAndIncrement(); - CompletableFuture correlatedCompletableFuture = new CompletableFuture<>() + CompletableFuture correlatedCompletableFuture = new CompletableFuture<>(); + // Important: don't chain to above as we want the above to be completed not the result of when complete + correlatedCompletableFuture .thenApply(InternalPlcResponse.class::cast) .whenComplete((internalPlcResponse, throwable) -> { if (throwable != null) { diff --git a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/messages/items/DefaultModbusByteArrayFieldItem.java b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/messages/items/DefaultModbusByteArrayFieldItem.java index 4b3002fdbe2..4f335c9f920 100644 --- a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/messages/items/DefaultModbusByteArrayFieldItem.java +++ b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/messages/items/DefaultModbusByteArrayFieldItem.java @@ -18,13 +18,14 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.modbus.messages.items; -import org.apache.commons.lang3.ArrayUtils; -import org.apache.plc4x.java.base.messages.items.DefaultByteArrayFieldItem; - -import java.nio.ByteBuffer; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import java.nio.ByteOrder; +import java.nio.charset.Charset; import java.util.Arrays; import java.util.stream.Stream; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.plc4x.java.base.messages.items.DefaultByteArrayFieldItem; /** * default implementation for DefaultByteArrayFieldItem for Usage within Modbus module @@ -40,11 +41,16 @@ public class DefaultModbusByteArrayFieldItem extends DefaultByteArrayFieldItem { private ByteOrder byteOrder; private Byte[] completeByteArray; + private byte[] backend; + + private ByteBuf byteBuf = null; public DefaultModbusByteArrayFieldItem(Byte[]... values) { super(values); this.byteOrder = DEFAULT_ENDIANNESS; this.completeByteArray = Arrays.stream(getValues()).flatMap(Stream::of).toArray(Byte[]::new); + this.backend = ArrayUtils.toPrimitive(completeByteArray); + byteBuf = Unpooled.wrappedBuffer(backend); } @Override @@ -60,17 +66,25 @@ public boolean isValidByteArray(int index) { @Override public Byte[] getByteArray(int index) { - return getValue(index); + return getByteArrayFromIndex(index); } @Override public boolean isValidShort(int index) { - return this.completeByteArray.length >= shortIndexToByteIndex(index) + SHORT_BYTES; + try{ + short b = byteBuf.getShort(index*Short.BYTES); + return true; + } catch(Exception ex){ + return false; + } } @Override public Short getShort(int index) { - return getShort(index, this.byteOrder); + if (!isValidShort(index)){ + return null; + } + return byteBuf.getShort(index*Short.BYTES); } /** @@ -84,10 +98,12 @@ public Short getShort(int index, ByteOrder byteOrder) { if (!isValidShort(index)) { return null; } - return ByteBuffer - .wrap(ArrayUtils.toPrimitive(getByteArrayFromIndex(shortIndexToByteIndex(index)))) - .order(byteOrder) - .getShort(); + if (byteOrder.equals(ByteOrder.LITTLE_ENDIAN)) { + return byteBuf.getShortLE(index*Short.BYTES); + } else { + return byteBuf.getShort(index*Short.BYTES); + } + } /** @@ -103,12 +119,20 @@ private static int shortIndexToByteIndex(int shortIndex) { @Override public boolean isValidInteger(int index) { - return this.completeByteArray.length >= intIndexToByteIndex(index) + INTEGER_BYTES; + try{ + int b = byteBuf.getInt(index*Integer.BYTES); + return true; + } catch(Exception ex){ + return false; + } } @Override public Integer getInteger(int index) { - return getInteger(index, this.byteOrder); + if (!isValidInteger(index)){ + return null; + } + return byteBuf.getInt(index*Integer.BYTES); } /** @@ -122,10 +146,11 @@ public Integer getInteger(int index, ByteOrder byteOrder) { if (!isValidInteger(index)) { return null; } - return ByteBuffer - .wrap(ArrayUtils.toPrimitive(getByteArrayFromIndex(intIndexToByteIndex(index)))) - .order(byteOrder) - .getInt(); + if (byteOrder.equals(ByteOrder.LITTLE_ENDIAN)) { + return byteBuf.getIntLE(index*Integer.BYTES); + } else { + return byteBuf.getInt(index*Integer.BYTES); + } } /** @@ -141,12 +166,20 @@ private static int intIndexToByteIndex(int intIndex) { @Override public boolean isValidLong(int index) { - return this.completeByteArray.length >= longIndexToByteIndex(index) + LONG_BYTES; + try{ + long b = byteBuf.getLong(index*Long.BYTES); + return true; + } catch(Exception ex){ + return false; + } } @Override public Long getLong(int index) { - return getLong(index, this.byteOrder); + if (!isValidLong(index)){ + return null; + } + return byteBuf.getLong(index*Long.BYTES); } /** @@ -160,10 +193,11 @@ public Long getLong(int index, ByteOrder byteOrder) { if (!isValidLong(index)) { return null; } - return ByteBuffer - .wrap(ArrayUtils.toPrimitive(getByteArrayFromIndex(longIndexToByteIndex(index)))) - .order(byteOrder) - .getLong(); + if (byteOrder.equals(ByteOrder.LITTLE_ENDIAN)) { + return byteBuf.getLongLE(index*Long.BYTES); + } else { + return byteBuf.getLong(index*Long.BYTES); + } } /** @@ -214,7 +248,80 @@ public int hashCode() { //ToDo: Implement conversion for Float and Unsigned-Datatypes - //ToDo: Add exceptions to avoid unwanted states --> e.g. neg indexes + @Override + public boolean isValidByte(int index) { + try{ + byte b = byteBuf.getByte(index); + return true; + } catch(Exception ex){ + return false; + } + } + + @Override + public Byte getByte(int index) { + if (!isValidByte(index)){ + return null; + } + return byteBuf.getByte(index); + } + + @Override + public boolean isValidFloat(int index) { + try{ + float f = byteBuf.getFloat(index*Float.BYTES); + return true; + } catch(Exception ex){ + return false; + } + } + + @Override + public Float getFloat(int index) { + if (!isValidFloat(index)){ + return null; + } + return byteBuf.getFloat(index*Float.BYTES); + } + + @Override + public boolean isValidDouble(int index) { + try{ + double f = byteBuf.getDouble(index*Double.BYTES); + return true; + } catch(Exception ex){ + return false; + } + } + @Override + public Double getDouble(int index) { + if (!isValidDouble(index)){ + return null; + } + return byteBuf.getDouble(index*Double.BYTES); + } + + //TODO: index or index*2? String is byte oriented. + @Override + public boolean isValidString(int index) { + try{ + CharSequence s = byteBuf.getCharSequence(index*2, byteBuf.readableBytes(), Charset.defaultCharset()); + return true; + } catch(Exception ex){ + return false; + } + } + + @Override + public String getString(int index) { + if (!isValidString(index)){ + return null; + } + CharSequence s = byteBuf.getCharSequence(index*2, byteBuf.readableBytes(), Charset.defaultCharset()); + return s.toString(); + } + + } diff --git a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/CoilModbusField.java b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/CoilModbusField.java index adb7600d5ee..48acc403893 100644 --- a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/CoilModbusField.java +++ b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/CoilModbusField.java @@ -18,10 +18,9 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.modbus.model; -import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; - import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; public class CoilModbusField extends ModbusField { @@ -40,6 +39,10 @@ public static CoilModbusField of(String addressString) throws PlcInvalidFieldExc String quantityString = matcher.group("quantity"); Integer quantity = quantityString != null ? Integer.valueOf(quantityString) : null; + if (quantity != null){ + if ((quantity < 0) || (quantity > 2000)) throw new PlcInvalidFieldException(addressString, ADDRESS_PATTERN); + } + return new CoilModbusField(address, quantity); } } diff --git a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ModbusField.java b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ModbusField.java index 3254e02bee3..c0d4eca0051 100644 --- a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ModbusField.java +++ b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ModbusField.java @@ -18,14 +18,13 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.modbus.model; -import org.apache.plc4x.java.api.model.PlcField; - import java.util.Objects; import java.util.regex.Pattern; +import org.apache.plc4x.java.api.model.PlcField; public abstract class ModbusField implements PlcField { - public static final Pattern ADDRESS_PATTERN = Pattern.compile("(?
\\d+)(\\[(?\\d)])?"); + public static final Pattern ADDRESS_PATTERN = Pattern.compile("(?
\\d+)(\\[(?\\d+?)])?"); private final int address; @@ -68,7 +67,7 @@ public int hashCode() { public String toString() { return "ModbusField{" + "address=" + address + - "quantity=" + quantity + + ",quantity=" + quantity + '}'; } } diff --git a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ReadDiscreteInputsModbusField.java b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ReadDiscreteInputsModbusField.java index 00cb49598ab..18ce8d54191 100644 --- a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ReadDiscreteInputsModbusField.java +++ b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ReadDiscreteInputsModbusField.java @@ -18,10 +18,9 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.modbus.model; -import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; - import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; public class ReadDiscreteInputsModbusField extends ModbusField { @@ -39,7 +38,11 @@ public static ReadDiscreteInputsModbusField of(String addressString) throws PlcI int address = Integer.parseInt(matcher.group("address")); String quantityString = matcher.group("quantity"); - Integer quantity = quantityString != null ? Integer.valueOf(quantityString) : null; + Integer quantity = quantityString != null ? Integer.valueOf(quantityString) : null; + if (quantity != null) { + if ((quantity < 0) || (quantity > 2000)) throw new PlcInvalidFieldException(addressString, ADDRESS_PATTERN); + } + return new ReadDiscreteInputsModbusField(address, quantity); } } diff --git a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ReadHoldingRegistersModbusField.java b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ReadHoldingRegistersModbusField.java index 9f51e1eb67a..b21f50fa83b 100644 --- a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ReadHoldingRegistersModbusField.java +++ b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ReadHoldingRegistersModbusField.java @@ -18,10 +18,9 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.modbus.model; -import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; - import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; public class ReadHoldingRegistersModbusField extends ModbusField { @@ -40,6 +39,10 @@ public static ReadHoldingRegistersModbusField of(String addressString) throws Pl String quantityString = matcher.group("quantity"); Integer quantity = quantityString != null ? Integer.valueOf(quantityString) : null; + if (quantity != null) { + if ((quantity < 0) || (quantity > 125)) throw new PlcInvalidFieldException(addressString, ADDRESS_PATTERN); + } + return new ReadHoldingRegistersModbusField(address, quantity); } } diff --git a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ReadInputRegistersModbusField.java b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ReadInputRegistersModbusField.java index 3b61343760d..53d7b7ccbae 100644 --- a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ReadInputRegistersModbusField.java +++ b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/ReadInputRegistersModbusField.java @@ -18,10 +18,9 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.modbus.model; -import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; - import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; public class ReadInputRegistersModbusField extends ModbusField { @@ -40,6 +39,10 @@ public static ReadInputRegistersModbusField of(String addressString) throws PlcI String quantityString = matcher.group("quantity"); Integer quantity = quantityString != null ? Integer.valueOf(quantityString) : null; + if (quantity != null) { + if ((quantity < 0) || (quantity > 125)) throw new PlcInvalidFieldException(addressString, ADDRESS_PATTERN); + } + return new ReadInputRegistersModbusField(address, quantity); } } diff --git a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/RegisterModbusField.java b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/RegisterModbusField.java index 06973641285..67eb0ba4692 100644 --- a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/RegisterModbusField.java +++ b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/model/RegisterModbusField.java @@ -18,10 +18,9 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.modbus.model; -import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; - import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; // TODO: Default to {@link ReadHoldingRegistersModbusField} public class RegisterModbusField extends ModbusField { @@ -41,6 +40,10 @@ public static RegisterModbusField of(String addressString) throws PlcInvalidFiel String quantityString = matcher.group("quantity"); Integer quantity = quantityString != null ? Integer.valueOf(quantityString) : null; + if (quantity != null){ + if ((quantity < 0) || (quantity > 125)) throw new PlcInvalidFieldException(addressString, ADDRESS_PATTERN); + } + return new RegisterModbusField(address, quantity); } } diff --git a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocol.java b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocol.java index 12be747bb8d..8ddd1647209 100644 --- a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocol.java +++ b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocol.java @@ -26,6 +26,11 @@ Licensed to the Apache Software Foundation (ASF) under one import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageCodec; +import java.math.BigInteger; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; @@ -45,12 +50,6 @@ Licensed to the Apache Software Foundation (ASF) under one import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.math.BigInteger; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicInteger; - public class Plc4XModbusProtocol extends MessageToMessageCodec> { @@ -60,6 +59,12 @@ public class Plc4XModbusProtocol extends MessageToMessageCodec> requestsMap = new ConcurrentHashMap<>(); + private final short slaveId; + + public Plc4XModbusProtocol(short slaveId) { + this.slaveId = slaveId; + } + @Override protected void encode(ChannelHandlerContext ctx, PlcRequestContainer msg, List out) throws Exception { LOGGER.trace("(<--OUT): {}, {}, {}", ctx, msg, out); @@ -89,8 +94,6 @@ private void encodeWriteRequest(PlcRequestContainer> 3) + 1; + // (8/8)+1 = 2, but must be 1; + int temp = quantity - 1; + int requiredLength = (temp >> 3) + 1; if (bytesToWrite.length != requiredLength) { throw new PlcProtocolException( "Invalid coil values created. Should be big enough to transport N bits. Was " + @@ -163,7 +168,7 @@ private void encodeWriteRequest(PlcRequestContainer msg, List out) throws PlcException { @@ -178,8 +183,6 @@ private void encodeReadRequest(PlcRequestContainer values) throws PlcProtocolException { private byte[] produceCoilValues(List values) throws PlcProtocolException { List coils = new LinkedList<>(); + int items = values.size(); byte actualCoil = 0; int i = 7; + for (Object value : values) { final boolean coilSet; if (value.getClass() == Boolean.class) { @@ -381,13 +386,17 @@ private byte[] produceCoilValues(List values) throws PlcProtocolException { throw new PlcUnsupportedDataTypeException(value.getClass()); } byte coilToSet = coilSet ? (byte) 1 : (byte) 0; - actualCoil = (byte) (actualCoil & 0xff | coilToSet << i); - i--; - if (i < 0) { + int pos = 7 - i; + actualCoil = (byte) (actualCoil & 0xff | coilToSet << pos); + items--; + i--; + if ((items!=0) && (i < 0)) { coils.add(actualCoil); actualCoil = 0; - i = 8; + i = 7; } + if (items==0) coils.add(actualCoil); + } if (coils.isEmpty()) { // We only have one coil @@ -523,4 +532,4 @@ private DefaultModbusByteArrayFieldItem produceRegisterValueList(ByteBuf byteBuf } return new DefaultModbusByteArrayFieldItem(data.toArray(new Byte[0][0])); } -} +} \ No newline at end of file diff --git a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/util/ModbusPlcFieldHandler.java b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/util/ModbusPlcFieldHandler.java index eaf3912a852..1edea540441 100644 --- a/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/util/ModbusPlcFieldHandler.java +++ b/plc4j/protocols/modbus/src/main/java/org/apache/plc4x/java/modbus/util/ModbusPlcFieldHandler.java @@ -18,6 +18,18 @@ Licensed to the Apache Software Foundation (ASF) under one */ package org.apache.plc4x.java.modbus.util; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.Duration; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneOffset; +import java.util.BitSet; +import java.util.LinkedList; +import java.util.List; import org.apache.commons.lang3.ArrayUtils; import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; import org.apache.plc4x.java.api.model.PlcField; @@ -27,10 +39,6 @@ Licensed to the Apache Software Foundation (ASF) under one import org.apache.plc4x.java.modbus.messages.items.DefaultModbusByteArrayFieldItem; import org.apache.plc4x.java.modbus.model.*; -import java.util.BitSet; -import java.util.LinkedList; -import java.util.List; - public class ModbusPlcFieldHandler extends DefaultPlcFieldHandler { @Override @@ -111,4 +119,322 @@ public BaseDefaultFieldItem encodeByteArray(PlcField field, Object[] values) { } return new DefaultModbusByteArrayFieldItem(byteArrays.toArray(new Byte[0][0])); } + + @Override + public BaseDefaultFieldItem encodeShort(PlcField field, Object[] values) { + int size = Short.BYTES; + ModbusField modbusField = (ModbusField) field; + List byteArrays = new LinkedList<>(); + byte[] backend = new byte[values.length * size]; + ByteBuf byteBuf = Unpooled.wrappedBuffer(backend); + byteBuf.clear(); + if ((modbusField.getQuantity()*2/size) == values.length) { + for (int i = 0; i < values.length; i++) { + if (values[i] instanceof Short){ + byteBuf.writeShort((Short) values[i]); + } + } + + BytesToRegisters(backend, byteArrays); + + return new DefaultModbusByteArrayFieldItem(byteArrays.toArray(new Byte[0][0])); + } else { + throw new IllegalArgumentException( + "Value of type " + values.getClass().getName() + + " is not assignable to " + modbusField + " fields."); + } + } + + @Override + public BaseDefaultFieldItem encodeLong(PlcField field, Object[] values) { + int size = Long.BYTES; + ModbusField modbusField = (ModbusField) field; + List byteArrays = new LinkedList<>(); + byte[] backend = new byte[values.length * size]; + ByteBuf byteBuf = Unpooled.wrappedBuffer(backend); + byteBuf.clear(); + if ((modbusField.getQuantity()*2/size) == values.length) { + for (int i = 0; i < values.length; i++) { + if (values[i] instanceof Long){ + byteBuf.writeLong((Long) values[i]); + } + } + + BytesToRegisters(backend, byteArrays); + + return new DefaultModbusByteArrayFieldItem(byteArrays.toArray(new Byte[0][0])); + } else { + throw new IllegalArgumentException( + "Value of type " + values.getClass().getName() + + " is not assignable to " + modbusField + " fields."); + } + } + + @Override + public BaseDefaultFieldItem encodeDouble(PlcField field, Object[] values) { + int size = Double.BYTES; + ModbusField modbusField = (ModbusField) field; + List byteArrays = new LinkedList<>(); + byte[] backend = new byte[values.length * size]; + ByteBuf byteBuf = Unpooled.wrappedBuffer(backend); + byteBuf.clear(); + if ((modbusField.getQuantity()*2/size) == values.length) { + for (int i = 0; i < values.length; i++) { + if (values[i] instanceof Double){ + byteBuf.writeDouble((Double) values[i]); + } + } + + BytesToRegisters(backend, byteArrays); + + return new DefaultModbusByteArrayFieldItem(byteArrays.toArray(new Byte[0][0])); + } else { + throw new IllegalArgumentException( + "Value of type " + values.getClass().getName() + + " is not assignable to " + modbusField + " fields."); + } + } + + @Override + public BaseDefaultFieldItem encodeInteger(PlcField field, Object[] values) { + int size = Integer.BYTES; + ModbusField modbusField = (ModbusField) field; + List byteArrays = new LinkedList<>(); + byte[] backend = new byte[values.length * size]; + ByteBuf byteBuf = Unpooled.wrappedBuffer(backend); + byteBuf.clear(); + if ((modbusField.getQuantity()*2/size) == values.length) { + for (int i = 0; i < values.length; i++) { + if (values[i] instanceof Integer){ + byteBuf.writeInt((Integer) values[i]); + } + } + + BytesToRegisters(backend, byteArrays); + + return new DefaultModbusByteArrayFieldItem(byteArrays.toArray(new Byte[0][0])); + } else { + throw new IllegalArgumentException( + "Value of type " + values.getClass().getName() + + " is not assignable to " + modbusField + " fields."); + } + } + + @Override + public BaseDefaultFieldItem encodeFloat(PlcField field, Object[] values) { + int size = Float.BYTES; + ModbusField modbusField = (ModbusField) field; + List byteArrays = new LinkedList<>(); + byte[] backend = new byte[values.length * size]; + ByteBuf byteBuf = Unpooled.wrappedBuffer(backend); + byteBuf.clear(); + if ((modbusField.getQuantity()*2/size) == values.length) { + for (int i = 0; i < values.length; i++) { + if (values[i] instanceof Float){ + byteBuf.writeFloat((Float) values[i]); + } + } + + BytesToRegisters(backend, byteArrays); + + return new DefaultModbusByteArrayFieldItem(byteArrays.toArray(new Byte[0][0])); + } else { + throw new IllegalArgumentException( + "Value of type " + values.getClass().getName() + + " is not assignable to " + modbusField + " fields."); + } + } + + @Override + public BaseDefaultFieldItem encodeDuration(PlcField field, Object[] values) { + int size = Long.BYTES; + ModbusField modbusField = (ModbusField) field; + List byteArrays = new LinkedList<>(); + byte[] backend = new byte[values.length * size]; + ByteBuf byteBuf = Unpooled.wrappedBuffer(backend); + byteBuf.clear(); + if ((modbusField.getQuantity()*2/size) == values.length) { + for (int i = 0; i < values.length; i++) { + if (values[i] instanceof Duration){ + byteBuf.writeLong(((Duration) values[i]).toNanos()); + } + } + + BytesToRegisters(backend, byteArrays); + + return new DefaultModbusByteArrayFieldItem(byteArrays.toArray(new Byte[0][0])); + } else { + throw new IllegalArgumentException( + "Value of type " + values.getClass().getName() + + " is not assignable to " + modbusField + " fields."); + } + } + + @Override + public BaseDefaultFieldItem encodeTime(PlcField field, Object[] values) { + int size = Long.BYTES; + ModbusField modbusField = (ModbusField) field; + List byteArrays = new LinkedList<>(); + byte[] backend = new byte[values.length * size]; + ByteBuf byteBuf = Unpooled.wrappedBuffer(backend); + byteBuf.clear(); + if ((modbusField.getQuantity()*2/size) == values.length) { + for (int i = 0; i < values.length; i++) { + if (values[i] instanceof LocalTime){ + byteBuf.writeLong(((LocalTime) values[i]).toNanoOfDay()); + } + } + + BytesToRegisters(backend, byteArrays); + + return new DefaultModbusByteArrayFieldItem(byteArrays.toArray(new Byte[0][0])); + } else { + throw new IllegalArgumentException( + "Value of type " + values.getClass().getName() + + " is not assignable to " + modbusField + " fields."); + } + } + + @Override + public BaseDefaultFieldItem encodeDate(PlcField field, Object[] values) { + int size = Long.BYTES; + ModbusField modbusField = (ModbusField) field; + List byteArrays = new LinkedList<>(); + byte[] backend = new byte[values.length * size]; + ByteBuf byteBuf = Unpooled.wrappedBuffer(backend); + byteBuf.clear(); + if ((modbusField.getQuantity()*2/size) == values.length) { + for (int i = 0; i < values.length; i++) { + if (values[i] instanceof LocalDate){ + byteBuf.writeLong(((LocalDate) values[i]).toEpochDay()); + } + } + + BytesToRegisters(backend, byteArrays); + + return new DefaultModbusByteArrayFieldItem(byteArrays.toArray(new Byte[0][0])); + } else { + throw new IllegalArgumentException( + "Value of type " + values.getClass().getName() + + " is not assignable to " + modbusField + " fields."); + } + } + + @Override + public BaseDefaultFieldItem encodeDateTime(PlcField field, Object[] values) { + int size = Long.BYTES; + ModbusField modbusField = (ModbusField) field; + List byteArrays = new LinkedList<>(); + byte[] backend = new byte[values.length * size]; + ByteBuf byteBuf = Unpooled.wrappedBuffer(backend); + byteBuf.clear(); + if ((modbusField.getQuantity()*2/size) == values.length) { + for (int i = 0; i < values.length; i++) { + if (values[i] instanceof LocalDateTime){ + byteBuf.writeLong(((LocalDateTime) values[i]).toEpochSecond(ZoneOffset.UTC)); + } + } + + BytesToRegisters(backend, byteArrays); + + return new DefaultModbusByteArrayFieldItem(byteArrays.toArray(new Byte[0][0])); + } else { + throw new IllegalArgumentException( + "Value of type " + values.getClass().getName() + + " is not assignable to " + modbusField + " fields."); + } + } + + @Override + public BaseDefaultFieldItem encodeBigDecimal(PlcField field, Object[] values) { + int size = 4; //BigInteger + ModbusField modbusField = (ModbusField) field; + List byteArrays = new LinkedList<>(); + byte[] backend = new byte[values.length * size]; + ByteBuf byteBuf = Unpooled.wrappedBuffer(backend); + byteBuf.clear(); + if ((modbusField.getQuantity()*2/size) == values.length) { + for (int i = 0; i < values.length; i++) { + if (values[i] instanceof BigDecimal){ + byteBuf.writeBytes(((BigDecimal) values[i]).toBigInteger().toByteArray()); + } + } + + BytesToRegisters(backend, byteArrays); + + return new DefaultModbusByteArrayFieldItem(byteArrays.toArray(new Byte[0][0])); + } else { + throw new IllegalArgumentException( + "Value of type " + values.getClass().getName() + + " is not assignable to " + modbusField + " fields."); + } + } + + @Override + public BaseDefaultFieldItem encodeBigInteger(PlcField field, Object[] values) { + int size = 4; //BigInteger + ModbusField modbusField = (ModbusField) field; + List byteArrays = new LinkedList<>(); + byte[] backend = new byte[values.length * size]; + ByteBuf byteBuf = Unpooled.wrappedBuffer(backend); + byteBuf.clear(); + if ((modbusField.getQuantity()*2/size) == values.length) { + for (int i = 0; i < values.length; i++) { + if (values[i] instanceof BigInteger){ + byteBuf.writeBytes(((BigInteger) values[i]).toByteArray()); + } + } + + BytesToRegisters(backend, byteArrays); + + return new DefaultModbusByteArrayFieldItem(byteArrays.toArray(new Byte[0][0])); + } else { + throw new IllegalArgumentException( + "Value of type " + values.getClass().getName() + + " is not assignable to " + modbusField + " fields."); + } + } + + @Override + public BaseDefaultFieldItem encodeString(PlcField field, Object[] values) { + int size = 0; //BigInteger + ModbusField modbusField = (ModbusField) field; + List byteArrays = new LinkedList<>(); + for (Object value:values) size+=((String) value).getBytes().length; + size+=((size % 2) == 0)?0:1; + byte[] backend = new byte[values.length * size]; + ByteBuf byteBuf = Unpooled.wrappedBuffer(backend); + byteBuf.clear(); + + if ((modbusField.getQuantity()*2) == values.length) { + for (int i = 0; i < values.length; i++) { + if (values[i] instanceof String){ + byteBuf.writeBytes(((String) values[i]).getBytes()); + } + } + if(byteBuf.readableBytes() registers){ + Byte[] tempBytes = null; + int quantity = (backend.length) / 2; + for (int j=0; j < quantity; j++){ + tempBytes = new Byte[2]; + tempBytes[0] = backend[(j*2)]; + tempBytes[1] = backend[((j*2+1))]; + registers.add(tempBytes); + } + } + + + + } diff --git a/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocolTest.java b/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocolTest.java index a746a23887d..30b37a23289 100644 --- a/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocolTest.java +++ b/plc4j/protocols/modbus/src/test/java/org/apache/plc4x/java/modbus/netty/Plc4XModbusProtocolTest.java @@ -158,7 +158,7 @@ private static byte[] cutRegister(byte[] right) { @Before public void setUp() { - SUT = new Plc4XModbusProtocol(); + SUT = new Plc4XModbusProtocol((short) 1); } @Test From 4b2ae76a5077cd59196e900cb159e32d68f3af89 Mon Sep 17 00:00:00 2001 From: Cesar Garcia Date: Sat, 12 Dec 2020 15:31:49 -0400 Subject: [PATCH 16/17] Prueba --- .dockerignore | 40 +- .editorconfig | 62 +- .gitignore | 338 +- .gitlab-ci.yml | 96 +- .mvn/extensions.xml | 54 +- .mvn/wrapper/MavenWrapperDownloader.java | 234 +- .mvn/wrapper/maven-wrapper.properties | 38 +- .travis.yml | 60 +- DEVELOPMENT.md | 98 +- Dockerfile | 228 +- Jenkinsfile | 618 +-- LICENSE | 444 +- NOTICE | 26 +- README.md | 560 +- RELEASE_NOTES | 472 +- Sometimes-Failling-Tests.md | 64 +- build-reproducible.sh | 136 +- build-utils/language-base-freemarker/pom.xml | 110 +- .../freemarker/FreemarkerLanguageOutput.java | 258 +- .../FreemarkerLanguageTemplateHelper.java | 46 +- build-utils/language-java/pom.xml | 114 +- .../language/java/JavaLanguageOutput.java | 114 +- .../java/JavaLanguageTemplateHelper.java | 1300 ++--- ...gins.codegenerator.language.LanguageOutput | 38 +- .../templates/java/enum-template.ftlh | 196 +- .../resources/templates/java/io-template.ftlh | 862 +-- .../templates/java/pojo-template.ftlh | 416 +- build-utils/pom.xml | 86 +- build-utils/protocol-base-mspec/pom.xml | 136 +- .../codegenerator/language/mspec/MSpec.g4 | 456 +- .../language/mspec/expression/Expression.g4 | 222 +- .../expression/ExpressionStringListener.java | 696 +-- .../expression/ExpressionStringParser.java | 96 +- .../DefaultComplexTypeDefinition.java | 184 +- ...ultDiscriminatedComplexTypeDefinition.java | 100 +- .../DefaultEnumTypeDefinition.java | 138 +- .../model/definitions/DefaultEnumValue.java | 106 +- .../definitions/DefaultTypeDefinition.java | 120 +- .../mspec/model/fields/DefaultArrayField.java | 128 +- .../model/fields/DefaultChecksumField.java | 110 +- .../mspec/model/fields/DefaultConstField.java | 110 +- .../fields/DefaultDiscriminatorField.java | 98 +- .../mspec/model/fields/DefaultEnumField.java | 102 +- .../model/fields/DefaultImplicitField.java | 110 +- .../model/fields/DefaultManualArrayField.java | 164 +- .../model/fields/DefaultManualField.java | 138 +- .../model/fields/DefaultOptionalField.java | 114 +- .../model/fields/DefaultPaddingField.java | 126 +- .../model/fields/DefaultReservedField.java | 98 +- .../model/fields/DefaultSimpleField.java | 102 +- .../model/fields/DefaultSwitchField.java | 112 +- .../model/fields/DefaultTaggedField.java | 72 +- .../model/fields/DefaultVirtualField.java | 110 +- .../DefaultComplexTypeReference.java | 74 +- .../DefaultSimpleTypeReference.java | 88 +- .../DefaultSimpleVarLengthTypeReference.java | 60 +- .../mspec/parser/MessageFormatListener.java | 938 ++-- .../mspec/parser/MessageFormatParser.java | 100 +- .../src/remote-resources/LICENSE | 6 +- .../src/remote-resources/UNLICENSE | 46 +- build-utils/protocol-test/pom.xml | 170 +- .../plc4x/protocol/test/TestProtocol.java | 90 +- ...4x.plugins.codegenerator.protocol.Protocol | 36 +- .../main/resources/protocols/test/test.mspec | 140 +- .../src/site/asciidoc/index.adoc | 236 +- build-utils/protocol-test/src/site/site.xml | 288 +- compare-reproducible.sh | 82 +- jenkins.pom | 176 +- licenses/UNLICENSE | 46 +- media/logos/SVG/PLC4X logo without mascot.svg | 116 +- media/logos/SVG/logo PLC4X black line.svg | 3194 +++++------ .../logos/SVG/logo PLC4X color CMYK@300x.svg | 2982 +++++----- media/logos/SVG/logo PLC4X on dark bg.svg | 2982 +++++----- media/logos/SVG/logo PLC4X white line.svg | 3194 +++++------ .../SVG/mascot color with apache feather.svg | 4922 ++++++++-------- .../SVG/mascot color without feather.svg | 2804 +++++----- mvnw | 610 +- mvnw.cmd | 342 +- plc4j/api/pom.xml | 96 +- .../apache/plc4x/java/PlcDriverManager.java | 212 +- .../apache/plc4x/java/api/PlcConnection.java | 210 +- .../api/authentication/PlcAuthentication.java | 44 +- .../PlcUsernamePasswordAuthentication.java | 138 +- .../exceptions/PlcConnectionException.java | 80 +- .../java/api/exceptions/PlcException.java | 88 +- .../exceptions/PlcFieldRangeException.java | 56 +- .../PlcIncompatibleDatatypeException.java | 56 +- .../exceptions/PlcInvalidFieldException.java | 100 +- .../java/api/exceptions/PlcIoException.java | 86 +- .../PlcNotImplementedException.java | 60 +- .../api/exceptions/PlcProtocolException.java | 90 +- .../PlcProtocolPayloadTooBigException.java | 106 +- .../api/exceptions/PlcRuntimeException.java | 88 +- .../api/exceptions/PlcTimeoutException.java | 92 +- .../PlcUnsupportedDataTypeException.java | 92 +- .../PlcUnsupportedOperationException.java | 54 +- .../PlcUnsupportedProtocolException.java | 72 +- .../java/api/messages/PlcFieldRequest.java | 80 +- .../java/api/messages/PlcFieldResponse.java | 82 +- .../plc4x/java/api/messages/PlcMessage.java | 52 +- .../java/api/messages/PlcReadRequest.java | 82 +- .../java/api/messages/PlcReadResponse.java | 390 +- .../plc4x/java/api/messages/PlcRequest.java | 56 +- .../java/api/messages/PlcRequestBuilder.java | 46 +- .../plc4x/java/api/messages/PlcResponse.java | 54 +- .../api/messages/PlcSubscriptionEvent.java | 56 +- .../api/messages/PlcSubscriptionRequest.java | 134 +- .../api/messages/PlcSubscriptionResponse.java | 68 +- .../messages/PlcUnsubscriptionRequest.java | 98 +- .../messages/PlcUnsubscriptionResponse.java | 52 +- .../java/api/messages/PlcWriteRequest.java | 152 +- .../java/api/messages/PlcWriteResponse.java | 52 +- .../api/metadata/PlcConnectionMetadata.java | 84 +- .../api/model/PlcConsumerRegistration.java | 48 +- .../apache/plc4x/java/api/model/PlcField.java | 102 +- .../java/api/model/PlcSubscriptionHandle.java | 74 +- .../java/api/types/PlcClientDatatype.java | 70 +- .../plc4x/java/api/types/PlcResponseCode.java | 62 +- .../java/api/types/PlcSubscriptionType.java | 84 +- .../org/apache/plc4x/java/spi/PlcDriver.java | 122 +- plc4j/api/src/site/asciidoc/design.adoc | 102 +- .../plc4x/java/PlcDriverManagerTest.java | 234 +- ...PlcUsernamePasswordAuthenticationTest.java | 116 +- .../java/api/connection/PlcReaderTest.java | 116 +- .../java/api/connection/PlcWriterTest.java | 72 +- .../PlcConnectionExceptionTest.java | 110 +- .../java/api/exceptions/PlcExceptionTest.java | 110 +- .../PlcFieldRangeExceptionTest.java | 70 +- .../PlcIncompatibleDatatypeExceptionTest.java | 68 +- .../PlcInvalidFieldExceptionTest.java | 116 +- .../api/exceptions/PlcIoExceptionTest.java | 110 +- .../PlcNotImplementedExceptionTest.java | 68 +- .../exceptions/PlcProtocolExceptionTest.java | 110 +- ...PlcProtocolPayloadTooBigExceptionTest.java | 82 +- .../exceptions/PlcRuntimeExceptionTest.java | 110 +- .../exceptions/PlcTimeoutExceptionTest.java | 76 +- .../PlcUnsupportedDataTypeExceptionTest.java | 124 +- .../PlcUnsupportedOperationExceptionTest.java | 68 +- .../java/api/messages/APIMessageTests.java | 536 +- .../messages/PlcProprietaryRequestTest.java | 88 +- .../messages/PlcProprietaryResponseTest.java | 108 +- .../java/api/messages/PlcReadRequestTest.java | 216 +- .../api/messages/PlcReadResponseTest.java | 84 +- .../java/api/messages/PlcRequestTest.java | 212 +- .../java/api/messages/PlcResponseTest.java | 180 +- .../messages/PlcSubscriptionEventTest.java | 116 +- .../messages/PlcSubscriptionRequestTest.java | 58 +- .../messages/PlcSubscriptionResponseTest.java | 76 +- .../PlcUnsubscriptionRequestTest.java | 150 +- .../PlcUnsubscriptionResponseTest.java | 58 +- .../api/messages/PlcWriteRequestTest.java | 224 +- .../api/messages/PlcWriteResponseTest.java | 94 +- .../java/api/messages/mock/MockField.java | 104 +- .../specific/TypeSafePlcReadRequestTest.java | 152 +- .../specific/TypeSafePlcReadResponseTest.java | 164 +- .../specific/TypeSafePlcWriteRequestTest.java | 152 +- .../TypeSafePlcWriteResponseTest.java | 134 +- .../java/api/types/PlcClientDatatypeTest.java | 90 +- .../java/api/types/PlcResponseCodeTest.java | 76 +- .../api/types/PlcSubscriptionTypeTest.java | 70 +- .../plc4x/java/mock/DuplicateMockDriver.java | 46 +- .../apache/plc4x/java/mock/MockDriver.java | 110 +- .../plc4x/java/mock/MockPlcConnection.java | 58 +- .../org.apache.plc4x.java.spi.PlcDriver | 38 +- .../org.apache.plc4x.java.spi.PlcDriver | 38 +- plc4j/drivers/ab-eth/pom.xml | 264 +- .../apache/plc4x/java/abeth/AbEthDriver.java | 144 +- .../abeth/connection/AbEthFieldHandler.java | 72 +- .../abeth/connection/AbEthPlcConnection.java | 316 +- .../plc4x/java/abeth/model/AbEthField.java | 210 +- .../java/abeth/model/types/FileType.java | 130 +- .../java/abeth/protocol/AbEthProtocol.java | 122 +- .../abeth/protocol/Plc4xAbEthProtocol.java | 502 +- .../org.apache.plc4x.java.spi.PlcDriver | 38 +- .../plc4x/protocol/abeth/AbEthTest.java | 60 +- .../resources/testsuite/AbEthTestsuite.xml | 322 +- plc4j/drivers/ads/pom.xml | 216 +- .../apache/plc4x/java/ads/AdsPlcDriver.java | 216 +- .../connection/AdsAbstractPlcConnection.java | 498 +- .../ads/connection/AdsConnectionFactory.java | 116 +- .../connection/AdsSerialPlcConnection.java | 140 +- .../ads/connection/AdsTcpPlcConnection.java | 750 +-- .../org.apache.plc4x.java.spi.PlcDriver | 38 +- .../plc4x/java/ads/AdsPlcDriverTest.java | 328 +- .../adslib/ADSClientNotificationExample.java | 566 +- .../apache/plc4x/java/ads/adslib/AdsLib.java | 1130 ++-- .../plc4x/java/ads/adslib/AmsRequest.java | 102 +- .../plc4x/java/ads/adslib/AmsRouter.java | 768 +-- .../apache/plc4x/java/ads/adslib/Output.java | 76 +- .../plc4x/java/ads/adslib/package-info.java | 46 +- .../AdsAbstractPlcConnectionTest.java | 698 +-- .../connection/AdsConnectionFactoryTest.java | 328 +- .../AdsSerialPlcConnectionTest.java | 484 +- .../connection/AdsTcpPlcConnectionTests.java | 380 +- plc4j/drivers/ethernet-ip/pom.xml | 236 +- .../java/ethernetip/EtherNetIpPlcDriver.java | 166 +- .../BaseEtherNetIpPlcConnection.java | 214 +- .../EtherNetIpTcpPlcConnection.java | 168 +- .../org.apache.plc4x.java.spi.PlcDriver | 38 +- .../plc4x/java/ethernetip/EnipTest.java | 130 +- .../ethernetip/ManualPlc4XEtherNetIpTest.java | 110 +- plc4j/drivers/modbus/pom.xml | 200 +- .../plc4x/java/modbus/ModbusPlcDriver.java | 190 +- .../connection/BaseModbusPlcConnection.java | 234 +- .../connection/ModbusConnectionFactory.java | 80 +- .../connection/ModbusSerialPlcConnection.java | 94 +- .../connection/ModbusTcpPlcConnection.java | 162 +- .../org.apache.plc4x.java.spi.PlcDriver | 38 +- .../java/modbus/ModbusPlcDriverTest.java | 250 +- .../BaseModbusPlcConnectionTest.java | 310 +- .../ModbusConnectionFactoryTest.java | 188 +- .../ModbusSerialPlcConnectionTest.java | 432 +- .../ModbusTcpPlcConnectionTests.java | 118 +- plc4j/drivers/opcua/pom.xml | 182 +- .../plc4x/java/opcua/OpcuaPlcDriver.java | 192 +- .../connection/BaseOpcuaPlcConnection.java | 190 +- .../connection/OpcuaConnectionFactory.java | 78 +- .../connection/OpcuaTcpPlcConnection.java | 928 ++-- .../plc4x/java/opcua/protocol/OpcuaField.java | 236 +- .../opcua/protocol/OpcuaPlcFieldHandler.java | 302 +- .../protocol/OpcuaSubsriptionHandle.java | 164 +- .../opcua/protocol/model/OpcuaDataTypes.java | 92 +- .../protocol/model/OpcuaIdentifierType.java | 98 +- .../org.apache.plc4x.java.spi.PlcDriver | 38 +- .../plc4x/java/opcua/ManualPLC4XOpcua.java | 290 +- .../plc4x/java/opcua/OpcuaPlcDriverTest.java | 134 +- .../apache/plc4x/java/opcua/UtilsTest.java | 80 +- .../connection/OpcuaTcpPlcConnectionTest.java | 72 +- .../java/opcua/protocol/OpcuaFieldTest.java | 102 +- .../protocol/OpcuaPlcFieldHandlerTest.java | 72 +- .../protocol/OpcuaSubscriptionHandleTest.java | 72 +- plc4j/drivers/pom.xml | 90 +- plc4j/drivers/s7/README.md | 64 +- plc4j/drivers/s7/pom.xml | 284 +- .../org/apache/plc4x/java/s7/S7PlcDriver.java | 198 +- .../java/s7/connection/S7PlcConnection.java | 1381 ++--- .../org.apache.plc4x.java.spi.PlcDriver | 38 +- .../org/apache/plc4x/java/s7/BenchmarkS7.java | 180 +- .../apache/plc4x/java/s7/S7PlcDriverTest.java | 162 +- .../java/s7/connection/S7PlcConnectionIT.java | 274 +- .../s7/connection/S7PlcConnectionTests.java | 184 +- .../s7/connection/S7PlcTestConnection.java | 406 +- .../s7/connection/issues/PLC4X47Test.java | 102 +- plc4j/drivers/simulated/pom.xml | 134 +- .../java/simulated/SimulatedPlcDriver.java | 130 +- .../connection/SimulatedPlcConnection.java | 438 +- .../java/simulated/connection/TestDevice.java | 398 +- .../java/simulated/connection/TestField.java | 256 +- .../connection/TestFieldHandler.java | 348 +- .../simulated/connection/TestFieldItem.java | 70 +- .../java/simulated/connection/TestType.java | 56 +- .../org.apache.plc4x.java.spi.PlcDriver | 76 +- .../simulated/SimulatedPlcDriverTest.java | 112 +- .../SimulatedPlcConnectionTest.java | 488 +- .../simulated/connection/TestDeviceTest.java | 112 +- .../connection/TestFieldHandlerTest.java | 264 +- .../connection/TestFieldItemTest.java | 60 +- .../simulated/connection/TestFieldTest.java | 122 +- plc4j/examples/dummy-driver/pom.xml | 190 +- .../examples/dummydriver/DummyDriver.java | 134 +- .../connection/DummyConnection.java | 156 +- .../dummydriver/model/DummyField.java | 70 +- .../dummydriver/netty/DummyProtocol.java | 150 +- .../org.apache.plc4x.java.spi.PlcDriver | 38 +- plc4j/examples/hello-cloud-azure/pom.xml | 288 +- .../java/examples/cloud/azure/CliOptions.java | 198 +- .../cloud/azure/S7PlcToAzureIoTHubSample.java | 172 +- plc4j/examples/hello-cloud-google/README.md | 122 +- plc4j/examples/hello-cloud-google/pom.xml | 298 +- .../examples/cloud/google/CliOptions.java | 442 +- .../google/S7PlcToGoogleIoTCoreSample.java | 572 +- .../src/main/resources/logback.xml | 78 +- .../kafka-connector.yml | 68 +- .../examples/hello-connectivity-kafka/pom.xml | 400 +- .../hello-connectivity-kafka/server.sh | 62 +- .../connectivity/kafka/KafkaConnector.java | 270 +- .../kafka/model/Configuration.java | 112 +- .../connectivity/kafka/model/KafkaConfig.java | 114 +- .../connectivity/kafka/model/PlcConfig.java | 114 +- .../kafka/model/PlcFieldConfig.java | 138 +- .../kafka/model/PlcMemoryBlock.java | 82 +- .../src/main/resources/logback.xml | 70 +- .../mqtt-connector.yml | 70 +- .../examples/hello-connectivity-mqtt/pom.xml | 306 +- .../connectivity/mqtt/MqttConnector.java | 308 +- .../mqtt/model/Configuration.java | 112 +- .../connectivity/mqtt/model/MqttConfig.java | 112 +- .../connectivity/mqtt/model/PlcConfig.java | 114 +- .../mqtt/model/PlcFieldConfig.java | 138 +- .../mqtt/model/PlcMemoryBlock.java | 82 +- .../src/main/resources/logback.xml | 70 +- .../examples/hello-integration-edgent/pom.xml | 256 +- .../integration/edgent/CliOptions.java | 198 +- .../integration/edgent/PlcLogger.java | 118 +- .../src/main/resources/logback.xml | 70 +- .../examples/hello-integration-iotdb/pom.xml | 270 +- .../integration/iotdb/CliOptions.java | 376 +- .../examples/integration/iotdb/PlcLogger.java | 278 +- .../src/main/resources/logback.xml | 70 +- plc4j/examples/hello-opm/pom.xml | 244 +- .../java/examples/helloopm/HelloOpm.java | 216 +- .../hello-opm/src/main/resources/logback.xml | 70 +- .../hello-storage-elasticsearch/README.adoc | 132 +- .../hello-storage-elasticsearch/pom.xml | 384 +- .../storage/elasticsearch/CliOptions.java | 162 +- .../elasticsearch/ElasticsearchStorage.java | 534 +- .../src/main/resources/log4j2.xml | 68 +- .../src/main/resources/logback.xml | 78 +- plc4j/examples/hello-webapp/client/pom.xml | 272 +- .../client/src/main/royale/HelloPLC4X.mxml | 208 +- .../src/main/royale/service/RobotService.as | 182 +- plc4j/examples/hello-webapp/pom.xml | 174 +- plc4j/examples/hello-webapp/service/pom.xml | 222 +- .../robot/controllers/RobotController.java | 210 +- plc4j/examples/hello-webapp/webapp/pom.xml | 282 +- .../plc4x/examples/robot/Application.java | 64 +- .../src/main/resources/application.properties | 50 +- plc4j/examples/hello-world-plc4x/pom.xml | 258 +- .../java/examples/helloplc4x/CliOptions.java | 168 +- .../java/examples/helloplc4x/HelloPlc4x.java | 228 +- .../src/main/resources/logback.xml | 70 +- plc4j/examples/pom.xml | 238 +- plc4j/integrations/apache-calcite/pom.xml | 192 +- .../java/org/apache/plc4x/Plc4xBaseTable.java | 396 +- .../java/org/apache/plc4x/Plc4xSchema.java | 210 +- .../org/apache/plc4x/Plc4xSchemaFactory.java | 138 +- .../org/apache/plc4x/Plc4xStreamTable.java | 90 +- .../java/org/apache/plc4x/Plc4xTable.java | 78 +- .../org/apache/plc4x/DriverManagerTest.java | 176 +- .../org/apache/plc4x/Plc4XBaseTableTest.java | 102 +- .../apache/plc4x/Plc4xSchemaFactoryTest.java | 68 +- .../src/test/resources/example.yml | 62 +- .../src/test/resources/logback.xml | 74 +- .../src/test/resources/model.json | 78 +- plc4j/integrations/apache-camel/pom.xml | 362 +- .../apache-camel/src/main/docs/PLC4X.adoc | 42 +- .../org/apache/plc4x/camel/Constants.java | 58 +- .../apache/plc4x/camel/Plc4XComponent.java | 78 +- .../org/apache/plc4x/camel/Plc4XConsumer.java | 250 +- .../org/apache/plc4x/camel/Plc4XEndpoint.java | 272 +- .../plc4x/camel/Plc4XPollingConsumer.java | 270 +- .../org/apache/plc4x/camel/Plc4XProducer.java | 220 +- .../services/org/apache/camel/component/plc4x | 36 +- .../org/apache/plc4x/camel/ConstantsTest.java | 72 +- .../org/apache/plc4x/camel/ManualTest.java | 162 +- .../org/apache/plc4x/camel/MockDriver.java | 206 +- .../plc4x/camel/Plc4XComponentTest.java | 130 +- .../apache/plc4x/camel/Plc4XConsumerTest.java | 104 +- .../apache/plc4x/camel/Plc4XEndpointTest.java | 110 +- .../plc4x/camel/Plc4XPollingConsumerTest.java | 128 +- .../apache/plc4x/camel/Plc4XProducerTest.java | 228 +- .../org.apache.plc4x.java.spi.PlcDriver | 36 +- .../src/test/resources/log4j2.properties | 48 +- .../src/test/resources/logback.xml | 74 +- plc4j/integrations/apache-edgent/pom.xml | 162 +- .../plc4x/edgent/PlcConnectionAdapter.java | 744 +-- .../org/apache/plc4x/edgent/PlcFunctions.java | 658 +-- .../org/apache/plc4x/edgent/package-info.java | 48 +- .../edgent/PlcConnectionAdapterTest.java | 1104 ++-- .../apache/plc4x/edgent/PlcFunctionsTest.java | 288 +- .../plc4x/edgent/mock/MockConnection.java | 310 +- .../apache/plc4x/edgent/mock/MockDriver.java | 96 +- .../apache/plc4x/edgent/mock/MockField.java | 124 +- .../plc4x/edgent/mock/MockFieldHandler.java | 208 +- .../plc4x/edgent/mock/MockFieldItem.java | 68 +- .../org.apache.plc4x.java.spi.PlcDriver | 38 +- plc4j/integrations/apache-kafka/README.md | 194 +- .../config/plc4x-source.properties | 100 +- plc4j/integrations/apache-kafka/pom.xml | 302 +- .../plc4x/kafka/Plc4xSourceConnector.java | 552 +- .../apache/plc4x/kafka/Plc4xSourceTask.java | 562 +- .../apache/plc4x/kafka/config/Defaults.java | 66 +- .../org/apache/plc4x/kafka/config/Job.java | 96 +- .../plc4x/kafka/config/JobReference.java | 78 +- .../org/apache/plc4x/kafka/config/Source.java | 90 +- .../plc4x/kafka/config/SourceConfig.java | 214 +- .../exceptions/ConfigurationException.java | 62 +- .../apache/plc4x/kafka/util/VersionUtil.java | 64 +- .../plc4x/kafka/config/SourceConfigTest.java | 164 +- .../nifi-plc4x-nar/false-positives.xml | 54 +- .../apache-nifi/nifi-plc4x-nar/pom.xml | 208 +- .../apache-nifi/nifi-plc4x-processors/pom.xml | 94 +- .../apache/plc4x/nifi/BasePlc4xProcessor.java | 314 +- .../apache/plc4x/nifi/Plc4xSinkProcessor.java | 162 +- .../plc4x/nifi/Plc4xSourceProcessor.java | 158 +- .../org.apache.nifi.processor.Processor | 32 +- .../plc4x4nifi/Plc4xSinkProcessorTest.java | 80 +- .../plc4x4nifi/Plc4xSourceProcessorTest.java | 84 +- plc4j/integrations/apache-nifi/pom.xml | 232 +- plc4j/integrations/logstash-plugin/README.md | 138 +- plc4j/integrations/logstash-plugin/pom.xml | 552 +- .../src/gem/lib/logstash-input-plc4x_jars.rb | 42 +- .../src/gem/lib/logstash/inputs/plc4x.rb | 58 +- .../src/gem/logstash-input-plc4x.gemspec | 82 +- .../java/org/apache/plc4x/logstash/Plc4x.java | 340 +- .../apache/plc4x/logstash/Plc4xInputTest.java | 150 +- plc4j/integrations/pom.xml | 102 +- plc4j/karaf-features/README.md | 82 +- plc4j/karaf-features/karaf-itest/pom.xml | 374 +- .../org/apache/plc4x/karaf/FeatureIT.java | 198 +- .../resources/etc/org.ops4j.pax.logging.cfg | 140 +- plc4j/karaf-features/pom.xml | 172 +- plc4j/karaf-features/s7/pom.xml | 202 +- .../s7/src/main/feature/feature.xml | 96 +- .../org/apache/plc4x/karaf/FeatureTest.java | 182 +- plc4j/pom.xml | 690 +-- plc4j/protocols/ads/LINKS.md | 38 +- plc4j/protocols/ads/pom.xml | 220 +- .../ads/api/commands/AdsAbstractRequest.java | 80 +- .../ads/api/commands/AdsAbstractResponse.java | 80 +- .../AdsAddDeviceNotificationRequest.java | 388 +- .../AdsAddDeviceNotificationResponse.java | 226 +- .../java/ads/api/commands/AdsCommandType.java | 72 +- .../AdsDeleteDeviceNotificationRequest.java | 192 +- .../AdsDeleteDeviceNotificationResponse.java | 192 +- .../AdsDeviceNotificationRequest.java | 294 +- .../AdsDeviceNotificationResponse.java | 80 +- .../commands/AdsReadDeviceInfoRequest.java | 114 +- .../commands/AdsReadDeviceInfoResponse.java | 304 +- .../java/ads/api/commands/AdsReadRequest.java | 258 +- .../ads/api/commands/AdsReadResponse.java | 274 +- .../ads/api/commands/AdsReadStateRequest.java | 114 +- .../api/commands/AdsReadStateResponse.java | 246 +- .../ads/api/commands/AdsReadWriteRequest.java | 320 +- .../api/commands/AdsReadWriteResponse.java | 266 +- .../api/commands/AdsWriteControlRequest.java | 298 +- .../api/commands/AdsWriteControlResponse.java | 190 +- .../ads/api/commands/AdsWriteRequest.java | 296 +- .../ads/api/commands/AdsWriteResponse.java | 192 +- .../java/ads/api/commands/UnknownCommand.java | 176 +- .../java/ads/api/commands/package-info.java | 42 +- .../commands/types/AdsNotificationSample.java | 232 +- .../ads/api/commands/types/AdsReturnCode.java | 474 +- .../api/commands/types/AdsStampHeader.java | 226 +- .../java/ads/api/commands/types/AdsState.java | 170 +- .../ads/api/commands/types/CycleTime.java | 118 +- .../java/ads/api/commands/types/Data.java | 124 +- .../java/ads/api/commands/types/Device.java | 170 +- .../ads/api/commands/types/DeviceState.java | 118 +- .../ads/api/commands/types/IndexGroup.java | 246 +- .../ads/api/commands/types/IndexOffset.java | 146 +- .../java/ads/api/commands/types/Length.java | 130 +- .../ads/api/commands/types/MajorVersion.java | 136 +- .../java/ads/api/commands/types/MaxDelay.java | 118 +- .../ads/api/commands/types/MinorVersion.java | 138 +- .../commands/types/NotificationHandle.java | 118 +- .../ads/api/commands/types/ReadLength.java | 118 +- .../java/ads/api/commands/types/Result.java | 148 +- .../ads/api/commands/types/SampleSize.java | 130 +- .../java/ads/api/commands/types/Samples.java | 120 +- .../java/ads/api/commands/types/Stamps.java | 118 +- .../ads/api/commands/types/TimeStamp.java | 344 +- .../api/commands/types/TransmissionMode.java | 154 +- .../java/ads/api/commands/types/Version.java | 120 +- .../ads/api/commands/types/WriteLength.java | 128 +- .../ads/api/commands/types/package-info.java | 42 +- .../plc4x/java/ads/api/generic/AdsData.java | 64 +- .../plc4x/java/ads/api/generic/AmsHeader.java | 450 +- .../plc4x/java/ads/api/generic/AmsPacket.java | 184 +- .../java/ads/api/generic/package-info.java | 42 +- .../java/ads/api/generic/types/AmsError.java | 146 +- .../java/ads/api/generic/types/AmsNetId.java | 180 +- .../java/ads/api/generic/types/AmsPort.java | 264 +- .../java/ads/api/generic/types/Command.java | 252 +- .../ads/api/generic/types/DataLength.java | 128 +- .../java/ads/api/generic/types/Invoke.java | 122 +- .../java/ads/api/generic/types/State.java | 406 +- .../ads/api/generic/types/package-info.java | 42 +- .../plc4x/java/ads/api/package-info.java | 44 +- .../api/serial/AmsSerialAcknowledgeFrame.java | 346 +- .../java/ads/api/serial/AmsSerialFrame.java | 398 +- .../ads/api/serial/AmsSerialResetFrame.java | 370 +- .../java/ads/api/serial/package-info.java | 42 +- .../plc4x/java/ads/api/serial/types/CRC.java | 118 +- .../ads/api/serial/types/FragmentNumber.java | 138 +- .../ads/api/serial/types/MagicCookie.java | 118 +- .../ads/api/serial/types/ReceiverAddress.java | 142 +- .../api/serial/types/TransmitterAddress.java | 144 +- .../java/ads/api/serial/types/UserData.java | 144 +- .../ads/api/serial/types/UserDataLength.java | 138 +- .../ads/api/serial/types/package-info.java | 42 +- .../plc4x/java/ads/api/tcp/AmsTCPPacket.java | 188 +- .../plc4x/java/ads/api/tcp/AmsTcpHeader.java | 278 +- .../plc4x/java/ads/api/tcp/package-info.java | 42 +- .../java/ads/api/tcp/types/TcpLength.java | 122 +- .../java/ads/api/tcp/types/UserData.java | 124 +- .../java/ads/api/tcp/types/package-info.java | 42 +- .../java/ads/api/util/ByteBufSupplier.java | 54 +- .../plc4x/java/ads/api/util/ByteReadable.java | 108 +- .../plc4x/java/ads/api/util/ByteValue.java | 208 +- .../java/ads/api/util/LengthSupplier.java | 50 +- .../ads/api/util/UnsignedIntLEByteValue.java | 208 +- .../api/util/UnsignedShortLEByteValue.java | 208 +- .../plc4x/java/ads/api/util/package-info.java | 42 +- .../plc4x/java/ads/model/AdsDataType.java | 1154 ++-- .../apache/plc4x/java/ads/model/AdsField.java | 52 +- .../java/ads/model/AdsPlcFieldHandler.java | 2030 +++---- .../java/ads/model/AdsSubscriptionHandle.java | 170 +- .../plc4x/java/ads/model/DirectAdsField.java | 282 +- .../java/ads/model/SymbolicAdsField.java | 210 +- .../plc4x/java/ads/model/package-info.java | 42 +- .../ads/protocol/Ads2PayloadProtocol.java | 772 +-- .../ads/protocol/Payload2SerialProtocol.java | 352 +- .../ads/protocol/Payload2TcpProtocol.java | 138 +- .../java/ads/protocol/Plc4x2AdsProtocol.java | 902 +-- .../ads/protocol/exception/AdsException.java | 114 +- .../AdsProtocolOverflowException.java | 64 +- .../plc4x/java/ads/protocol/package-info.java | 42 +- .../java/ads/protocol/util/DigestUtil.java | 118 +- .../protocol/util/LittleEndianDecoder.java | 714 +-- .../protocol/util/LittleEndianEncoder.java | 570 +- .../util/SingleMessageRateLimiter.java | 248 +- .../java/ads/protocol/util/package-info.java | 42 +- .../ads/src/site/asciidoc/index.adoc | 170 +- .../util/LittleEndianDecoderSpec.groovy | 198 +- .../util/LittleEndianEncoderSpec.groovy | 106 +- .../org/apache/plc4x/java/ads/AdsDumper.java | 228 +- .../plc4x/java/ads/ManualPlc4XAdsTest.java | 188 +- .../AdsDeviceNotificationResponseTest.java | 58 +- .../commands/CommandFactoryMethodTest.java | 218 +- .../types/AdsNotificationSampleTest.java | 136 +- .../commands/types/AdsStampHeaderTest.java | 178 +- .../types/CommandTypesFactoryMethodTest.java | 312 +- .../ads/api/commands/types/DeviceTest.java | 72 +- .../ads/api/commands/types/LengthTest.java | 118 +- .../api/commands/types/ReadLengthTest.java | 120 +- .../api/commands/types/SampleSizeTest.java | 120 +- .../ads/api/commands/types/SamplesTest.java | 120 +- .../api/commands/types/WriteLengthTest.java | 124 +- .../api/generic/GenericFactoryMethodTest.java | 172 +- .../ads/api/generic/types/AmsErrorTest.java | 194 +- .../ads/api/generic/types/AmsNetIdTest.java | 118 +- .../ads/api/generic/types/AmsPortTest.java | 150 +- .../ads/api/generic/types/CommandTest.java | 112 +- .../ads/api/generic/types/DataLengthTest.java | 152 +- .../types/GenericTypesFactoryMethodTest.java | 180 +- .../java/ads/api/generic/types/StateTest.java | 108 +- .../ads/api/generic/types/TcpLengthTest.java | 124 +- .../api/serial/SerialFactoryMethodTest.java | 166 +- .../types/GenericTypesFactoryMethodTest.java | 184 +- .../ads/api/tcp/TcpFactoryMethodTest.java | 172 +- .../types/GenericTypesFactoryMethodTest.java | 174 +- .../java/ads/api/util/ByteValueTest.java | 290 +- .../ads/model/AdsPlcFieldHandlerTest.java | 1180 ++-- .../java/ads/model/DirectAdsFieldTest.java | 140 +- .../ads/protocol/AbstractProtocolTest.java | 302 +- .../ads/protocol/Ads2PayloadProtocolTest.java | 196 +- ...SerialProtocolExampleConversationTest.java | 456 +- .../protocol/Payload2SerialProtocolTest.java | 224 +- .../ads/protocol/Payload2TcpProtocolTest.java | 222 +- .../ads/protocol/Plc4x2AdsProtocolTest.java | 510 +- .../ads/protocol/util/DigestUtilTest.java | 290 +- .../ads/src/test/resources/logback.xml | 74 +- plc4j/protocols/benchmarks/README.md | 58 +- plc4j/protocols/benchmarks/pom.xml | 302 +- .../ads/protocol/ADSProtocolBenchmark.java | 328 +- .../benchmarks/src/main/resources/logback.xml | 70 +- plc4j/protocols/delta-v/pom.xml | 312 +- plc4j/protocols/driver-bases/base/pom.xml | 200 +- .../GeneratedDriverByteToMessageCodec.java | 158 +- .../java/base/PlcByteToMessageCodec.java | 118 +- .../java/base/PlcMessageToMessageCodec.java | 120 +- .../connection/AbstractPlcConnection.java | 210 +- .../java/base/connection/ChannelFactory.java | 66 +- .../connection/DefaultPlcFieldHandler.java | 212 +- .../base/connection/NettyPlcConnection.java | 264 +- .../java/base/connection/PlcFieldHandler.java | 124 +- .../plc4x/java/base/events/ConnectEvent.java | 44 +- .../java/base/events/ConnectedEvent.java | 44 +- .../DefaultPlcProprietaryRequest.java | 86 +- .../DefaultPlcProprietaryResponse.java | 84 +- .../base/messages/DefaultPlcReadRequest.java | 226 +- .../base/messages/DefaultPlcReadResponse.java | 1232 ++-- .../messages/DefaultPlcSubscriptionEvent.java | 110 +- .../DefaultPlcSubscriptionRequest.java | 336 +- .../DefaultPlcSubscriptionResponse.java | 180 +- .../DefaultPlcUnsubscriptionRequest.java | 180 +- .../DefaultPlcUnsubscriptionResponse.java | 72 +- .../base/messages/DefaultPlcWriteRequest.java | 572 +- .../messages/DefaultPlcWriteResponse.java | 124 +- .../messages/InternalPlcFieldRequest.java | 62 +- .../messages/InternalPlcFieldResponse.java | 52 +- .../base/messages/InternalPlcMessage.java | 46 +- .../InternalPlcProprietaryRequest.java | 44 +- .../InternalPlcProprietaryResponse.java | 42 +- .../base/messages/InternalPlcReadRequest.java | 52 +- .../messages/InternalPlcReadResponse.java | 62 +- .../base/messages/InternalPlcRequest.java | 48 +- .../base/messages/InternalPlcResponse.java | 50 +- .../InternalPlcSubscriptionEvent.java | 50 +- .../InternalPlcSubscriptionRequest.java | 72 +- .../InternalPlcSubscriptionResponse.java | 60 +- .../InternalPlcUnsubscriptionRequest.java | 58 +- .../InternalPlcUnsubscriptionResponse.java | 50 +- .../messages/InternalPlcWriteRequest.java | 72 +- .../messages/InternalPlcWriteResponse.java | 56 +- .../base/messages/PlcProprietaryRequest.java | 50 +- .../base/messages/PlcProprietaryResponse.java | 50 +- .../base/messages/PlcProprietarySender.java | 50 +- .../base/messages/PlcProtocolMessage.java | 50 +- .../java/base/messages/PlcRawMessage.java | 92 +- .../plc4x/java/base/messages/PlcReader.java | 80 +- .../base/messages/PlcRequestContainer.java | 170 +- .../java/base/messages/PlcSubscriber.java | 126 +- .../plc4x/java/base/messages/PlcWriter.java | 80 +- .../messages/items/BaseDefaultFieldItem.java | 402 +- .../items/DefaultBigDecimalFieldItem.java | 342 +- .../items/DefaultBigIntegerFieldItem.java | 342 +- .../items/DefaultBooleanFieldItem.java | 368 +- .../items/DefaultByteArrayFieldItem.java | 116 +- .../messages/items/DefaultByteFieldItem.java | 300 +- .../items/DefaultDoubleFieldItem.java | 316 +- .../items/DefaultDurationFieldItem.java | 108 +- .../messages/items/DefaultFloatFieldItem.java | 312 +- .../items/DefaultIntegerFieldItem.java | 324 +- .../items/DefaultLocalDateFieldItem.java | 108 +- .../items/DefaultLocalDateTimeFieldItem.java | 156 +- .../items/DefaultLocalTimeFieldItem.java | 108 +- .../messages/items/DefaultLongFieldItem.java | 308 +- .../messages/items/DefaultShortFieldItem.java | 302 +- .../items/DefaultStringFieldItem.java | 118 +- .../model/DefaultPlcConsumerRegistration.java | 170 +- .../model/DefaultPlcSubscriptionHandle.java | 124 +- .../InternalPlcConsumerRegistration.java | 64 +- .../model/InternalPlcSubscriptionHandle.java | 50 +- .../java/base/model/SubscriptionPlcField.java | 110 +- .../SingleItemToSingleRequestProtocol.java | 1292 ++--- .../DefaultPlcReadResponseSpec.groovy | 172 +- .../messages/items/DefaultItemsSpec.groovy | 434 +- .../connection/AbstractPlcConnectionTest.java | 200 +- .../connection/NettyPlcConnectionTest.java | 184 +- .../DefaultPlcProprietaryRequestTest.java | 94 +- .../DefaultPlcProprietaryResponseTest.java | 98 +- .../messages/DefaultPlcReadRequestTest.java | 230 +- .../messages/DefaultPlcReadResponseTest.java | 238 +- .../DefaultPlcSubscriptionEventTest.java | 134 +- .../DefaultPlcSubscriptionRequestTest.java | 312 +- .../DefaultPlcSubscriptionResponseTest.java | 246 +- .../DefaultPlcUnsubscriptionRequestTest.java | 180 +- .../DefaultPlcUnsubscriptionResponseTest.java | 94 +- .../messages/DefaultPlcWriteRequestTest.java | 138 +- .../messages/DefaultPlcWriteResponseTest.java | 180 +- .../java/base/messages/PlcRawMessageTest.java | 112 +- .../messages/PlcRequestContainerTest.java | 162 +- .../items/DefaultLongFieldItemTest.java | 226 +- .../DefaultPlcConsumerRegistrationTest.java | 174 +- .../DefaultPlcSubscriptionHandleTest.java | 144 +- .../base/model/SubscriptionPlcFieldTest.java | 134 +- ...SingleItemToSingleRequestProtocolTest.java | 1456 ++--- ...framework.report.IReportCreator.properties | 130 +- .../driver-bases/pcap-socket/pom.xml | 132 +- .../base/connection/PcapChannelFactory.java | 202 +- plc4j/protocols/driver-bases/pom.xml | 90 +- .../protocols/driver-bases/raw-socket/pom.xml | 132 +- .../connection/RawSocketChannelFactory.java | 220 +- plc4j/protocols/driver-bases/serial/pom.xml | 160 +- .../connection/connection/SerialChannel.java | 1270 ++--- .../connection/SerialChannelFactory.java | 166 +- .../connection/SerialChannelHandler.java | 344 +- .../connection/SerialPollingSelector.java | 352 +- .../connection/SerialSelectionKey.java | 160 +- .../connection/SerialSelectorProvider.java | 136 +- .../connection/SerialSocketAddress.java | 94 +- .../connection/SerialSocketChannel.java | 316 +- .../connection/SerialChannelFactoryTest.java | 220 +- plc4j/protocols/driver-bases/tcp/pom.xml | 122 +- .../connection/TcpSocketChannelFactory.java | 224 +- plc4j/protocols/driver-bases/test/pom.xml | 192 +- .../apache/plc4x/java/mock/MockDevice.java | 100 +- .../org/apache/plc4x/java/mock/MockField.java | 98 +- .../plc4x/java/mock/MockFieldHandler.java | 206 +- .../apache/plc4x/java/mock/MockFieldItem.java | 68 +- .../plc4x/java/mock/PlcMockConnection.java | 386 +- .../apache/plc4x/java/mock/PlcMockDriver.java | 124 +- .../java/mock/connection/MockConnection.java | 82 +- .../mock/connection/TestChannelFactory.java | 90 +- .../mock/connection/tcp/TcpHexDumper.java | 296 +- .../protocol/Plc4XSupportedDataTypes.java | 514 +- .../apache/plc4x/java/mock/util/Assert.java | 172 +- .../apache/plc4x/java/mock/util/HexUtil.java | 98 +- ...framework.report.IReportCreator.properties | 130 +- .../org.apache.plc4x.java.spi.PlcDriver | 38 +- .../plc4x/java/mock/MockFieldHandlerTest.java | 220 +- .../plc4x/java/mock/MockFieldItemTest.java | 60 +- .../apache/plc4x/java/mock/MockFieldTest.java | 94 +- .../java/mock/PlcMockConnectionTest.java | 326 +- .../plc4x/java/mock/PlcMockDriverTest.java | 190 +- plc4j/protocols/driver-bases/udp/pom.xml | 122 +- .../connection/UdpSocketChannelFactory.java | 220 +- plc4j/protocols/ethernet-ip/pom.xml | 246 +- .../ethernetip/model/EtherNetIpField.java | 204 +- .../java/ethernetip/netty/EnipCodec.java | 114 +- .../netty/Plc4XEtherNetIpProtocol.java | 994 ++-- .../events/EtherNetIpConnectedEvent.java | 44 +- .../netty/util/EnipPlcFieldHandler.java | 220 +- .../ethernet-ip/src/site/asciidoc/index.adoc | 158 +- plc4j/protocols/iso-on-tcp/pom.xml | 148 +- .../isoontcp/protocol/IsoOnTcpProtocol.java | 245 +- .../protocol/model/IsoOnTcpMessage.java | 60 +- .../protocol/IsoOnTcpProtocolTest.java | 338 +- plc4j/protocols/iso-tp/pom.xml | 146 +- .../java/isotp/protocol/IsoTPProtocol.java | 892 +-- .../protocol/events/IsoTPConnectedEvent.java | 44 +- .../isotp/protocol/model/IsoTPMessage.java | 76 +- .../model/params/CalledTsapParameter.java | 68 +- .../model/params/CallingTsapParameter.java | 68 +- .../model/params/ChecksumParameter.java | 80 +- ...connectAdditionalInformationParameter.java | 82 +- .../protocol/model/params/Parameter.java | 54 +- .../model/params/TpduSizeParameter.java | 82 +- .../protocol/model/params/TsapParameter.java | 72 +- .../model/tpdus/ConnectionConfirmTpdu.java | 68 +- .../model/tpdus/ConnectionRequestTpdu.java | 68 +- .../protocol/model/tpdus/ConnectionTpdu.java | 106 +- .../protocol/model/tpdus/CustomTpdu.java | 66 +- .../isotp/protocol/model/tpdus/DataTpdu.java | 102 +- .../model/tpdus/DisconnectConfirmTpdu.java | 66 +- .../model/tpdus/DisconnectRequestTpdu.java | 82 +- .../protocol/model/tpdus/DisconnectTpdu.java | 92 +- .../isotp/protocol/model/tpdus/ErrorTpdu.java | 94 +- .../java/isotp/protocol/model/tpdus/Tpdu.java | 128 +- .../protocol/model/types/DeviceGroup.java | 102 +- .../model/types/DisconnectReason.java | 128 +- .../protocol/model/types/ParameterCode.java | 150 +- .../protocol/model/types/ProtocolClass.java | 106 +- .../protocol/model/types/RejectCause.java | 104 +- .../isotp/protocol/model/types/TpduCode.java | 124 +- .../isotp/protocol/model/types/TpduSize.java | 156 +- .../isotp/protocol/IsoTPProtocolTest.java | 1270 ++--- .../protocol/model/IsoTPMessageTests.java | 120 +- .../protocol/model/params/ParameterTests.java | 122 +- .../model/params/TsapParameterTests.java | 118 +- .../protocol/model/tpdus/IsotpModelTests.java | 368 +- .../protocol/model/types/IsotpTypeTests.java | 430 +- plc4j/protocols/modbus/pom.xml | 256 +- .../DefaultModbusByteArrayFieldItem.java | 654 +-- .../java/modbus/model/CoilModbusField.java | 96 +- .../model/MaskWriteRegisterModbusField.java | 182 +- .../plc4x/java/modbus/model/ModbusField.java | 146 +- .../model/ReadDiscreteInputsModbusField.java | 96 +- .../ReadHoldingRegistersModbusField.java | 96 +- .../model/ReadInputRegistersModbusField.java | 96 +- .../modbus/model/RegisterModbusField.java | 98 +- .../modbus/netty/Plc4XModbusProtocol.java | 1068 ++-- .../modbus/util/ModbusPlcFieldHandler.java | 880 +-- .../java/modbus/ManualPlc4XModbusTest.java | 276 +- .../DefaultModbusByteArrayFieldItemTest.java | 270 +- .../modbus/netty/Plc4XModbusProtocolTest.java | 818 +-- .../modbus/src/test/resources/logback.xml | 74 +- plc4j/protocols/pom.xml | 176 +- plc4j/protocols/s7/LINKS.md | 48 +- plc4j/protocols/s7/pom.xml | 208 +- .../apache/plc4x/java/s7/model/S7Field.java | 528 +- .../plc4x/java/s7/model/S7SslField.java | 142 +- .../java/s7/model/S7SubscriptionField.java | 332 +- .../java/s7/netty/Plc4XNettyException.java | 74 +- .../plc4x/java/s7/netty/Plc4XS7Protocol.java | 3636 ++++++------ .../s7/netty/S7HEmbeddedChannelFactory.java | 45 + .../apache/plc4x/java/s7/netty/S7HProxy.java | 343 ++ .../plc4x/java/s7/netty/S7HProxyHelper.java | 74 + .../plc4x/java/s7/netty/S7Protocol.java | 3854 ++++++------- .../plc4x/java/s7/netty/events/S7Alarm.java | 1056 ++-- .../s7/netty/events/S7ConnectedEvent.java | 44 +- .../s7/netty/model/messages/S7Message.java | 196 +- .../netty/model/messages/S7PushMessage.java | 56 +- .../model/messages/S7RequestMessage.java | 160 +- .../model/messages/S7ResponseMessage.java | 100 +- .../SetupCommunicationRequestMessage.java | 70 +- .../CpuCyclicServicesRequestParameter.java | 120 +- .../CpuCyclicServicesResponseParameter.java | 100 +- .../params/CpuDiagnosticPushParameter.java | 174 +- .../model/params/CpuServicesParameter.java | 108 +- .../params/CpuServicesPushParameter.java | 112 +- .../params/CpuServicesRequestParameter.java | 66 +- .../params/CpuServicesResponseParameter.java | 130 +- .../s7/netty/model/params/S7Parameter.java | 54 +- .../params/SetupCommunicationParameter.java | 104 +- .../s7/netty/model/params/VarParameter.java | 108 +- .../params/items/S7AnyVarParameterItem.java | 188 +- .../model/params/items/VarParameterItem.java | 54 +- .../model/payloads/AlarmMessagePayload.java | 202 +- .../CpuCyclicServicesRequestPayload.java | 242 +- .../CpuCyclicServicesResponsePayload.java | 168 +- .../CpuCyclicServicesUnsubscribePayload.java | 158 +- .../payloads/CpuDiagnosticMessagePayload.java | 164 +- ...CpuMessageSubscriptionResponsePayload.java | 118 +- .../CpuMessageSubscriptionServicePayload.java | 154 +- .../model/payloads/CpuServicesPayload.java | 172 +- .../s7/netty/model/payloads/S7Payload.java | 54 +- .../s7/netty/model/payloads/VarPayload.java | 118 +- .../payloads/items/AlarmMessageItem.java | 252 +- .../payloads/items/AssociatedValueItem.java | 138 +- .../items/CpuDiagnosticMessageItem.java | 190 +- .../payloads/items/MessageObjectItem.java | 668 +-- .../payloads/items/S7AnyVarPayloadItem.java | 190 +- .../model/payloads/items/VarPayloadItem.java | 116 +- .../model/payloads/ssls/SslDataRecord.java | 50 +- .../SslModuleIdentificationDataRecord.java | 132 +- .../s7/netty/model/types/AlarmQueryType.java | 148 +- .../java/s7/netty/model/types/AlarmType.java | 162 +- .../netty/model/types/CpuCurrentModeType.java | 166 +- .../types/CpuCyclicServiceTimeBaseType.java | 152 +- ...ServicesParameterSubFunctionGroupType.java | 158 +- .../CpuServicesParameterFunctionGroup.java | 130 +- .../CpuServicesParameterSubFunctionGroup.java | 148 +- .../model/types/CpuUserDataMethodType.java | 154 +- ...CpuUserDataParameterFunctionGroupType.java | 166 +- .../model/types/CpuUserDataParameterType.java | 160 +- .../model/types/DataTransportErrorCode.java | 124 +- .../netty/model/types/DataTransportSize.java | 128 +- .../netty/model/types/HeaderErrorClass.java | 110 +- .../java/s7/netty/model/types/MemoryArea.java | 166 +- .../s7/netty/model/types/MessageType.java | 110 +- .../s7/netty/model/types/ParameterError.java | 140 +- .../s7/netty/model/types/ParameterType.java | 144 +- .../s7/netty/model/types/PushEventType.java | 134 +- .../java/s7/netty/model/types/QueryType.java | 146 +- .../netty/model/types/SpecificationType.java | 104 +- .../java/s7/netty/model/types/SslId.java | 204 +- .../model/types/SubscribedEventType.java | 154 +- .../s7/netty/model/types/TransportSize.java | 404 +- .../model/types/VariableAddressingMode.java | 130 +- .../strategies/DefaultS7MessageProcessor.java | 1052 ++-- .../LongS7MessageProcessorCodec.java | 1310 ++--- .../netty/strategies/S7MessageProcessor.java | 76 +- .../s7/netty/util/S7PlcFieldEventHandler.java | 82 +- .../java/s7/netty/util/S7PlcFieldHandler.java | 1354 ++--- .../netty/util/S7RequestSizeCalculator.java | 316 +- .../netty/util/S7ResponseSizeEstimator.java | 358 +- .../java/s7/netty/util/S7SizeHelper.java | 354 +- .../java/s7/protocol/S7ByteReadResponse.java | 1016 ++-- .../S7CyclicServicesSubscriptionHandle.java | 158 +- .../S7DiagnosticSubscriptionHandle.java | 160 +- .../java/s7/protocol/event/S7AlarmEvent.java | 1396 ++--- .../s7/protocol/event/S7CyclicValueEvent.java | 950 ++-- .../plc4x/java/s7/protocol/event/S7Event.java | 110 +- .../java/s7/protocol/event/S7ModeEvent.java | 1052 ++-- .../java/s7/protocol/event/S7SysEvent.java | 1040 ++-- .../java/s7/protocol/event/S7UserEvent.java | 56 +- .../plc4x/java/s7/types/S7ControllerType.java | 62 +- .../s7/types/S7SubscriptionFieldType.java | 68 +- .../java/s7/utils/S7DiagnosticEventId.java | 1370 ++--- .../apache/plc4x/java/s7/utils/S7Helper.java | 2718 ++++----- .../plc4x/java/s7/utils/S7ParamErrorCode.java | 552 +- .../plc4x/java/s7/utils/S7TsapIdEncoder.java | 96 +- .../protocols/s7/src/site/asciidoc/index.adoc | 200 +- .../java/s7/netty/Plc4XS7ProtocolSpec.groovy | 556 +- .../org/apache/plc4x/java/issues/PLC4X56.java | 162 +- .../apache/plc4x/java/s7/PcapGenerator.java | 636 +-- .../plc4x/java/s7/model/S7FieldTests.java | 204 +- .../java/s7/netty/Plc4XS7ProtocolTest.java | 368 +- .../plc4x/java/s7/netty/S7ProtocolTest.java | 848 +-- .../netty/model/messages/S7MessageTests.java | 380 +- .../netty/model/params/S7ParameterTests.java | 158 +- .../netty/model/payloads/S7PayloadTests.java | 262 +- .../s7/netty/model/types/S7TypeTests.java | 298 +- .../DefaultS7MessageProcessorTest.java | 1862 +++---- .../s7/netty/util/S7PlcFieldHandlerTest.java | 732 +-- .../util/S7RequestSizeCalculatorTest.java | 280 +- .../util/S7ResponseSizeEstimatorTest.java | 242 +- .../java/s7/netty/util/S7SizeHelperTest.java | 238 +- .../plc4x/java/s7/types/S7DataTypeTest.java | 112 +- .../java/s7/utils/S7TsapIdEncoderTest.java | 134 +- ...framework.report.IReportCreator.properties | 130 +- .../s7/src/test/resources/logback.xml | 70 +- .../developers/implementing-drivers.adoc | 496 +- plc4j/protocols/src/site/site.xml | 58 +- plc4j/src/site/asciidoc/index.adoc | 200 +- .../site/asciidoc/users/gettingstarted.adoc | 356 +- plc4j/utils/connection-pool/pom.xml | 100 +- .../java/utils/connectionpool/PoolKey.java | 144 +- .../utils/connectionpool/PoolKeyFactory.java | 208 +- .../PooledPlcConnectionFactory.java | 92 +- .../PooledPlcDriverManager.java | 350 +- .../connectionpool/PoolKeyFactoryTest.java | 184 +- .../connectionpool/PooledDummyDriver.java | 104 +- .../PooledPlcDriverManagerTest.java | 732 +-- .../org.apache.plc4x.java.spi.PlcDriver | 38 +- .../src/test/resources/logback.xml | 66 +- plc4j/utils/driver-base-java/pom.xml | 82 +- .../jinahya/bit/io/MyDefaultBitInput.java | 70 +- .../plc4x/java/utils/EvaluationHelper.java | 106 +- .../org/apache/plc4x/java/utils/Message.java | 52 +- .../apache/plc4x/java/utils/MessageIO.java | 46 +- .../apache/plc4x/java/utils/MessageInput.java | 50 +- .../plc4x/java/utils/MessageOutput.java | 50 +- .../plc4x/java/utils/ParseException.java | 64 +- .../apache/plc4x/java/utils/ReadBuffer.java | 438 +- .../apache/plc4x/java/utils/WriteBuffer.java | 416 +- plc4j/utils/interop/pom.xml | 430 +- plc4j/utils/interop/src/assembly/assembly.xml | 80 +- .../org/apache/plc4x/interop/impl/Client.java | 120 +- .../apache/plc4x/interop/impl/Handler.java | 320 +- .../org/apache/plc4x/interop/impl/Server.java | 182 +- plc4j/utils/opm/pom.xml | 204 +- .../apache/plc4x/java/opm/AliasRegistry.java | 98 +- .../apache/plc4x/java/opm/OPMException.java | 74 +- .../org/apache/plc4x/java/opm/OpmUtils.java | 184 +- .../org/apache/plc4x/java/opm/PlcEntity.java | 66 +- .../plc4x/java/opm/PlcEntityInterceptor.java | 1138 ++-- .../plc4x/java/opm/PlcEntityManager.java | 450 +- .../org/apache/plc4x/java/opm/PlcField.java | 70 +- .../plc4x/java/opm/SimpleAliasRegistry.java | 150 +- .../opm/src/site/asciidoc/opm/using-opm.adoc | 122 +- plc4j/utils/opm/src/site/site.xml | 58 +- .../plc4x/java/opm/ConnectedEntityTest.java | 236 +- .../plc4x/java/opm/OPMExceptionTest.java | 82 +- .../apache/plc4x/java/opm/OpmUtilsTest.java | 130 +- .../java/opm/PlcEntityInterceptorTest.java | 426 +- .../java/opm/PlcEntityManagerComplexTest.java | 918 +-- .../plc4x/java/opm/PlcEntityManagerTest.java | 634 +-- .../java/opm/SimpleAliasRegistryTest.java | 156 +- .../utils/opm/src/test/resources/logback.xml | 70 +- plc4j/utils/pcap-sockets/pom.xml | 178 +- .../pcapsockets/PcapSocketException.java | 68 +- .../pcapsockets/netty/PacketHandler.java | 54 +- .../pcapsockets/netty/PcapSocketAddress.java | 120 +- .../pcapsockets/netty/PcapSocketChannel.java | 602 +- .../netty/PcapSocketChannelConfig.java | 184 +- .../netty/PcapSocketChannelOption.java | 78 +- .../pcapsockets/netty/TcpIpPacketHandler.java | 82 +- .../pcapsockets/netty/UdpIpPacketHandler.java | 82 +- plc4j/utils/pom.xml | 116 +- plc4j/utils/protocol-test-utils/pom.xml | 142 +- .../test/ProtocolTestsuiteRunner.java | 350 +- .../ProtocolTestsuiteException.java | 64 +- .../test/model/ProtocolTestsuite.java | 96 +- .../plc4x/protocol/test/model/Testcase.java | 122 +- .../src/main/resources/schemas/testsuite.xsd | 108 +- plc4j/utils/raw-sockets/pom.xml | 200 +- .../utils/rawsockets/RawSocketException.java | 68 +- .../rawsockets/attic/RawEthernetSocket.java | 300 +- .../utils/rawsockets/attic/RawIpSocket.java | 1258 ++--- .../rawsockets/attic/RawSocketListener.java | 44 +- .../utils/rawsockets/netty/PacketHandler.java | 54 +- .../rawsockets/netty/RawSocketAddress.java | 90 +- .../rawsockets/netty/RawSocketChannel.java | 562 +- .../netty/RawSocketChannelConfig.java | 132 +- .../netty/RawSocketChannelOption.java | 64 +- .../rawsockets/netty/RawSocketIpAddress.java | 92 +- .../rawsockets/netty/TcpIpPacketHandler.java | 82 +- .../rawsockets/netty/UdpIpPacketHandler.java | 82 +- .../src/remote-resources/META-INF/LICENSE | 16 +- .../src/remote-resources/META-INF/NOTICE | 8 +- .../rawsockets/attic/RawIpSocketTest.java | 196 +- .../netty/RawSocketChannelTest.java | 202 +- plc4j/utils/scraper/README.md | 40 +- plc4j/utils/scraper/pom.xml | 288 +- .../plc4x/java/scraper/ResultHandler.java | 76 +- .../apache/plc4x/java/scraper/ScrapeJob.java | 96 +- .../plc4x/java/scraper/ScrapeJobImpl.java | 136 +- .../apache/plc4x/java/scraper/Scraper.java | 82 +- .../plc4x/java/scraper/ScraperImpl.java | 362 +- .../plc4x/java/scraper/ScraperTask.java | 98 +- .../plc4x/java/scraper/ScraperTaskImpl.java | 468 +- .../java/scraper/config/JobConfiguration.java | 78 +- .../config/JobConfigurationClassicImpl.java | 98 +- .../JobConfigurationClassicImplBuilder.java | 132 +- .../scraper/config/JobConfigurationImpl.java | 168 +- .../scraper/config/ScraperConfiguration.java | 162 +- .../ScraperConfigurationClassicImpl.java | 172 +- ...craperConfigurationClassicImplBuilder.java | 108 +- .../JobConfigurationTriggeredImpl.java | 94 +- .../JobConfigurationTriggeredImplBuilder.java | 142 +- .../ScraperConfigurationTriggeredImpl.java | 254 +- ...aperConfigurationTriggeredImplBuilder.java | 100 +- .../ScraperConfigurationException.java | 86 +- .../scraper/exception/ScraperException.java | 74 +- .../TriggeredScrapeJobImpl.java | 148 +- .../TriggeredScraperImpl.java | 734 +-- .../TriggeredScraperMBean.java | 66 +- .../TriggeredScraperTask.java | 546 +- .../TriggeredScraperTaskMBean.java | 70 +- .../triggerhandler/TriggerConfiguration.java | 1442 ++--- .../triggerhandler/TriggerHandler.java | 46 +- .../triggerhandler/TriggerHandlerImpl.java | 226 +- .../collector/TriggerCollector.java | 130 +- .../collector/TriggerCollectorImpl.java | 646 +-- .../util/PercentageAboveThreshold.java | 116 +- .../plc4x/java/s7/ManualS7PlcDriverMT.java | 410 +- .../scraper/ScraperConfigurationTest.java | 408 +- .../plc4x/java/scraper/ScraperRunner.java | 80 +- .../plc4x/java/scraper/ScraperTaskTest.java | 224 +- .../plc4x/java/scraper/ScraperTest.java | 348 +- .../java/scraper/TriggeredScraperRunner.java | 110 +- .../scraper/TriggeredScraperRunnerModbus.java | 138 +- .../ScraperConfigurationBuilderTest.java | 136 +- .../TriggeredScraperImplTest.java | 234 +- .../TriggerConfigurationTest.java | 300 +- .../scraper/src/test/resources/config.json | 34 +- .../scraper/src/test/resources/config.yml | 56 +- .../scraper/src/test/resources/example.yml | 86 +- .../resources/example_triggered_scraper.yml | 146 +- .../example_triggered_scraper_modbus.yml | 60 +- .../test/resources/example_with_strings.yml | 82 +- .../src/test/resources/logback-test.xml | 76 +- .../scraper/src/test/resources/logback.xml | 70 +- .../test/resources/mock-scraper-config.yml | 112 +- plc4j/utils/test-utils/pom.xml | 114 +- .../java/org/apache/plc4x/test/FastTests.java | 44 +- .../plc4x/test/RequireInternetConnection.java | 66 +- .../RequireInternetConnectionCondition.java | 90 +- .../plc4x/test/RequireNonCaptureAllDns.java | 66 +- .../RequireNonCaptureAllDnsCondition.java | 80 +- .../org/apache/plc4x/test/RequirePcap.java | 66 +- .../plc4x/test/RequirePcapCondition.java | 114 +- .../org/apache/plc4x/test/RequirePcapNg.java | 66 +- .../plc4x/test/RequirePcapNgCondition.java | 138 +- .../test-utils/src/main/resources/logback.xml | 70 +- pom.xml | 3878 ++++++------- protocols/ab-eth/pom.xml | 84 +- .../plc4x/protocol/abeth/ABETHProtocol.java | 92 +- ...4x.plugins.codegenerator.protocol.Protocol | 36 +- .../resources/protocols/abeth/ab-eth.mspec | 168 +- protocols/bacnetip/pom.xml | 84 +- .../protocol/bacnetip/BacNetIpProtocol.java | 94 +- ...4x.plugins.codegenerator.protocol.Protocol | 36 +- .../protocols/bacnetip/bacnetip.mspec | 1354 ++--- protocols/df1/pom.xml | 84 +- .../plc4x/protocol/df1/Df1Protocol.java | 92 +- ...4x.plugins.codegenerator.protocol.Protocol | 36 +- .../main/resources/protocols/df1/df1.mspec | 106 +- protocols/knxnetip/pom.xml | 84 +- .../protocol/knxnetip/KnxNetIpProtocol.java | 92 +- ...4x.plugins.codegenerator.protocol.Protocol | 36 +- .../protocols/knxnetip/knxnetip.mspec | 602 +- .../knxnetip/src/site/asciidoc/index.adoc | 112 +- .../plc4x/protocols/knxnetip/protocol.tdml | 1208 ++-- protocols/pom.xml | 418 +- protocols/proxy/pom.xml | 68 +- protocols/proxy/src/main/java/.keepMe | 38 +- .../plc4x/protocols/proxy/interop.thrift | 186 +- protocols/s7/pom.xml | 84 +- .../apache/plc4x/protocol/s7/S7Protocol.java | 92 +- ...4x.plugins.codegenerator.protocol.Protocol | 36 +- .../src/main/resources/protocols/s7/s7.mspec | 734 +-- .../apache/plc4x/protocols/s7/protocol.tdml | 4930 ++++++++--------- sandbox/code-gen/pom.xml | 140 +- sandbox/code-gen/src/main/antlr4/imaginary.g4 | 296 +- .../org/apache/plc4x/codegen/DFDLUtil.java | 192 +- .../org/apache/plc4x/codegen/api/Buffer.java | 62 +- .../plc4x/codegen/ast/AbstractNode.java | 64 +- .../codegen/ast/AssignementExpression.java | 94 +- .../plc4x/codegen/ast/BinaryExpression.java | 122 +- .../org/apache/plc4x/codegen/ast/Block.java | 106 +- .../plc4x/codegen/ast/BlockBuilder.java | 96 +- .../plc4x/codegen/ast/CallExpression.java | 124 +- .../plc4x/codegen/ast/ClassDeclaration.java | 146 +- .../apache/plc4x/codegen/ast/CodeWriter.java | 150 +- .../plc4x/codegen/ast/ConstantExpression.java | 92 +- .../codegen/ast/ConstructorDeclaration.java | 82 +- .../codegen/ast/DeclarationStatement.java | 102 +- .../plc4x/codegen/ast/ExceptionType.java | 80 +- .../apache/plc4x/codegen/ast/Expression.java | 54 +- .../apache/plc4x/codegen/ast/Expressions.java | 648 +-- .../plc4x/codegen/ast/FieldDeclaration.java | 112 +- .../plc4x/codegen/ast/FieldReference.java | 88 +- .../apache/plc4x/codegen/ast/FileNode.java | 86 +- .../apache/plc4x/codegen/ast/Generator.java | 152 +- .../apache/plc4x/codegen/ast/IfStatement.java | 120 +- .../plc4x/codegen/ast/JavaGenerator.java | 656 +-- .../apache/plc4x/codegen/ast/LineComment.java | 86 +- .../org/apache/plc4x/codegen/ast/Method.java | 142 +- .../plc4x/codegen/ast/MethodDefinition.java | 146 +- .../apache/plc4x/codegen/ast/Modifier.java | 50 +- .../plc4x/codegen/ast/NewExpression.java | 96 +- .../org/apache/plc4x/codegen/ast/Node.java | 54 +- .../apache/plc4x/codegen/ast/NodeVisitor.java | 56 +- .../codegen/ast/ParameterExpression.java | 82 +- .../apache/plc4x/codegen/ast/Primitive.java | 116 +- .../plc4x/codegen/ast/PythonGenerator.java | 636 +-- .../plc4x/codegen/ast/ReturnStatement.java | 80 +- .../apache/plc4x/codegen/ast/Statement.java | 44 +- .../plc4x/codegen/ast/TypeDefinition.java | 86 +- .../apache/plc4x/codegen/ast/TypeUtil.java | 58 +- .../apache/plc4x/codegen/ast/UnknownType.java | 92 +- .../codegen/python/AbstractNodeVisitor.java | 454 +- .../apache/plc4x/codegen/python/AddNode.java | 60 +- .../plc4x/codegen/python/AliasNode.java | 104 +- .../plc4x/codegen/python/AnnAssignerNode.java | 148 +- .../apache/plc4x/codegen/python/ArgNode.java | 104 +- .../plc4x/codegen/python/ArgumentsNode.java | 92 +- .../plc4x/codegen/python/AssignNode.java | 110 +- .../plc4x/codegen/python/AttributeNode.java | 126 +- .../plc4x/codegen/python/AugAssignNode.java | 126 +- .../plc4x/codegen/python/BinOpNode.java | 126 +- .../apache/plc4x/codegen/python/CallNode.java | 132 +- .../plc4x/codegen/python/ClassDefNode.java | 146 +- .../plc4x/codegen/python/CodePrinter.java | 148 +- .../plc4x/codegen/python/CompareNode.java | 132 +- .../plc4x/codegen/python/ContextNode.java | 44 +- .../apache/plc4x/codegen/python/EqNode.java | 56 +- .../apache/plc4x/codegen/python/ExprNode.java | 82 +- .../plc4x/codegen/python/FunctionDefNode.java | 158 +- .../apache/plc4x/codegen/python/IfNode.java | 132 +- .../plc4x/codegen/python/ImportFromNode.java | 132 +- .../plc4x/codegen/python/KeywordNode.java | 104 +- .../plc4x/codegen/python/LineEntryNode.java | 92 +- .../apache/plc4x/codegen/python/ListNode.java | 110 +- .../apache/plc4x/codegen/python/LoadNode.java | 56 +- .../plc4x/codegen/python/ModuleNode.java | 86 +- .../apache/plc4x/codegen/python/MultNode.java | 56 +- .../codegen/python/NameConstantNode.java | 82 +- .../apache/plc4x/codegen/python/NameNode.java | 104 +- .../org/apache/plc4x/codegen/python/Node.java | 58 +- .../plc4x/codegen/python/NodeVisitor.java | 172 +- .../plc4x/codegen/python/NotEqNode.java | 56 +- .../apache/plc4x/codegen/python/NumNode.java | 82 +- .../apache/plc4x/codegen/python/PassNode.java | 56 +- .../plc4x/codegen/python/ReturnNode.java | 82 +- .../plc4x/codegen/python/StoreNode.java | 56 +- .../apache/plc4x/codegen/python/StrNode.java | 82 +- .../plc4x/codegen/python/TupleNode.java | 110 +- .../plc4x/codegen/python/WhileNode.java | 132 +- .../apache/plc4x/codegen/util/BufferUtil.java | 90 +- .../plc4x/codegen/util/EnumFactory.java | 306 +- .../plc4x/codegen/util/PojoFactory.java | 240 +- .../code-gen/src/main/resources/example.json | 282 +- .../code-gen/src/main/resources/example2.json | 4256 +++++++------- .../apache/plc4x/codegen/DFDLUtilTest.java | 74 +- .../apache/plc4x/codegen/ModuleNodeTest.java | 374 +- .../org/apache/plc4x/codegen/PojoBuilder.java | 70 +- .../plc4x/codegen/ast/JavaGeneratorTest.java | 626 +-- .../codegen/ast/PythonGeneratorTest.java | 196 +- .../plc4x/codegen/util/EnumFactoryTest.java | 178 +- .../org/apache/plc4x/codegen/util/MyPojo.java | 128 +- .../plc4x/codegen/util/PojoFactoryTest.java | 126 +- .../src/test/resources/protocol.dfdl.xsd | 1816 +++--- sandbox/plc-simulator/pom.xml | 254 +- .../apache/plc4x/simulator/PlcSimulator.java | 236 +- .../plc4x/simulator/server/ServerModule.java | 64 +- .../plc4x/simulator/server/s7/S7Server.java | 138 +- .../simulator/server/s7/S7ServerModule.java | 110 +- .../server/s7/protocol/S7Step7Protocol.java | 152 +- .../s7/protocol/S7Step7ServerProtocol.java | 456 +- .../simulation/SimulationModule.java | 86 +- .../watertank/WaterTankSimulationModule.java | 120 +- ...apache.plc4x.simulator.server.ServerModule | 38 +- ...lc4x.simulator.simulation.SimulationModule | 38 +- .../src/main/resources/logback.xml | 70 +- sandbox/plc4cpp/CMakeLists.txt | 118 +- sandbox/plc4cpp/README.md | 92 +- sandbox/plc4cpp/api/CMakeLists.txt | 140 +- .../org/apache/plc4x/cpp/PlcConnection.cpp | 164 +- .../cpp/org/apache/plc4x/cpp/PlcConnection.h | 336 +- .../org/apache/plc4x/cpp/PlcDriverManager.cpp | 374 +- .../org/apache/plc4x/cpp/PlcDriverManager.h | 140 +- .../apache/plc4x/cpp/api/PlcConnection.cpp | 162 +- .../org/apache/plc4x/cpp/api/PlcConnection.h | 318 +- .../api/authentication/PlcAuthentication.cpp | 100 +- .../api/authentication/PlcAuthentication.h | 94 +- .../PlcUsernamePasswordAuthentication.cpp | 192 +- .../PlcUsernamePasswordAuthentication.h | 130 +- .../api/exceptions/PlcConnectionException.cpp | 78 +- .../api/exceptions/PlcConnectionException.h | 106 +- .../plc4x/cpp/api/exceptions/PlcException.cpp | 112 +- .../plc4x/cpp/api/exceptions/PlcException.h | 116 +- .../api/exceptions/PlcFieldRangeException.cpp | 90 +- .../api/exceptions/PlcFieldRangeException.h | 96 +- .../PlcIncompatibleDatatypeException.cpp | 90 +- .../PlcIncompatibleDatatypeException.h | 100 +- .../exceptions/PlcInvalidFieldException.cpp | 126 +- .../api/exceptions/PlcInvalidFieldException.h | 112 +- .../cpp/api/exceptions/PlcIoException.cpp | 80 +- .../plc4x/cpp/api/exceptions/PlcIoException.h | 110 +- .../exceptions/PlcNotImplementedException.cpp | 80 +- .../exceptions/PlcNotImplementedException.h | 106 +- .../api/exceptions/PlcProtocolException.cpp | 80 +- .../cpp/api/exceptions/PlcProtocolException.h | 116 +- .../PlcProtocolPayloadTooBigException.cpp | 138 +- .../PlcProtocolPayloadTooBigException.h | 126 +- .../api/exceptions/PlcRuntimeException.cpp | 102 +- .../cpp/api/exceptions/PlcRuntimeException.h | 118 +- .../api/exceptions/PlcTimeoutException.cpp | 102 +- .../cpp/api/exceptions/PlcTimeoutException.h | 138 +- .../PlcUnsupportedDataTypeException.cpp | 80 +- .../PlcUnsupportedDataTypeException.h | 106 +- .../PlcUnsupportedOperationException.cpp | 80 +- .../PlcUnsupportedOperationException.h | 110 +- .../cpp/api/messages/PlcFieldRequest.cpp | 80 +- .../plc4x/cpp/api/messages/PlcFieldRequest.h | 126 +- .../cpp/api/messages/PlcFieldResponse.cpp | 80 +- .../plc4x/cpp/api/messages/PlcFieldResponse.h | 134 +- .../plc4x/cpp/api/messages/PlcMessage.cpp | 80 +- .../plc4x/cpp/api/messages/PlcMessage.h | 104 +- .../plc4x/cpp/api/messages/PlcReadRequest.cpp | 94 +- .../plc4x/cpp/api/messages/PlcReadRequest.h | 134 +- .../api/messages/PlcReadRequestBuilder.cpp | 80 +- .../cpp/api/messages/PlcReadRequestBuilder.h | 114 +- .../cpp/api/messages/PlcReadResponse.cpp | 80 +- .../plc4x/cpp/api/messages/PlcReadResponse.h | 272 +- .../plc4x/cpp/api/messages/PlcRequest.cpp | 80 +- .../plc4x/cpp/api/messages/PlcRequest.h | 110 +- .../cpp/api/messages/PlcRequestBuilder.cpp | 80 +- .../cpp/api/messages/PlcRequestBuilder.h | 108 +- .../plc4x/cpp/api/messages/PlcResponse.cpp | 80 +- .../plc4x/cpp/api/messages/PlcResponse.h | 110 +- .../cpp/api/messages/PlcSubscriptionEvent.cpp | 80 +- .../cpp/api/messages/PlcSubscriptionEvent.h | 116 +- .../api/messages/PlcSubscriptionRequest.cpp | 80 +- .../cpp/api/messages/PlcSubscriptionRequest.h | 176 +- .../api/messages/PlcSubscriptionResponse.cpp | 80 +- .../api/messages/PlcSubscriptionResponse.h | 124 +- .../api/messages/PlcUnsubscriptionRequest.cpp | 80 +- .../api/messages/PlcUnsubscriptionRequest.h | 122 +- .../messages/PlcUnsubscriptionResponse.cpp | 80 +- .../api/messages/PlcUnsubscriptionResponse.h | 108 +- .../cpp/api/messages/PlcWriteRequest.cpp | 80 +- .../plc4x/cpp/api/messages/PlcWriteRequest.h | 172 +- .../cpp/api/messages/PlcWriteResponse.cpp | 80 +- .../plc4x/cpp/api/messages/PlcWriteResponse.h | 104 +- .../apache/plc4x/cpp/api/messages/REQUEST.cpp | 78 +- .../apache/plc4x/cpp/api/messages/REQUEST.h | 98 +- .../plc4x/cpp/api/messages/RESPONSE.cpp | 78 +- .../apache/plc4x/cpp/api/messages/RESPONSE.h | 94 +- .../cpp/api/messages/RequestTemplate.cpp | 78 +- .../plc4x/cpp/api/messages/RequestTemplate.h | 96 +- .../cpp/api/messages/ResponseTemplate.cpp | 78 +- .../plc4x/cpp/api/messages/ResponseTemplate.h | 92 +- .../api/metadata/PlcConnectionMetadata.cpp | 78 +- .../cpp/api/metadata/PlcConnectionMetadata.h | 132 +- .../apache/plc4x/cpp/api/model/Consumer.cpp | 80 +- .../org/apache/plc4x/cpp/api/model/Consumer.h | 122 +- .../cpp/api/model/PlcConsumerRegistration.cpp | 80 +- .../cpp/api/model/PlcConsumerRegistration.h | 96 +- .../apache/plc4x/cpp/api/model/PlcField.cpp | 80 +- .../org/apache/plc4x/cpp/api/model/PlcField.h | 118 +- .../cpp/api/model/PlcSubscriptionHandle.cpp | 80 +- .../cpp/api/model/PlcSubscriptionHandle.h | 122 +- .../plc4x/cpp/api/types/PlcClientDataType.cpp | 80 +- .../plc4x/cpp/api/types/PlcClientDataType.h | 110 +- .../plc4x/cpp/api/types/PlcResponseCode.cpp | 80 +- .../plc4x/cpp/api/types/PlcResponseCode.h | 100 +- .../cpp/api/types/PlcSubscriptionType.cpp | 80 +- .../plc4x/cpp/api/types/PlcSubscriptionType.h | 116 +- .../plc4x/cpp/api/types/ValueTypeObject.cpp | 82 +- .../plc4x/cpp/api/types/ValueTypeObject.h | 98 +- .../org/apache/plc4x/cpp/spi/PlcDriver.cpp | 72 +- .../cpp/org/apache/plc4x/cpp/spi/PlcDriver.h | 170 +- sandbox/plc4cpp/drivers/CMakeLists.txt | 52 +- sandbox/plc4cpp/drivers/proxy/CMakeLists.txt | 94 +- .../apache/plc4x/cpp/proxy/ProxyDriver.cpp | 178 +- .../org/apache/plc4x/cpp/proxy/ProxyDriver.h | 174 +- .../cpp/proxy/connection/ProxyConnection.cpp | 118 +- .../cpp/proxy/connection/ProxyConnection.h | 272 +- .../org/apache/plc4x/cpp/proxy/dllexports.cpp | 78 +- .../org/apache/plc4x/cpp/proxy/dllexports.h | 56 +- sandbox/plc4cpp/drivers/s7/CMakeLists.txt | 86 +- .../org/apache/plc4x/cpp/s7/S7PlcDriver.cpp | 186 +- .../cpp/org/apache/plc4x/cpp/s7/S7PlcDriver.h | 174 +- .../cpp/s7/connection/S7PlcConnection.cpp | 266 +- .../plc4x/cpp/s7/connection/S7PlcConnection.h | 296 +- .../org/apache/plc4x/cpp/s7/dllexports.cpp | 78 +- .../cpp/org/apache/plc4x/cpp/s7/dllexports.h | 56 +- sandbox/plc4cpp/examples/CMakeLists.txt | 40 +- .../examples/hello-world-plc4x/CMakeLists.txt | 54 +- .../cpp/examples/helloplc4x/helloplc4x.cpp | 244 +- sandbox/plc4cpp/integrations/CMakeLists.txt | 40 +- .../integrations/apache-mynewt/CMakeLists.txt | 40 +- .../integrations/edgex-foundry/CMakeLists.txt | 40 +- sandbox/plc4cpp/pom.xml | 688 +-- sandbox/plc4cpp/protocols/CMakeLists.txt | 40 +- .../protocols/driver-bases/CMakeLists.txt | 40 +- .../driver-bases/base/CMakeLists.txt | 136 +- .../base/connection/AbstractPlcConnection.cpp | 164 +- .../base/connection/AbstractPlcConnection.h | 156 +- .../cpp/base/connection/BoostConnection.cpp | 1008 ++-- .../cpp/base/connection/BoostConnection.h | 238 +- .../cpp/base/connection/ChannelFactory.cpp | 78 +- .../cpp/base/connection/ChannelFactory.h | 116 +- .../connection/DefaultPlcFieldHandler.cpp | 222 +- .../base/connection/DefaultPlcFieldHandler.h | 190 +- .../cpp/base/connection/PlcFieldHandler.cpp | 78 +- .../cpp/base/connection/PlcFieldHandler.h | 196 +- .../plc4x/cpp/base/events/ConnectEvent.cpp | 78 +- .../plc4x/cpp/base/events/ConnectEvent.h | 96 +- .../plc4x/cpp/base/events/ConnectedEvent.cpp | 78 +- .../plc4x/cpp/base/events/ConnectedEvent.h | 94 +- .../base/messages/DefaultPlcReadRequest.cpp | 288 +- .../cpp/base/messages/DefaultPlcReadRequest.h | 198 +- .../base/messages/DefaultPlcWriteRequest.cpp | 234 +- .../base/messages/DefaultPlcWriteRequest.h | 158 +- .../base/messages/InternalPlcFieldRequest.cpp | 84 +- .../base/messages/InternalPlcFieldRequest.h | 106 +- .../messages/InternalPlcFieldResponse.cpp | 78 +- .../base/messages/InternalPlcFieldResponse.h | 104 +- .../InternalPlcProprietaryRequest.cpp | 80 +- .../messages/InternalPlcProprietaryRequest.h | 102 +- .../InternalPlcProprietaryResponse.cpp | 80 +- .../messages/InternalPlcProprietaryResponse.h | 102 +- .../base/messages/InternalPlcReadRequest.cpp | 78 +- .../base/messages/InternalPlcReadRequest.h | 106 +- .../cpp/base/messages/InternalPlcRequest.cpp | 78 +- .../cpp/base/messages/InternalPlcRequest.h | 104 +- .../cpp/base/messages/InternalPlcResponse.cpp | 78 +- .../cpp/base/messages/InternalPlcResponse.h | 104 +- .../base/messages/InternalPlcWriteRequest.cpp | 78 +- .../base/messages/InternalPlcWriteRequest.h | 118 +- .../base/messages/PlcProprietaryRequest.cpp | 78 +- .../cpp/base/messages/PlcProprietaryRequest.h | 106 +- .../base/messages/PlcProprietaryResponse.cpp | 80 +- .../base/messages/PlcProprietaryResponse.h | 104 +- .../plc4x/cpp/base/messages/PlcReader.cpp | 78 +- .../plc4x/cpp/base/messages/PlcReader.h | 96 +- .../plc4x/cpp/base/messages/PlcWriter.cpp | 78 +- .../plc4x/cpp/base/messages/PlcWriter.h | 108 +- .../messages/items/BaseDefaultFieldItem.cpp | 86 +- .../messages/items/BaseDefaultFieldItem.h | 272 +- .../items/DefaultBigDecimalFieldItem.cpp | 392 +- .../items/DefaultBigDecimalFieldItem.h | 166 +- .../items/DefaultBigIntegerFieldItem.cpp | 402 +- .../items/DefaultBigIntegerFieldItem.h | 168 +- .../items/DefaultBooleanFieldItem.cpp | 378 +- .../messages/items/DefaultBooleanFieldItem.h | 160 +- .../items/DefaultByteArrayFieldItem.cpp | 392 +- .../items/DefaultByteArrayFieldItem.h | 160 +- .../messages/items/DefaultByteFieldItem.cpp | 390 +- .../messages/items/DefaultByteFieldItem.h | 160 +- .../messages/items/DefaultDoubleFieldItem.cpp | 392 +- .../messages/items/DefaultDoubleFieldItem.h | 160 +- .../messages/items/DefaultFloatFieldItem.cpp | 392 +- .../messages/items/DefaultFloatFieldItem.h | 160 +- .../items/DefaultIntegerFieldItem.cpp | 392 +- .../messages/items/DefaultIntegerFieldItem.h | 160 +- .../items/DefaultLocalDateFieldItem.cpp | 392 +- .../items/DefaultLocalDateFieldItem.h | 160 +- .../items/DefaultLocalDateTimeFieldItem.cpp | 190 +- .../items/DefaultLocalDateTimeFieldItem.h | 140 +- .../items/DefaultLocalTimeFieldItem.cpp | 190 +- .../items/DefaultLocalTimeFieldItem.h | 140 +- .../messages/items/DefaultLongFieldItem.cpp | 392 +- .../messages/items/DefaultLongFieldItem.h | 162 +- .../messages/items/DefaultShortFieldItem.cpp | 392 +- .../messages/items/DefaultShortFieldItem.h | 162 +- .../messages/items/DefaultStringFieldItem.cpp | 118 +- .../messages/items/DefaultStringFieldItem.h | 130 +- .../plc4x/cpp/s7/types/S7ControllerType.h | 128 +- sandbox/plc4cpp/utils/CMakeLists.txt | 44 +- sandbox/plc4cpp/utils/logger/CMakeLists.txt | 62 +- .../apache/plc4x/cpp/utils/logger/BLogger.cpp | 950 ++-- .../apache/plc4x/cpp/utils/logger/BLogger.h | 312 +- .../apache/plc4x/cpp/utils/logger/DatDmp.cpp | 286 +- .../apache/plc4x/cpp/utils/logger/DatDmp.h | 176 +- .../plc4x/cpp/utils/logger/DbgTrace.cpp | 104 +- .../apache/plc4x/cpp/utils/logger/DbgTrace.h | 108 +- .../plc4x/cpp/utils/logger/ErrorCategory.cpp | 142 +- .../plc4x/cpp/utils/logger/ErrorCategory.h | 248 +- .../cpp/utils/logger/ErrorInfoException.cpp | 342 +- .../cpp/utils/logger/ErrorInfoException.h | 164 +- .../apache/plc4x/cpp/utils/logger/ExLog.cpp | 286 +- .../org/apache/plc4x/cpp/utils/logger/ExLog.h | 142 +- .../plc4cpp/utils/systemconfig/CMakeLists.txt | 48 +- .../systemconfig/SystemConfiguration.cpp | 128 +- .../utils/systemconfig/SystemConfiguration.h | 138 +- sandbox/plc4net/.gitignore | 686 +-- sandbox/plc4net/api/PlcDriverManager.cs | 206 +- sandbox/plc4net/api/api.csproj | 54 +- sandbox/plc4net/api/api/IPlcConnection.cs | 176 +- sandbox/plc4net/api/api/IPlcDriver.cs | 112 +- .../api/authentication/IPlcAuthentication.cs | 56 +- .../PlcUsernamePasswordAuthentication.cs | 94 +- .../api/metadata/IPlcConnectionMetadata.cs | 76 +- .../api/exceptions/PlcConnectionException.cs | 98 +- .../plc4net/api/exceptions/PlcException.cs | 98 +- .../exceptions/PlcInvalidFieldException.cs | 90 +- .../plc4net/api/messages/IPlcFieldRequest.cs | 102 +- .../plc4net/api/messages/IPlcFieldResponse.cs | 96 +- sandbox/plc4net/api/messages/IPlcMessage.cs | 56 +- .../plc4net/api/messages/IPlcReadRequest.cs | 56 +- .../api/messages/IPlcReadRequestBuilder.cs | 68 +- .../plc4net/api/messages/IPlcReadResponse.cs | 56 +- sandbox/plc4net/api/messages/IPlcRequest.cs | 70 +- .../api/messages/IPlcRequestBuilder.cs | 66 +- sandbox/plc4net/api/messages/IPlcResponse.cs | 64 +- .../api/messages/IPlcSubscriptionEventArgs.cs | 68 +- .../api/messages/IPlcSubscriptionRequest.cs | 56 +- .../IPlcSubscriptionRequestBuilder.cs | 106 +- .../api/messages/IPlcSubscriptionResponse.cs | 82 +- .../api/messages/IPlcUnsubscriptionRequest.cs | 56 +- .../IPlcUnsubscriptionRequestBuilder.cs | 88 +- .../messages/IPlcUnsubscriptionResponse.cs | 56 +- .../plc4net/api/messages/IPlcWriteRequest.cs | 62 +- .../api/messages/IPlcWriteRequestBuilder.cs | 266 +- sandbox/plc4net/api/model/IPlcField.cs | 76 +- .../api/model/IPlcSubscriptionHandle.cs | 68 +- sandbox/plc4net/api/pom.xml | 142 +- sandbox/plc4net/api/types/PlcResponseCode.cs | 68 +- .../plc4net.driver/plc4net.driver.csproj | 58 +- sandbox/plc4net/plc4net.driver/pom.xml | 134 +- sandbox/plc4net/plc4net.sln | 88 +- sandbox/plc4net/pom.xml | 90 +- sandbox/plc4py/README.md | 116 +- sandbox/plc4py/pom.xml | 436 +- sandbox/plc4py/setup.py | 132 +- sandbox/plc4py/src/assembly/python.xml | 92 +- sandbox/plc4py/src/main/python/__init__.py | 34 +- .../plc4py/src/main/python/org/__init__.py | 34 +- .../src/main/python/org/apache/__init__.py | 34 +- .../python/org/apache/plc4x/InteropClient.py | 90 +- .../python/org/apache/plc4x/PlcConnection.py | 148 +- .../org/apache/plc4x/PlcDriverManager.py | 158 +- .../main/python/org/apache/plc4x/__init__.py | 34 +- .../plc4py/src/main/resources/lib/log4j2.xml | 62 +- sandbox/plc4py/src/test/python/__init__.py | 52 +- .../plc4py/src/test/python/org/__init__.py | 52 +- .../src/test/python/org/apache/__init__.py | 52 +- .../test/python/org/apache/plc4x/__init__.py | 34 +- .../org/apache/plc4x/test_PlcDriverManager.py | 284 +- sandbox/pom.xml | 150 +- sandbox/streampipes-connectors/READMME.adoc | 96 +- .../streampipes-connectors/env/development | 54 +- sandbox/streampipes-connectors/pom.xml | 398 +- .../streampipes/bacnetip/BacNetIpAdapter.java | 744 +-- .../bacnetip/config/ConfigKeys.java | 62 +- .../bacnetip/config/ConnectWorkerConfig.java | 166 +- sandbox/test-java-bacnetip-driver/pom.xml | 236 +- .../java/bacnetip/PassiveBacNetIpDriver.java | 152 +- .../connection/BacNetIpFieldHandler.java | 72 +- .../PassiveBacNetIpPlcConnection.java | 236 +- .../java/bacnetip/model/BacNetIpField.java | 94 +- .../bacnetip/protocol/BacNetIpProtocol.java | 124 +- .../bacnetip/protocol/HelloWorldProtocol.java | 144 +- .../org.apache.plc4x.java.spi.PlcDriver | 38 +- .../java/bacnetip/ManualBacNetDecoder.java | 70 +- .../bacnetip/PassiveBacNetIpDriverManual.java | 84 +- sandbox/test-java-df1-driver/README.adoc | 68 +- sandbox/test-java-df1-driver/pom.xml | 338 +- .../apache/plc4x/java/df1/DF1PlcDriver.java | 148 +- .../org/apache/plc4x/java/df1/Df1Field.java | 124 +- .../df1/connection/BaseDf1Connection.java | 68 +- .../df1/connection/SerialDf1Connection.java | 296 +- .../plc4x/java/df1/fields/DataType.java | 88 +- .../plc4x/java/df1/protocol/Df1Protocol.java | 314 +- .../java/df1/protocol/Plc4XDf1Protocol.java | 344 +- .../apache/plc4x/java/df1/util/DF1Utils.java | 316 +- .../plc4x/java/df1/util/Df1FieldHandler.java | 78 +- .../org.apache.plc4x.java.spi.PlcDriver | 38 +- .../plc4x/java/df1/DF1PlcDriverTest.java | 86 +- .../protocol/df1/BenchmarkGeneratedDf1.java | 162 +- .../protocol/df1/BenchmarkManualDf1.java | 478 +- .../apache/plc4x/protocol/df1/Df1Test.java | 60 +- .../plc4x/protocol/df1/EndToEndTest.java | 112 +- .../org/apache/plc4x/protocol/df1/IOTest.java | 198 +- .../test/resources/testsuite/Df1Testsuite.xml | 200 +- sandbox/test-java-knxnetip-driver/pom.xml | 232 +- .../apache/plc4x/java/knxnetip/IOTest.java | 204 +- .../plc4x/java/knxnetip/KNXNetIpTest.java | 60 +- .../resources/testsuite/KNXNetIPTestsuite.xml | 1086 ++-- sandbox/test-java-passive-s7-driver/pom.xml | 200 +- .../javapassive/s7/PassiveS7PlcDriver.java | 180 +- .../s7/connection/PassiveS7PlcConnection.java | 198 +- .../s7/protocol/HelloWorldProtocol.java | 96 +- .../s7/protocol/PassiveS7Protocol.java | 124 +- .../org.apache.plc4x.java.spi.PlcDriver | 38 +- .../java/BenchmarkGeneratedPassiveS7.java | 90 +- sandbox/test-java-s7-driver/pom.xml | 180 +- .../src/test/java/BenchmarkGeneratedS7.java | 142 +- src/main/script/prerequisiteCheck.groovy | 730 +-- src/remote-resources/NOTICE | 50 +- src/site/asciidoc/developers/building.adoc | 256 +- src/site/asciidoc/developers/ci.adoc | 124 +- .../asciidoc/developers/code-gen/index.adoc | 792 +-- .../code-gen/language/freemarker.adoc | 232 +- .../developers/code-gen/protocol/df1.adoc | 186 +- .../developers/code-gen/protocol/mspec.adoc | 702 +-- src/site/asciidoc/developers/conferences.adoc | 98 +- .../asciidoc/developers/contributing.adoc | 404 +- src/site/asciidoc/developers/decisions.adoc | 132 +- src/site/asciidoc/developers/issues.adoc | 38 +- src/site/asciidoc/developers/jqassistant.adoc | 252 +- src/site/asciidoc/developers/maturity.adoc | 152 +- src/site/asciidoc/developers/preparing.adoc | 788 +-- .../developers/release-build-tools.adoc | 920 +-- src/site/asciidoc/developers/release.adoc | 1036 ++-- src/site/asciidoc/developers/sonar.adoc | 38 +- src/site/asciidoc/developers/team.adoc | 110 +- src/site/asciidoc/developers/vm.adoc | 190 +- src/site/asciidoc/developers/vpn.adoc | 378 +- src/site/asciidoc/developers/website.adoc | 396 +- src/site/asciidoc/developers/wiki.adoc | 38 +- .../writing-driver/writing-driver.adoc | 112 +- src/site/asciidoc/index.adoc | 202 +- src/site/asciidoc/protocols/ab-eth/index.adoc | 64 +- src/site/asciidoc/protocols/ads/index.adoc | 50 +- .../asciidoc/protocols/delta-v/index.adoc | 394 +- .../asciidoc/protocols/delta-v/read-data.adoc | 3310 +++++------ .../delta-v/reverse-engineering.adoc | 502 +- .../asciidoc/protocols/ehtercat/index.adoc | 56 +- .../asciidoc/protocols/ethernet-ip/index.adoc | 60 +- src/site/asciidoc/protocols/features.adoc | 172 +- src/site/asciidoc/protocols/index.adoc | 98 +- src/site/asciidoc/protocols/modbus/index.adoc | 52 +- src/site/asciidoc/protocols/opc-ua/index.adoc | 56 +- src/site/asciidoc/protocols/s7/index.adoc | 578 +- .../asciidoc/protocols/s7/s7comm-plus.adoc | 74 +- src/site/asciidoc/protocols/s7/s7comm.adoc | 286 +- src/site/asciidoc/users/download.adoc | 266 +- src/site/asciidoc/users/gettingstarted.adoc | 46 +- src/site/asciidoc/users/industry40.adoc | 248 +- src/site/asciidoc/users/opm.adoc | 144 +- src/site/asciidoc/users/security.adoc | 50 +- src/site/asciidoc/users/testing.adoc | 328 +- src/site/resources-filtered/plc4x-doap.rdf | 224 +- .../css/bootstrap-responsive.min.css | 38 +- src/site/resources/css/site.css | 186 +- .../resources/images/apache_nifi_logo.svg | 36 +- src/site/resources/plc4x-pmc.rdf | 156 +- src/site/site.xml | 294 +- tools/README.md | 142 +- tools/boost/pom.xml | 284 +- tools/boost/src/assembly/bundle.xml | 78 +- tools/check_sigs.sh | 134 +- tools/clean-site.sh | 68 +- tools/common.sh | 404 +- tools/download_staged_release.sh | 274 +- tools/logstash/pom.xml | 210 +- tools/pom.xml | 110 +- tools/thrift/pom.xml | 676 +-- tools/thrift/src/assembly/compiler.xml | 84 +- tools/thrift/src/assembly/cpp.xml | 110 +- tools/thrift/src/assembly/python.xml | 84 +- vim.exe.stackdump | 36 +- 1522 files changed, 169448 insertions(+), 168886 deletions(-) create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/S7HEmbeddedChannelFactory.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/S7HProxy.java create mode 100644 plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/netty/S7HProxyHelper.java diff --git a/.dockerignore b/.dockerignore index 8e24f8bb909..cef3f4a9186 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,21 +1,21 @@ -# -# 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. -# - -Dockerfile -.dockerignore -.git/** +# +# 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. +# + +Dockerfile +.dockerignore +.git/** **/target/** \ No newline at end of file diff --git a/.editorconfig b/.editorconfig index df7383c37b0..a84ad446e94 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,31 +1,31 @@ -# -# 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. -# - -[*] -charset=utf-8 -end_of_line=lf -insert_final_newline=false -indent_style=space -indent_size=4 - -[{*.yml,*.yaml}] -indent_style=space -indent_size=2 - -[*.xml] -indent_style=space -indent_size=2 +# +# 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. +# + +[*] +charset=utf-8 +end_of_line=lf +insert_final_newline=false +indent_style=space +indent_size=4 + +[{*.yml,*.yaml}] +indent_style=space +indent_size=2 + +[*.xml] +indent_style=space +indent_size=2 diff --git a/.gitignore b/.gitignore index 124d53fa947..e7b7c185646 100644 --- a/.gitignore +++ b/.gitignore @@ -1,170 +1,170 @@ -# User-specific stuff: -.idea/** -*.iml -.vscode/** - -# Sensitive or high-churn files: -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.xml -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml - -# JIRA plugin -atlassian-ide-plugin.xml - -### Java template -# Compiled class file -*.class - -# Log file -*.log - -# Package Files # -*.jar -*.war -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* - -# Asciidoctor plugin -.asciidoctor - -### Maven template -target/ -pom.xml.tag -pom.xml.releaseBackup -pom.xml.versionsBackup -pom.xml.next -release.properties -dependency-reduced-pom.xml -buildNumber.properties -.mvn/timing.properties - -### Eclipse template -.metadata -*.tmp -*.bak -*.swp -*~.nib -local.properties -.settings/ -.loadpath -.recommenders -.project -.classpath - -# Locally stored "Eclipse launch configurations" -*.launch - -# STS (Spring Tool Suite) -.springBeans - -# Scala IDE specific (Scala & Java development for Eclipse) -.cache-main -.scala_dependencies -.worksheet - -# Emacs backup files -*~ -.scannerwork - -spock-reports - -# Other exclusions - -.DS_Store -elasticsearch-data/ -jqassistant/ - -# Exclude the C++ libs -plc4cpp/libs/libs/ -plc4cpp/.idea/ -plc4cpp/cmake-build-debug/ - - # Ignore VisualStudio related files -**/CMakeSettings.json -**/.vs/** - -# Exclude temporary python stuff -plc4py/venv/ -**/__pycache__/**/* -/plc4cpp/.vscode/ipch - -# Exclude gradle stuff -.gradle -/build/ - -# Ignore Gradle GUI config -gradle-app.setting - -# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) -!gradle-wrapper.jar - -# Cache of project -.gradletasknamecache - -# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 -# gradle/wrapper/gradle-wrapper.properties - -exclude ruby specifics: - -*.gem -*.rbc -/.config -/coverage/ -/InstalledFiles -/pkg/ -/spec/reports/ -/spec/examples.txt -/test/tmp/ -/test/version_tmp/ -/tmp/ - -# Used by dotenv library to load environment variables. -# .env - -# Ignore Byebug command history file. -.byebug_history - -## Specific to RubyMotion: -.dat* -.repl_history -build/ -*.bridgesupport -build-iPhoneOS/ -build-iPhoneSimulator/ - -## Specific to RubyMotion (use of CocoaPods): -# -# We recommend against adding the Pods directory to your .gitignore. However -# you should judge for yourself, the pros and cons are mentioned at: -# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control -# -# vendor/Pods/ - -## Documentation cache and generated files: -/.yardoc/ -/_yardoc/ -/doc/ -/rdoc/ - -## Environment normalization: -/.bundle/ -/vendor/bundle -/lib/bundler/man/ - -# for a library or gem, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# Gemfile.lock -# .ruby-version -# .ruby-gemset - -# unless supporting rvm < 1.11.0 or doing something fancy, ignore this: +# User-specific stuff: +.idea/** +*.iml +.vscode/** + +# Sensitive or high-churn files: +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.xml +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml + +# JIRA plugin +atlassian-ide-plugin.xml + +### Java template +# Compiled class file +*.class + +# Log file +*.log + +# Package Files # +*.jar +*.war +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +# Asciidoctor plugin +.asciidoctor + +### Maven template +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties + +### Eclipse template +.metadata +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.recommenders +.project +.classpath + +# Locally stored "Eclipse launch configurations" +*.launch + +# STS (Spring Tool Suite) +.springBeans + +# Scala IDE specific (Scala & Java development for Eclipse) +.cache-main +.scala_dependencies +.worksheet + +# Emacs backup files +*~ +.scannerwork + +spock-reports + +# Other exclusions + +.DS_Store +elasticsearch-data/ +jqassistant/ + +# Exclude the C++ libs +plc4cpp/libs/libs/ +plc4cpp/.idea/ +plc4cpp/cmake-build-debug/ + + # Ignore VisualStudio related files +**/CMakeSettings.json +**/.vs/** + +# Exclude temporary python stuff +plc4py/venv/ +**/__pycache__/**/* +/plc4cpp/.vscode/ipch + +# Exclude gradle stuff +.gradle +/build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Cache of project +.gradletasknamecache + +# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 +# gradle/wrapper/gradle-wrapper.properties + +exclude ruby specifics: + +*.gem +*.rbc +/.config +/coverage/ +/InstalledFiles +/pkg/ +/spec/reports/ +/spec/examples.txt +/test/tmp/ +/test/version_tmp/ +/tmp/ + +# Used by dotenv library to load environment variables. +# .env + +# Ignore Byebug command history file. +.byebug_history + +## Specific to RubyMotion: +.dat* +.repl_history +build/ +*.bridgesupport +build-iPhoneOS/ +build-iPhoneSimulator/ + +## Specific to RubyMotion (use of CocoaPods): +# +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# +# vendor/Pods/ + +## Documentation cache and generated files: +/.yardoc/ +/_yardoc/ +/doc/ +/rdoc/ + +## Environment normalization: +/.bundle/ +/vendor/bundle +/lib/bundler/man/ + +# for a library or gem, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# Gemfile.lock +# .ruby-version +# .ruby-gemset + +# unless supporting rvm < 1.11.0 or doing something fancy, ignore this: .rvmrc \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 64a03f04cbd..a191e41f564 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,48 +1,48 @@ -# -# 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. -# - -image: maven:3-jdk-8 - -# Asciidoctor requires some tools for generating the documentation -before_script: - - apt-get update - - apt-get install -y python-seqdiag python-nwdiag - -stages: - - build - - stage-site - -build: - stage: build - script: - - mvn clean package site site:stage - artifacts: - paths: - - target/staging - -# Have gitlab publish the content of the target/staging directory as gitlab pages website -# NOTE: Don't ask me why I have to rename it that way ... -pages: - stage: stage-site - script: - - mkdir public - - mv target/staging/* public/ - artifacts: - paths: - - public - only: - - master +# +# 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. +# + +image: maven:3-jdk-8 + +# Asciidoctor requires some tools for generating the documentation +before_script: + - apt-get update + - apt-get install -y python-seqdiag python-nwdiag + +stages: + - build + - stage-site + +build: + stage: build + script: + - mvn clean package site site:stage + artifacts: + paths: + - target/staging + +# Have gitlab publish the content of the target/staging directory as gitlab pages website +# NOTE: Don't ask me why I have to rename it that way ... +pages: + stage: stage-site + script: + - mkdir public + - mv target/staging/* public/ + artifacts: + paths: + - public + only: + - master diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index acf6e3fd534..a3572edef10 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -1,28 +1,28 @@ - - - - - + + + + + \ No newline at end of file diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java index a2fae998bed..de90d650419 100644 --- a/.mvn/wrapper/MavenWrapperDownloader.java +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -1,117 +1,117 @@ -/* - * Copyright 2007-present the original author or authors. - * - * Licensed 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. - */ -import java.net.*; -import java.io.*; -import java.nio.channels.*; -import java.util.Properties; - -public class MavenWrapperDownloader { - - private static final String WRAPPER_VERSION = "0.5.2"; - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" - + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if(mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if(mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if(!outputFile.getParentFile().exists()) { - if(!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { - String username = System.getenv("MVNW_USERNAME"); - char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); - Authenticator.setDefault(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(username, password); - } - }); - } - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} +/* + * Copyright 2007-present the original author or authors. + * + * Licensed 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. + */ +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.2"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if(mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if(mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if(!outputFile.getParentFile().exists()) { + if(!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index e8975771b15..7d74bae7716 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1,19 +1,19 @@ -# 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. - -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.2/maven-wrapper-0.5.2.jar +# 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. + +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.2/maven-wrapper-0.5.2.jar diff --git a/.travis.yml b/.travis.yml index 271456fc470..a386b9fe5bb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,30 +1,30 @@ -# -# 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. -# - -language: java - -env: - - MAVEN_OPTS="-Xms512m -Xmx512m" - -matrix: - fast_finish: true - -install: true - -script: - - jdk_switcher use oraclejdk8 - - mvn clean install site:site +# +# 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. +# + +language: java + +env: + - MAVEN_OPTS="-Xms512m -Xmx512m" + +matrix: + fast_finish: true + +install: true + +script: + - jdk_switcher use oraclejdk8 + - mvn clean install site:site diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 2c5316949dd..b8e11e93605 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -1,50 +1,50 @@ - -# Concepts (open for discussion) - -## Requirements - -- Maven >= 3.3.1 -- Java >= 8 - -## General - -- All modules should use only one primary build system -- It should be super-easy for new contributors to get started (A new contributor should be able to checkout and build with a core testsuite with a simple: 'mvn package' run) -- New code should only be accepted, if there are tests (Currently the java part of the build is configured to fail if the code coverage is below 90%) - -## Java Specific - -- Development should be done in Java 8 -- Providing Java 7 compatible versions should be possible by using the retrolambda plugin - - Usage of default implementations does cause more problems than it solves in this case. - -## IDE specific -- For formatting there is a .editorconfig defined. Intellij Idea come with a plugin for this pre-installed, for eclipse an installation is required (http://editorconfig.org/). -- Import organizing uses the Intellij Idea default: - - Import order - - all other imports - - blank - - import javax.* - - import java.* - - blank - - all other static imports - - Star imports - - number of imports needed for .* = 5 + +# Concepts (open for discussion) + +## Requirements + +- Maven >= 3.3.1 +- Java >= 8 + +## General + +- All modules should use only one primary build system +- It should be super-easy for new contributors to get started (A new contributor should be able to checkout and build with a core testsuite with a simple: 'mvn package' run) +- New code should only be accepted, if there are tests (Currently the java part of the build is configured to fail if the code coverage is below 90%) + +## Java Specific + +- Development should be done in Java 8 +- Providing Java 7 compatible versions should be possible by using the retrolambda plugin + - Usage of default implementations does cause more problems than it solves in this case. + +## IDE specific +- For formatting there is a .editorconfig defined. Intellij Idea come with a plugin for this pre-installed, for eclipse an installation is required (http://editorconfig.org/). +- Import organizing uses the Intellij Idea default: + - Import order + - all other imports + - blank + - import javax.* + - import java.* + - blank + - all other static imports + - Star imports + - number of imports needed for .* = 5 - number of static-imports needed for .* = 3 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 00a96bbc1be..871e17a0107 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,114 +1,114 @@ -# 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. - -########################################################################################## -# Build PLC4X -########################################################################################## - -# This is the image we'll use to execute the build (and give it the name 'build'). -# (This image is based on Ubuntu) -# Fixed version of this in order to have a fixed JDK version -FROM azul/zulu-openjdk:8.42.0.21 as build - -# Install some stuff we need to run the build -RUN apt update -y - -# Install general purpose tools -RUN apt install -y make libpcap-dev libc-dev - -# Requied for "with-boost" profile -RUN apt install -y bison flex gcc g++ - -# Required for "with-cpp" profile -RUN apt install -y gcc g++ - -# Required for "with-dotnet" profile -RUN apt install -y wget -RUN wget -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb -RUN dpkg -i packages-microsoft-prod.deb -RUN apt install -y software-properties-common -RUN add-apt-repository universe -y -RUN apt install -y apt-transport-https -RUN apt update -y -RUN apt install -y dotnet-sdk-2.2 - -# Required for the general build -RUN apt install -y git - -# Required for "with-proxies" -RUN apt install -y bison flex gcc g++ - -# Required for "with-python" profile -RUN apt install -y python-setuptools python - -# Copy the project into the docker container -COPY . /ws/ - -# Change the working directory (where commands are executed) into the new "ws" directory -WORKDIR /ws - -# Tell Maven to fetch all needed dependencies first, so they can get cached -# (Tried a patched version of the plugin to allow exclusion of inner artifacts. -# See https://issues.apache.org/jira/browse/MDEP-568 for details) -RUN ./mvnw -P with-sandbox,with-cpp,with-boost,with-dotnet,with-python,with-proxies,with-logstash com.offbytwo.maven.plugins:maven-dependency-plugin:3.1.1.MDEP568:go-offline -DexcludeGroupIds=org.apache.plc4x,org.apache.plc4x.examples,org.apache.plc4x.sandbox -# Build everything with all tests -RUN ./mvnw -P with-sandbox,with-cpp,with-boost,with-dotnet,with-python,with-proxies,with-logstash install - -# Get the version of the project and save it in a local file on the container -RUN ./mvnw org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=project.version -DforceStdout -q -pl . > project_version - -########################################################################################## -# Build a demo container -########################################################################################## - -# Move the file to a place we can reference it from without a version -RUN PROJECT_VERSION=`cat project_version`; mv plc4j/examples/hello-storage-elasticsearch/target/plc4j-hello-storage-elasticsearch-$PROJECT_VERSION-uber-jar.jar plc4xdemo.jar - -# Build a highly optimized JRE -FROM alpine:3.10 as packager - -# Install regular JDK -RUN apk update -RUN apk --no-cache add openjdk11-jdk openjdk11-jmods - -# build minimal JRE -ENV JAVA_MINIMAL="/opt/java-minimal" -RUN /usr/lib/jvm/java-11-openjdk/bin/jlink \ - --verbose \ - --add-modules \ - java.base,java.sql,java.naming,java.desktop,java.management,java.security.jgss,java.instrument \ - --compress 2 --strip-debug --no-header-files --no-man-pages \ - --release-info="add:IMPLEMENTOR=radistao:IMPLEMENTOR_VERSION=radistao_JRE" \ - --output "$JAVA_MINIMAL" - -# Now create an actuall deployment container -FROM alpine:3.10 - -# Install our optimized JRE -ENV JAVA_HOME=/opt/java-minimal -ENV PATH="$PATH:$JAVA_HOME/bin" -COPY --from=packager "$JAVA_HOME" "$JAVA_HOME" - -# Prepare the demo by copying the example artifact from the 'build' container into this new one. -COPY --from=build /ws/plc4xdemo.jar /plc4xdemo.jar - -# Let runtime know which ports we will be listening on -EXPOSE 9200 9300 - -# Allow for extra options to be passed to the jar using PLC4X_OPTIONS env variable -ENV PLC4X_OPTIONS "" - -# This will be executed as soon as the container is started. -ENTRYPOINT ["sh", "-c", "[ -f /run/plc4xdemo.env ] && . /run/plc4xdemo.env ; java -jar /plc4xdemo.jar $PLC4X_OPTIONS"] +# 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. + +########################################################################################## +# Build PLC4X +########################################################################################## + +# This is the image we'll use to execute the build (and give it the name 'build'). +# (This image is based on Ubuntu) +# Fixed version of this in order to have a fixed JDK version +FROM azul/zulu-openjdk:8.42.0.21 as build + +# Install some stuff we need to run the build +RUN apt update -y + +# Install general purpose tools +RUN apt install -y make libpcap-dev libc-dev + +# Requied for "with-boost" profile +RUN apt install -y bison flex gcc g++ + +# Required for "with-cpp" profile +RUN apt install -y gcc g++ + +# Required for "with-dotnet" profile +RUN apt install -y wget +RUN wget -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb +RUN dpkg -i packages-microsoft-prod.deb +RUN apt install -y software-properties-common +RUN add-apt-repository universe -y +RUN apt install -y apt-transport-https +RUN apt update -y +RUN apt install -y dotnet-sdk-2.2 + +# Required for the general build +RUN apt install -y git + +# Required for "with-proxies" +RUN apt install -y bison flex gcc g++ + +# Required for "with-python" profile +RUN apt install -y python-setuptools python + +# Copy the project into the docker container +COPY . /ws/ + +# Change the working directory (where commands are executed) into the new "ws" directory +WORKDIR /ws + +# Tell Maven to fetch all needed dependencies first, so they can get cached +# (Tried a patched version of the plugin to allow exclusion of inner artifacts. +# See https://issues.apache.org/jira/browse/MDEP-568 for details) +RUN ./mvnw -P with-sandbox,with-cpp,with-boost,with-dotnet,with-python,with-proxies,with-logstash com.offbytwo.maven.plugins:maven-dependency-plugin:3.1.1.MDEP568:go-offline -DexcludeGroupIds=org.apache.plc4x,org.apache.plc4x.examples,org.apache.plc4x.sandbox +# Build everything with all tests +RUN ./mvnw -P with-sandbox,with-cpp,with-boost,with-dotnet,with-python,with-proxies,with-logstash install + +# Get the version of the project and save it in a local file on the container +RUN ./mvnw org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=project.version -DforceStdout -q -pl . > project_version + +########################################################################################## +# Build a demo container +########################################################################################## + +# Move the file to a place we can reference it from without a version +RUN PROJECT_VERSION=`cat project_version`; mv plc4j/examples/hello-storage-elasticsearch/target/plc4j-hello-storage-elasticsearch-$PROJECT_VERSION-uber-jar.jar plc4xdemo.jar + +# Build a highly optimized JRE +FROM alpine:3.10 as packager + +# Install regular JDK +RUN apk update +RUN apk --no-cache add openjdk11-jdk openjdk11-jmods + +# build minimal JRE +ENV JAVA_MINIMAL="/opt/java-minimal" +RUN /usr/lib/jvm/java-11-openjdk/bin/jlink \ + --verbose \ + --add-modules \ + java.base,java.sql,java.naming,java.desktop,java.management,java.security.jgss,java.instrument \ + --compress 2 --strip-debug --no-header-files --no-man-pages \ + --release-info="add:IMPLEMENTOR=radistao:IMPLEMENTOR_VERSION=radistao_JRE" \ + --output "$JAVA_MINIMAL" + +# Now create an actuall deployment container +FROM alpine:3.10 + +# Install our optimized JRE +ENV JAVA_HOME=/opt/java-minimal +ENV PATH="$PATH:$JAVA_HOME/bin" +COPY --from=packager "$JAVA_HOME" "$JAVA_HOME" + +# Prepare the demo by copying the example artifact from the 'build' container into this new one. +COPY --from=build /ws/plc4xdemo.jar /plc4xdemo.jar + +# Let runtime know which ports we will be listening on +EXPOSE 9200 9300 + +# Allow for extra options to be passed to the jar using PLC4X_OPTIONS env variable +ENV PLC4X_OPTIONS "" + +# This will be executed as soon as the container is started. +ENTRYPOINT ["sh", "-c", "[ -f /run/plc4xdemo.env ] && . /run/plc4xdemo.env ; java -jar /plc4xdemo.jar $PLC4X_OPTIONS"] diff --git a/Jenkinsfile b/Jenkinsfile index 989f0114e28..2f5fbc2a805 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,309 +1,309 @@ -#!groovy - -/* - * - * 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. - * - */ -pipeline { - - agent { - node { - label 'plc4x' - } - } - - environment { - // It seems the login the jenkins slave uses, doesn't pick up the environment changes, - // so we have to try to manually add theme here. - MAVEN_HOME = '/opt/maven' - PATH = "${MAVEN_HOME}/bin:${env.PATH}" - - PLC4X_BUILD_ON_JENKINS = true - JENKINS_PROFILE = 'jenkins-build' - // On non develop build we don't want to pollute the global m2 repo - MVN_LOCAL_REPO_OPT = '-Dmaven.repo.local=.repository' - // Test failures will be handled by the jenkins junit steps and mark the build as unstable. - MVN_TEST_FAIL_IGNORE = '-Dmaven.test.failure.ignore=true' - - SONARCLOUD_PARAMS = "-Dsonar.host.url=https://sonarcloud.io -Dsonar.organization=apache -Dsonar.projectKey=apache_plc4x -Dsonar.branch.name=develop" - } - - tools { - maven 'Maven 3 (latest)' - jdk 'JDK 1.8 (latest)' - } - - options { - // Kill this job after one hour. - timeout(time: 24, unit: 'HOURS') - // When we have test-fails e.g. we don't need to run the remaining steps - skipStagesAfterUnstable() - buildDiscarder(logRotator(numToKeepStr: '5', artifactNumToKeepStr: '3')) - } - - stages { - stage('Initialization') { - steps { - echo 'Building Branch: ' + env.BRANCH_NAME - echo 'Using PATH = ' + env.PATH - } - } - - stage('Cleanup') { - steps { - echo 'Cleaning up the workspace' - deleteDir() - } - } - - stage('Checkout') { - steps { - echo 'Checking out branch ' + env.BRANCH_NAME - checkout scm - } - } - - stage('Build') { - when { - expression { - env.BRANCH_NAME != 'develop' - } - } - steps { - echo 'Building' - //sh 'mvn -P${JENKINS_PROFILE},skip-prerequisite-check,development,with-sandbox,with-cpp,with-boost,with-dotnet,with-python,with-proxies,with-logstash ${MVN_TEST_FAIL_IGNORE} ${MVN_LOCAL_REPO_OPT} clean install' - sh 'mvn -P${JENKINS_PROFILE},skip-prerequisite-check,development,with-sandbox,with-logstash ${MVN_TEST_FAIL_IGNORE} ${MVN_LOCAL_REPO_OPT} clean install' - } - post { - always { - junit(testResults: '**/surefire-reports/*.xml', allowEmptyResults: true) - junit(testResults: '**/failsafe-reports/*.xml', allowEmptyResults: true) - } - } - } - - stage('Build develop') { - when { - branch 'develop' - } - steps { - echo 'Building' - // Clean up the snapshots directory. - dir("local-snapshots-dir/") { - deleteDir() - } - - // We'll deploy to a relative directory so we can save - // that and deploy in a later step on a different node - //sh 'mvn -U -P${JENKINS_PROFILE},skip-prerequisite-check,development,with-sandbox,with-cpp,with-boost,with-dotnet,with-python,with-proxies,with-logstash ${MVN_TEST_FAIL_IGNORE} ${JQASSISTANT_NEO4J_VERSION} -DaltDeploymentRepository=snapshot-repo::default::file:./local-snapshots-dir clean deploy' - sh 'mvn -U -P${JENKINS_PROFILE},skip-prerequisite-check,development,with-sandbox,with-logstash ${MVN_TEST_FAIL_IGNORE} ${JQASSISTANT_NEO4J_VERSION} -DaltDeploymentRepository=snapshot-repo::default::file:./local-snapshots-dir clean deploy' - - // Stash the build results so we can deploy them on another node - stash name: 'plc4x-build-snapshots', includes: 'local-snapshots-dir/**' - } - post { - always { - junit(testResults: '**/surefire-reports/*.xml', allowEmptyResults: true) - junit(testResults: '**/failsafe-reports/*.xml', allowEmptyResults: true) - } - } - } - - stage('Code Quality') { - when { - branch 'develop' - } - steps { - echo 'Checking Code Quality on SonarCloud' - withCredentials([string(credentialsId: 'chris-sonarcloud-token', variable: 'SONAR_TOKEN')]) { - //sh 'mvn -P${JENKINS_PROFILE},skip-prerequisite-check,with-python,with-proxies,with-sandbox,with-logstash sonar:sonar ${SONARCLOUD_PARAMS} -Dsonar.login=${SONAR_TOKEN}' - sh 'mvn -P${JENKINS_PROFILE},skip-prerequisite-check,with-sandbox,with-logstash sonar:sonar ${SONARCLOUD_PARAMS} -Dsonar.login=${SONAR_TOKEN}' - } - } - } - - stage('Deploy') { - when { - branch 'develop' - } - // Only the official build nodes have the credentials to deploy setup. - agent { - node { - label 'nexus-deploy' - } - } - steps { - echo 'Deploying' - // Clean up the snapshots directory. - dir("local-snapshots-dir/") { - deleteDir() - } - - // Unstash the previously stashed build results. - unstash name: 'plc4x-build-snapshots' - - // Deploy the artifacts using the wagon-maven-plugin. - sh 'mvn -f jenkins.pom -X -P deploy-snapshots wagon:upload' - - // Clean up the snapshots directory (freeing up more space after deploying). - dir("local-snapshots-dir/") { - deleteDir() - } - } - } - - stage('Build site') { - when { - branch 'develop' - } - steps { - echo 'Building Site' - //sh 'mvn -P${JENKINS_PROFILE},skip-prerequisite-check,with-proxies,with-logstash site' - sh 'mvn -P${JENKINS_PROFILE},skip-prerequisite-check,with-logstash site' - } - } - - stage('Stage site') { - when { - branch 'develop' - } - steps { - echo 'Staging Site' - // Build a directory containing the aggregated website. - //sh 'mvn -P${JENKINS_PROFILE},skip-prerequisite-check,with-proxies,with-logstash site:stage' - sh 'mvn -P${JENKINS_PROFILE},skip-prerequisite-check,with-logstash site:stage' - // Make sure the script is executable. - sh 'chmod +x tools/clean-site.sh' - // Remove some redundant resources, which shouldn't be required. - sh 'tools/clean-site.sh' - // Stash the generated site so we can publish it on the 'git-website' node. - stash includes: 'target/staging/**/*', name: 'plc4x-site' - } - } - - stage('Deploy site') { - when { - branch 'develop' - } - // Only the nodes labeled 'git-websites' have the credentials to commit to the. - agent { - node { - label 'git-websites' - } - } - steps { - echo 'Deploying Site' - // Clean up the site directory. - dir("target/staging") { - deleteDir() - } - - // Unstash the previously stashed site. - unstash 'plc4x-site' - // Publish the site with the scm-publish plugin. - sh 'mvn -f jenkins.pom -X -P deploy-site scm-publish:publish-scm' - - // Clean up the snapshots directory (freeing up more space after deploying). - dir("target/staging") { - deleteDir() - } - } - } - } - - // Send out notifications on unsuccessful builds. - post { - // If this build failed, send an email to the list. - failure { - script { - if(env.BRANCH_NAME == "develop") { - emailext( - subject: "[BUILD-FAILURE]: Job '${env.JOB_NAME} [${env.BRANCH_NAME}] [${env.BUILD_NUMBER}]'", - body: """ -BUILD-FAILURE: Job '${env.JOB_NAME} [${env.BRANCH_NAME}] [${env.BUILD_NUMBER}]': - -Check console output at "${env.JOB_NAME} [${env.BRANCH_NAME}] [${env.BUILD_NUMBER}]" -""", - to: "dev@plc4x.apache.org", - recipientProviders: [[$class: 'DevelopersRecipientProvider']] - ) - } - } - } - - // If this build didn't fail, but there were failing tests, send an email to the list. - unstable { - script { - if(env.BRANCH_NAME == "develop") { - emailext( - subject: "[BUILD-UNSTABLE]: Job '${env.JOB_NAME} [${env.BRANCH_NAME}] [${env.BUILD_NUMBER}]'", - body: """ -BUILD-UNSTABLE: Job '${env.JOB_NAME} [${env.BRANCH_NAME}] [${env.BUILD_NUMBER}]': - -Check console output at "${env.JOB_NAME} [${env.BRANCH_NAME}] [${env.BUILD_NUMBER}]" -""", - to: "dev@plc4x.apache.org", - recipientProviders: [[$class: 'DevelopersRecipientProvider']] - ) - } - } - } - - // Send an email, if the last build was not successful and this one is. - success { - // Cleanup the build directory if the build was successful - // (in this cae we probably don't have to do any post-build analysis) - deleteDir() - script { - if ((env.BRANCH_NAME == "develop") && (currentBuild.previousBuild != null) && (currentBuild.previousBuild.result != 'SUCCESS')) { - emailext ( - subject: "[BUILD-STABLE]: Job '${env.JOB_NAME} [${env.BRANCH_NAME}] [${env.BUILD_NUMBER}]'", - body: """ -BUILD-STABLE: Job '${env.JOB_NAME} [${env.BRANCH_NAME}] [${env.BUILD_NUMBER}]': - -Is back to normal. -""", - to: "dev@plc4x.apache.org", - recipientProviders: [[$class: 'DevelopersRecipientProvider']] - ) - } - } - } - - always { - script { - if(env.BRANCH_NAME == "master") { - // Double check if something was really changed as sometimes the - // build just runs without any changes. - if(currentBuild.changeSets.size() > 0) { - emailext( - subject: "[COMMIT-TO-MASTER]: A commit to the master branch was made'", - body: """ -COMMIT-TO-MASTER: A commit to the master branch was made: - -Check console output at "${env.JOB_NAME} [${env.BRANCH_NAME}] [${env.BUILD_NUMBER}]" -""", - to: "dev@plc4x.apache.org", - recipientProviders: [[$class: 'DevelopersRecipientProvider']] - ) - } - } - } - } - } - -} +#!groovy + +/* + * + * 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. + * + */ +pipeline { + + agent { + node { + label 'plc4x' + } + } + + environment { + // It seems the login the jenkins slave uses, doesn't pick up the environment changes, + // so we have to try to manually add theme here. + MAVEN_HOME = '/opt/maven' + PATH = "${MAVEN_HOME}/bin:${env.PATH}" + + PLC4X_BUILD_ON_JENKINS = true + JENKINS_PROFILE = 'jenkins-build' + // On non develop build we don't want to pollute the global m2 repo + MVN_LOCAL_REPO_OPT = '-Dmaven.repo.local=.repository' + // Test failures will be handled by the jenkins junit steps and mark the build as unstable. + MVN_TEST_FAIL_IGNORE = '-Dmaven.test.failure.ignore=true' + + SONARCLOUD_PARAMS = "-Dsonar.host.url=https://sonarcloud.io -Dsonar.organization=apache -Dsonar.projectKey=apache_plc4x -Dsonar.branch.name=develop" + } + + tools { + maven 'Maven 3 (latest)' + jdk 'JDK 1.8 (latest)' + } + + options { + // Kill this job after one hour. + timeout(time: 24, unit: 'HOURS') + // When we have test-fails e.g. we don't need to run the remaining steps + skipStagesAfterUnstable() + buildDiscarder(logRotator(numToKeepStr: '5', artifactNumToKeepStr: '3')) + } + + stages { + stage('Initialization') { + steps { + echo 'Building Branch: ' + env.BRANCH_NAME + echo 'Using PATH = ' + env.PATH + } + } + + stage('Cleanup') { + steps { + echo 'Cleaning up the workspace' + deleteDir() + } + } + + stage('Checkout') { + steps { + echo 'Checking out branch ' + env.BRANCH_NAME + checkout scm + } + } + + stage('Build') { + when { + expression { + env.BRANCH_NAME != 'develop' + } + } + steps { + echo 'Building' + //sh 'mvn -P${JENKINS_PROFILE},skip-prerequisite-check,development,with-sandbox,with-cpp,with-boost,with-dotnet,with-python,with-proxies,with-logstash ${MVN_TEST_FAIL_IGNORE} ${MVN_LOCAL_REPO_OPT} clean install' + sh 'mvn -P${JENKINS_PROFILE},skip-prerequisite-check,development,with-sandbox,with-logstash ${MVN_TEST_FAIL_IGNORE} ${MVN_LOCAL_REPO_OPT} clean install' + } + post { + always { + junit(testResults: '**/surefire-reports/*.xml', allowEmptyResults: true) + junit(testResults: '**/failsafe-reports/*.xml', allowEmptyResults: true) + } + } + } + + stage('Build develop') { + when { + branch 'develop' + } + steps { + echo 'Building' + // Clean up the snapshots directory. + dir("local-snapshots-dir/") { + deleteDir() + } + + // We'll deploy to a relative directory so we can save + // that and deploy in a later step on a different node + //sh 'mvn -U -P${JENKINS_PROFILE},skip-prerequisite-check,development,with-sandbox,with-cpp,with-boost,with-dotnet,with-python,with-proxies,with-logstash ${MVN_TEST_FAIL_IGNORE} ${JQASSISTANT_NEO4J_VERSION} -DaltDeploymentRepository=snapshot-repo::default::file:./local-snapshots-dir clean deploy' + sh 'mvn -U -P${JENKINS_PROFILE},skip-prerequisite-check,development,with-sandbox,with-logstash ${MVN_TEST_FAIL_IGNORE} ${JQASSISTANT_NEO4J_VERSION} -DaltDeploymentRepository=snapshot-repo::default::file:./local-snapshots-dir clean deploy' + + // Stash the build results so we can deploy them on another node + stash name: 'plc4x-build-snapshots', includes: 'local-snapshots-dir/**' + } + post { + always { + junit(testResults: '**/surefire-reports/*.xml', allowEmptyResults: true) + junit(testResults: '**/failsafe-reports/*.xml', allowEmptyResults: true) + } + } + } + + stage('Code Quality') { + when { + branch 'develop' + } + steps { + echo 'Checking Code Quality on SonarCloud' + withCredentials([string(credentialsId: 'chris-sonarcloud-token', variable: 'SONAR_TOKEN')]) { + //sh 'mvn -P${JENKINS_PROFILE},skip-prerequisite-check,with-python,with-proxies,with-sandbox,with-logstash sonar:sonar ${SONARCLOUD_PARAMS} -Dsonar.login=${SONAR_TOKEN}' + sh 'mvn -P${JENKINS_PROFILE},skip-prerequisite-check,with-sandbox,with-logstash sonar:sonar ${SONARCLOUD_PARAMS} -Dsonar.login=${SONAR_TOKEN}' + } + } + } + + stage('Deploy') { + when { + branch 'develop' + } + // Only the official build nodes have the credentials to deploy setup. + agent { + node { + label 'nexus-deploy' + } + } + steps { + echo 'Deploying' + // Clean up the snapshots directory. + dir("local-snapshots-dir/") { + deleteDir() + } + + // Unstash the previously stashed build results. + unstash name: 'plc4x-build-snapshots' + + // Deploy the artifacts using the wagon-maven-plugin. + sh 'mvn -f jenkins.pom -X -P deploy-snapshots wagon:upload' + + // Clean up the snapshots directory (freeing up more space after deploying). + dir("local-snapshots-dir/") { + deleteDir() + } + } + } + + stage('Build site') { + when { + branch 'develop' + } + steps { + echo 'Building Site' + //sh 'mvn -P${JENKINS_PROFILE},skip-prerequisite-check,with-proxies,with-logstash site' + sh 'mvn -P${JENKINS_PROFILE},skip-prerequisite-check,with-logstash site' + } + } + + stage('Stage site') { + when { + branch 'develop' + } + steps { + echo 'Staging Site' + // Build a directory containing the aggregated website. + //sh 'mvn -P${JENKINS_PROFILE},skip-prerequisite-check,with-proxies,with-logstash site:stage' + sh 'mvn -P${JENKINS_PROFILE},skip-prerequisite-check,with-logstash site:stage' + // Make sure the script is executable. + sh 'chmod +x tools/clean-site.sh' + // Remove some redundant resources, which shouldn't be required. + sh 'tools/clean-site.sh' + // Stash the generated site so we can publish it on the 'git-website' node. + stash includes: 'target/staging/**/*', name: 'plc4x-site' + } + } + + stage('Deploy site') { + when { + branch 'develop' + } + // Only the nodes labeled 'git-websites' have the credentials to commit to the. + agent { + node { + label 'git-websites' + } + } + steps { + echo 'Deploying Site' + // Clean up the site directory. + dir("target/staging") { + deleteDir() + } + + // Unstash the previously stashed site. + unstash 'plc4x-site' + // Publish the site with the scm-publish plugin. + sh 'mvn -f jenkins.pom -X -P deploy-site scm-publish:publish-scm' + + // Clean up the snapshots directory (freeing up more space after deploying). + dir("target/staging") { + deleteDir() + } + } + } + } + + // Send out notifications on unsuccessful builds. + post { + // If this build failed, send an email to the list. + failure { + script { + if(env.BRANCH_NAME == "develop") { + emailext( + subject: "[BUILD-FAILURE]: Job '${env.JOB_NAME} [${env.BRANCH_NAME}] [${env.BUILD_NUMBER}]'", + body: """ +BUILD-FAILURE: Job '${env.JOB_NAME} [${env.BRANCH_NAME}] [${env.BUILD_NUMBER}]': + +Check console output at "${env.JOB_NAME} [${env.BRANCH_NAME}] [${env.BUILD_NUMBER}]" +""", + to: "dev@plc4x.apache.org", + recipientProviders: [[$class: 'DevelopersRecipientProvider']] + ) + } + } + } + + // If this build didn't fail, but there were failing tests, send an email to the list. + unstable { + script { + if(env.BRANCH_NAME == "develop") { + emailext( + subject: "[BUILD-UNSTABLE]: Job '${env.JOB_NAME} [${env.BRANCH_NAME}] [${env.BUILD_NUMBER}]'", + body: """ +BUILD-UNSTABLE: Job '${env.JOB_NAME} [${env.BRANCH_NAME}] [${env.BUILD_NUMBER}]': + +Check console output at "${env.JOB_NAME} [${env.BRANCH_NAME}] [${env.BUILD_NUMBER}]" +""", + to: "dev@plc4x.apache.org", + recipientProviders: [[$class: 'DevelopersRecipientProvider']] + ) + } + } + } + + // Send an email, if the last build was not successful and this one is. + success { + // Cleanup the build directory if the build was successful + // (in this cae we probably don't have to do any post-build analysis) + deleteDir() + script { + if ((env.BRANCH_NAME == "develop") && (currentBuild.previousBuild != null) && (currentBuild.previousBuild.result != 'SUCCESS')) { + emailext ( + subject: "[BUILD-STABLE]: Job '${env.JOB_NAME} [${env.BRANCH_NAME}] [${env.BUILD_NUMBER}]'", + body: """ +BUILD-STABLE: Job '${env.JOB_NAME} [${env.BRANCH_NAME}] [${env.BUILD_NUMBER}]': + +Is back to normal. +""", + to: "dev@plc4x.apache.org", + recipientProviders: [[$class: 'DevelopersRecipientProvider']] + ) + } + } + } + + always { + script { + if(env.BRANCH_NAME == "master") { + // Double check if something was really changed as sometimes the + // build just runs without any changes. + if(currentBuild.changeSets.size() > 0) { + emailext( + subject: "[COMMIT-TO-MASTER]: A commit to the master branch was made'", + body: """ +COMMIT-TO-MASTER: A commit to the master branch was made: + +Check console output at "${env.JOB_NAME} [${env.BRANCH_NAME}] [${env.BUILD_NUMBER}]" +""", + to: "dev@plc4x.apache.org", + recipientProviders: [[$class: 'DevelopersRecipientProvider']] + ) + } + } + } + } + } + +} diff --git a/LICENSE b/LICENSE index 033d5d4c161..1495f33117a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,222 +1,222 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. - -=============================================================== - -The files: -plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/attic/RawEthernetSocket.java -plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/attic/RawIpSocket.java -plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/attic/RawSocketListener.java -Are copyrighted by the The Netty Project which is distributed under the Apache 2.0 license. - -The files: -.mvn/wrapper/MavenWrapperDownloader.java -mvnw -mvnw.cmd -Are provided from the Github Project: https://github.com/takari/maven-wrapper -which is distributed under the Apache 2.0 license. - -The file: -build-utils/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/plugins/codegenerator/language/mspec/expression/Expression.g4 -is licensed under the Category A: "UNLICENSE" which is available here: -UNLICENSE file in the licenses directory. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. + +=============================================================== + +The files: +plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/attic/RawEthernetSocket.java +plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/attic/RawIpSocket.java +plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/attic/RawSocketListener.java +Are copyrighted by the The Netty Project which is distributed under the Apache 2.0 license. + +The files: +.mvn/wrapper/MavenWrapperDownloader.java +mvnw +mvnw.cmd +Are provided from the Github Project: https://github.com/takari/maven-wrapper +which is distributed under the Apache 2.0 license. + +The file: +build-utils/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/plugins/codegenerator/language/mspec/expression/Expression.g4 +is licensed under the Category A: "UNLICENSE" which is available here: +UNLICENSE file in the licenses directory. diff --git a/NOTICE b/NOTICE index 6ff3737bfe3..30bbeb42320 100644 --- a/NOTICE +++ b/NOTICE @@ -1,13 +1,13 @@ -Apache PLC4X -Copyright 2017-2019 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). - ----------------------------------------------- - -This product includes software developed at -The Netty project (https://netty.io/). - -This product includes software developed at -The Milo project (https://github.com/eclipse/milo). +Apache PLC4X +Copyright 2017-2019 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +---------------------------------------------- + +This product includes software developed at +The Netty project (https://netty.io/). + +This product includes software developed at +The Milo project (https://github.com/eclipse/milo). diff --git a/README.md b/README.md index 80504de21d6..4c4f85ecf69 100644 --- a/README.md +++ b/README.md @@ -1,280 +1,280 @@ - -[![Maven central](https://img.shields.io/maven-central/v/org.apache.plc4x/plc4j-api.svg)](https://img.shields.io/maven-central/v/org.apache.plc4x/plc4j-api.svg) -[![License](https://img.shields.io/github/license/apache/plc4x.svg)](http://www.apache.org/licenses/LICENSE-2.0) -[![Last commit](https://img.shields.io/github/last-commit/apache/plc4x.svg)]() -[![Twitter](https://img.shields.io/twitter/follow/ApachePLC4X.svg?label=Follow&style=social)](https://twitter.com/ApachePLC4X) - - -

-
- Apache PLC4X Logo -
-

-

The Industrial IoT adapter

-

The ultimate goal of PLC4X is to create a set of libraries, that allow unified access to any type of - PLC

- -*** - -# Table of contents - - * [About PLC4X](#about-apache-plc4x) - * [Getting Started](#getting-started) - * [Developers](#developers) - * [Community](#community) - * [Contributing](#contributing) - * [Licensing](#licensing) - -*** - -## About Apache PLC4X - -Apache PLC4X is an effort to create a set of libraries for communicating with industrial grade programmable logic controllers (PLCs) in a uniform way. -We are planning on shipping libraries for usage in: - -1. Java -2. C/C++ (not ready for usage) -3. C# (.Net) (not ready for usage) -4. Python (not ready for usage) - -PLC4X also integrates with other Apache projects, such as: - -* [Apache Calcite](https://calcite.apache.org/) -* [Apache Camel](https://camel.apache.org/) -* [Apache Edgent](https://edgent.apache.org/) -* [Apache Kafka-Connect](https://kafka.apache.org) -* [Apache Karaf](https://karaf.apache.org/) -* [Apache NiFi](https://nifi.apache.org/) - -## Getting started - -Depending on the programming language, the usage will differ, therefore please go to the -[Getting Started](https://plc4x.apache.org/users/gettingstarted.html) on the PLC4X website to look up -the language of choice. - -### Java - -See the PLC4J user guide on the website to start using PLC4X in your Java application: -[https://plc4x.apache.org/plc4j/users/gettingstarted.html](https://plc4x.apache.org/plc4j/users/gettingstarted.html) - -## Developers - -### Environment - -Currently the project is configured to require the following software: - -1. Java 8 JDK: For running Maven in general as well as compiling the Java and Scala modules `JAVA_HOME` configured to - point to that. -2. libpcap/WinPcap for raw socket tests in Java or use of `passive-mode` drivers -3. (Optional) Graphwiz: For generating the graphs in the documentation (http://www.graphviz.org/) -4. Git (even when working on the source distribution) - -With this setup you will be able to build the Java part of PLC4X excluding the "proxy" drivers and servers. -For a full build of PLC4X with all options the following has to be provided: - -#### Linux - -On a clean Ubuntu 18.04 the following software needs to be installed: - -``` - sudo apt install python-setuptools gcc g++ make libpcap-dev -``` - -If you're building a source-distribution and haven't installed git yet, be sure to do so: - -``` - sudo get install git -``` - -In order to build the .Net version, please install the .Net package according to this guide: - -https://dev.to/carlos487/installing-dotnet-core-in-ubuntu-1804-7lp - -#### Mac - -Make sure `Homebrew` ist installed in order to update `Bison` to a newer version (the version 2.3 installed per default is too old) - -``` - /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" -``` - -Then update `Bison`: - -``` - brew install bison - brew link bison --force - echo 'export PATH="/usr/local/opt/bison/bin:$PATH"' >> ~/.bash_profile -``` - -Install `Python 2.7`: - -``` - brew install python@2 -``` - -Be sure to re-open the command window or the changes will not apply. - -If you're going to build the `with-dotnet` profile you also need to install DotNet. -Please download it from: https://dotnet.microsoft.com/download and run the installer. - -LibPCAP is also installed via Homebrew: - -``` - brew install libpcap -``` - -#### Windows - -Some tools need to be installed before being able to build on Windows: - -* WinBuilds (for `with-cpp`, `with-proxies` profiles) -* Bison (for `with-cpp` profiles) -* Flex (for `with-cpp` profiles) -* Python 2.7 (for `with-python`, `with-proxies` profiles) -* Dotnet (for `with-dotnet` profiles) -* WinPCAP -* OpenSSL - -He have tested `WinBuilds` with the bundle of: http://win-builds.org/doku.php/download_and_installation_from_windows -Run the installer as "Administrator" or you won't be able to install it to "C:\Program Files" or the 32 Bit counterpart. -When running the installer, make sure to select the options: -* Native Windows -* x86_64 -Not quite sure which elements are really needed, better just install all of them. -If the installer fails to do something complaining about having to use a different mirror, enter "http://win-builds.org/1.5.0" as mirror address. - -WARNING: If you don't use the installer version of the distribution. The build will probably fail and it will be pretty -impossible to see the problem. When manually executing the command, a popup will appear complaining about not being able -to find some DLL. So if you are having these problems, please try using the installer instead of manually unpacking -the archive. - -For `Bison`, please download the Setup installer version from here: http://gnuwin32.sourceforge.net/packages/bison.htm (When using the zip version the bison.exe couldn't find some DLL files) -It seems the official 2.4.1 version has issues when installed in a directory which's path contains spaces. Please make sure you replace the exe with a patched version form here: http://marin.jb.free.fr/bison/bison-2.4.1-modified.zip -(More infos on this issue here: https://sourceforge.net/p/gnuwin32/bugs/473/) - -Please download the `Flex` compiler from here: http://gnuwin32.sourceforge.net/packages/flex.htm (Ideally download the binary zip distribution) - -You can get `Python` from here: https://www.python.org/downloads/release/python-2716/ - -For `.Net`, you need the `Developer Pack` in order to build .Net applications. So be sure to get a reasonably fresh installation from https://dotnet.microsoft.com - -If you're building a source-distribution and haven't installed git yet, be sure to do so. - -The windows version of the PCAP library can be found here: https://sourceforge.net/projects/winpcap413-176/ -(In order to read PCAPNG files we require a libpcap version 1.1.0 or greater. The default -Windows version is 1.0. At this location there is a patched version based on libpcap 1.7.4) - -Last not least we need to install OpenSSL, which is available from here: https://indy.fulgan.com/SSL/ -The letter at the end of the version is sort of a "sub-minor" version, so I usually just take the version with the highest letter. - -Make sure the `bin` directories of containing the executables `mingw32-make.exe`, `bison.exe` and `flex.exe` are all on your systems `PATH` as well as the directory containing the `openssl.exe`. - -### Building with Docker - -If you don't want to bother setting up the environment on your normal system and you have Docker installed, you can also build everything in a Docker container: - -``` - docker build -t plc4x . - - docker run -p 9200:9200 -p 9300:9300 --name plc4x plc4x -``` - -### Getting Started - -You must have Java 8 installed on your system and connectivity to Maven Central -(for downloading external third party dependencies). Maven will be automatically -downloaded and installed by the maven wrapper `mvnw`. - -Build PLC4X Java jars and install them in your local maven repository - -``` -./mvnw install # add -DskipTests to omit running the tests -``` - -You can now construct Java applications that use PLC4X. The PLC4X examples -are a good place to start and are available inside the `plc4j/examples` -directory. - -The `C++` drivers are still under development and still not really usable. -Therefore they are located in the so-called `sandbox`. -If you want to build them, this has to be enabled by activating the `with-sandbox` and `with-cpp` maven profiles: - -``` -./mvnw -P with-sandbox,with-cpp install # add -DskipTests to omit running the tests -``` - -Same applies for the `C# / .Net` implementation with `with-dotnet` profiles. - -``` -./mvnw -P with-sandbox,with-dotnet install # add -DskipTests to omit running the tests -``` - -The Python implementation is currently in a somewhat unclean state and still needs refactoring. -In order to be able to build the Python module, you currently need to activate the: -`with-sandbox`, `with-python` and `with-proxies` profiles. - -``` -./mvnw -P with-sandbox,with-python,with-proxies install # add -DskipTests to omit running the tests -``` - -In order to build everything the following command should work: - -``` -./mvnw -P with-boost,with-cpp,with-dotnet,with-logstash,with-proxies,with-python,with-sandbox install -``` - -## Community - -Join the PLC4X community by using one of the following channels. We'll be glad to help! - -### Mailing Lists - -Subscribe to the following mailing lists: -* Apache PLC4X Developer List: [dev-subscribe@plc4x.apache.org](mailto:dev-subscribe@plc4x.apache.org) -* Apache PLC4X Commits List: [commit-subscribe@plc4x.apache.org](mailto:commit-subscribe@plc4x.apache.org) -* Apache PLC4X Jira Notification List: [issues-subscribe@plc4x.apache.org](mailto:issues-subscribe@plc4x.apache.org) - -See also: [https://plc4x.apache.org/mailing-lists.html](https://plc4x.apache.org/mailing-lists.html) - -### Twitter - -Get the latest PLC4X news on Twitter: [https://twitter.com/ApachePlc4x](https://twitter.com/ApachePlc4x) - -## Contributing - -There are multiple forms in which you can become involved with the PLC4X project. - -These usually are, but are not limited to: - -* Submitting Pull Requests -* Filing Bug-Reports -* Active communication on our mailing lists -* Promoting the project (articles, blog posts, talks at conferences) -* Documentation - -We are a very friendly bunch and don’t be afraid to step forward. -If you'd like to contribute to PLC4X, have a look at our -[contribution guide](https://plc4x.apache.org/developers/contributing.html)! - - -## Licensing - -Apache PLC4X is released under the Apache License Version 2.0. + +[![Maven central](https://img.shields.io/maven-central/v/org.apache.plc4x/plc4j-api.svg)](https://img.shields.io/maven-central/v/org.apache.plc4x/plc4j-api.svg) +[![License](https://img.shields.io/github/license/apache/plc4x.svg)](http://www.apache.org/licenses/LICENSE-2.0) +[![Last commit](https://img.shields.io/github/last-commit/apache/plc4x.svg)]() +[![Twitter](https://img.shields.io/twitter/follow/ApachePLC4X.svg?label=Follow&style=social)](https://twitter.com/ApachePLC4X) + + +

+
+ Apache PLC4X Logo +
+

+

The Industrial IoT adapter

+

The ultimate goal of PLC4X is to create a set of libraries, that allow unified access to any type of + PLC

+ +*** + +# Table of contents + + * [About PLC4X](#about-apache-plc4x) + * [Getting Started](#getting-started) + * [Developers](#developers) + * [Community](#community) + * [Contributing](#contributing) + * [Licensing](#licensing) + +*** + +## About Apache PLC4X + +Apache PLC4X is an effort to create a set of libraries for communicating with industrial grade programmable logic controllers (PLCs) in a uniform way. +We are planning on shipping libraries for usage in: + +1. Java +2. C/C++ (not ready for usage) +3. C# (.Net) (not ready for usage) +4. Python (not ready for usage) + +PLC4X also integrates with other Apache projects, such as: + +* [Apache Calcite](https://calcite.apache.org/) +* [Apache Camel](https://camel.apache.org/) +* [Apache Edgent](https://edgent.apache.org/) +* [Apache Kafka-Connect](https://kafka.apache.org) +* [Apache Karaf](https://karaf.apache.org/) +* [Apache NiFi](https://nifi.apache.org/) + +## Getting started + +Depending on the programming language, the usage will differ, therefore please go to the +[Getting Started](https://plc4x.apache.org/users/gettingstarted.html) on the PLC4X website to look up +the language of choice. + +### Java + +See the PLC4J user guide on the website to start using PLC4X in your Java application: +[https://plc4x.apache.org/plc4j/users/gettingstarted.html](https://plc4x.apache.org/plc4j/users/gettingstarted.html) + +## Developers + +### Environment + +Currently the project is configured to require the following software: + +1. Java 8 JDK: For running Maven in general as well as compiling the Java and Scala modules `JAVA_HOME` configured to + point to that. +2. libpcap/WinPcap for raw socket tests in Java or use of `passive-mode` drivers +3. (Optional) Graphwiz: For generating the graphs in the documentation (http://www.graphviz.org/) +4. Git (even when working on the source distribution) + +With this setup you will be able to build the Java part of PLC4X excluding the "proxy" drivers and servers. +For a full build of PLC4X with all options the following has to be provided: + +#### Linux + +On a clean Ubuntu 18.04 the following software needs to be installed: + +``` + sudo apt install python-setuptools gcc g++ make libpcap-dev +``` + +If you're building a source-distribution and haven't installed git yet, be sure to do so: + +``` + sudo get install git +``` + +In order to build the .Net version, please install the .Net package according to this guide: + +https://dev.to/carlos487/installing-dotnet-core-in-ubuntu-1804-7lp + +#### Mac + +Make sure `Homebrew` ist installed in order to update `Bison` to a newer version (the version 2.3 installed per default is too old) + +``` + /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" +``` + +Then update `Bison`: + +``` + brew install bison + brew link bison --force + echo 'export PATH="/usr/local/opt/bison/bin:$PATH"' >> ~/.bash_profile +``` + +Install `Python 2.7`: + +``` + brew install python@2 +``` + +Be sure to re-open the command window or the changes will not apply. + +If you're going to build the `with-dotnet` profile you also need to install DotNet. +Please download it from: https://dotnet.microsoft.com/download and run the installer. + +LibPCAP is also installed via Homebrew: + +``` + brew install libpcap +``` + +#### Windows + +Some tools need to be installed before being able to build on Windows: + +* WinBuilds (for `with-cpp`, `with-proxies` profiles) +* Bison (for `with-cpp` profiles) +* Flex (for `with-cpp` profiles) +* Python 2.7 (for `with-python`, `with-proxies` profiles) +* Dotnet (for `with-dotnet` profiles) +* WinPCAP +* OpenSSL + +He have tested `WinBuilds` with the bundle of: http://win-builds.org/doku.php/download_and_installation_from_windows +Run the installer as "Administrator" or you won't be able to install it to "C:\Program Files" or the 32 Bit counterpart. +When running the installer, make sure to select the options: +* Native Windows +* x86_64 +Not quite sure which elements are really needed, better just install all of them. +If the installer fails to do something complaining about having to use a different mirror, enter "http://win-builds.org/1.5.0" as mirror address. + +WARNING: If you don't use the installer version of the distribution. The build will probably fail and it will be pretty +impossible to see the problem. When manually executing the command, a popup will appear complaining about not being able +to find some DLL. So if you are having these problems, please try using the installer instead of manually unpacking +the archive. + +For `Bison`, please download the Setup installer version from here: http://gnuwin32.sourceforge.net/packages/bison.htm (When using the zip version the bison.exe couldn't find some DLL files) +It seems the official 2.4.1 version has issues when installed in a directory which's path contains spaces. Please make sure you replace the exe with a patched version form here: http://marin.jb.free.fr/bison/bison-2.4.1-modified.zip +(More infos on this issue here: https://sourceforge.net/p/gnuwin32/bugs/473/) + +Please download the `Flex` compiler from here: http://gnuwin32.sourceforge.net/packages/flex.htm (Ideally download the binary zip distribution) + +You can get `Python` from here: https://www.python.org/downloads/release/python-2716/ + +For `.Net`, you need the `Developer Pack` in order to build .Net applications. So be sure to get a reasonably fresh installation from https://dotnet.microsoft.com + +If you're building a source-distribution and haven't installed git yet, be sure to do so. + +The windows version of the PCAP library can be found here: https://sourceforge.net/projects/winpcap413-176/ +(In order to read PCAPNG files we require a libpcap version 1.1.0 or greater. The default +Windows version is 1.0. At this location there is a patched version based on libpcap 1.7.4) + +Last not least we need to install OpenSSL, which is available from here: https://indy.fulgan.com/SSL/ +The letter at the end of the version is sort of a "sub-minor" version, so I usually just take the version with the highest letter. + +Make sure the `bin` directories of containing the executables `mingw32-make.exe`, `bison.exe` and `flex.exe` are all on your systems `PATH` as well as the directory containing the `openssl.exe`. + +### Building with Docker + +If you don't want to bother setting up the environment on your normal system and you have Docker installed, you can also build everything in a Docker container: + +``` + docker build -t plc4x . + + docker run -p 9200:9200 -p 9300:9300 --name plc4x plc4x +``` + +### Getting Started + +You must have Java 8 installed on your system and connectivity to Maven Central +(for downloading external third party dependencies). Maven will be automatically +downloaded and installed by the maven wrapper `mvnw`. + +Build PLC4X Java jars and install them in your local maven repository + +``` +./mvnw install # add -DskipTests to omit running the tests +``` + +You can now construct Java applications that use PLC4X. The PLC4X examples +are a good place to start and are available inside the `plc4j/examples` +directory. + +The `C++` drivers are still under development and still not really usable. +Therefore they are located in the so-called `sandbox`. +If you want to build them, this has to be enabled by activating the `with-sandbox` and `with-cpp` maven profiles: + +``` +./mvnw -P with-sandbox,with-cpp install # add -DskipTests to omit running the tests +``` + +Same applies for the `C# / .Net` implementation with `with-dotnet` profiles. + +``` +./mvnw -P with-sandbox,with-dotnet install # add -DskipTests to omit running the tests +``` + +The Python implementation is currently in a somewhat unclean state and still needs refactoring. +In order to be able to build the Python module, you currently need to activate the: +`with-sandbox`, `with-python` and `with-proxies` profiles. + +``` +./mvnw -P with-sandbox,with-python,with-proxies install # add -DskipTests to omit running the tests +``` + +In order to build everything the following command should work: + +``` +./mvnw -P with-boost,with-cpp,with-dotnet,with-logstash,with-proxies,with-python,with-sandbox install +``` + +## Community + +Join the PLC4X community by using one of the following channels. We'll be glad to help! + +### Mailing Lists + +Subscribe to the following mailing lists: +* Apache PLC4X Developer List: [dev-subscribe@plc4x.apache.org](mailto:dev-subscribe@plc4x.apache.org) +* Apache PLC4X Commits List: [commit-subscribe@plc4x.apache.org](mailto:commit-subscribe@plc4x.apache.org) +* Apache PLC4X Jira Notification List: [issues-subscribe@plc4x.apache.org](mailto:issues-subscribe@plc4x.apache.org) + +See also: [https://plc4x.apache.org/mailing-lists.html](https://plc4x.apache.org/mailing-lists.html) + +### Twitter + +Get the latest PLC4X news on Twitter: [https://twitter.com/ApachePlc4x](https://twitter.com/ApachePlc4x) + +## Contributing + +There are multiple forms in which you can become involved with the PLC4X project. + +These usually are, but are not limited to: + +* Submitting Pull Requests +* Filing Bug-Reports +* Active communication on our mailing lists +* Promoting the project (articles, blog posts, talks at conferences) +* Documentation + +We are a very friendly bunch and don’t be afraid to step forward. +If you'd like to contribute to PLC4X, have a look at our +[contribution guide](https://plc4x.apache.org/developers/contributing.html)! + + +## Licensing + +Apache PLC4X is released under the Apache License Version 2.0. diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 80528f8ff22..185bacb0acc 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,236 +1,236 @@ -============================================================== -(Unreleased) Apache PLC4X 0.6.0-SNAPSHOT -============================================================== - -New Features ------------- - -Incompatible changes --------------------- - -- Moved the C++, C# and Python drivers into the `sandbox` - -Bug Fixes ---------- - -============================================================== -Apache PLC4X 0.6.0-SNAPSHOT -============================================================== - -This is the first release containing our new generaed drivers (AB-ETH) - -New Features ------------- - -- Implemented a new Apache Kafka Connect integration module -- Implemented a new Apache NiFi integration module -- Implemented a new Logstash integration module -- Implemented a driver for the AB-ETH protocol -- Implemented Apache Karaf features for S7 OSGI drivers -- PLC4X-121 Develop Code Generation to allow Generated Drivers in multiple Languages - -Sandbox (Beta-Features) -- Implemented a new BACnet/IP passive mode driver -- Implemented a new Serial DF1 driver - -Incompatible changes --------------------- - -Bug Fixes ---------- - -- PLC4X-104 S7 Driver Datatype TIME_OF_DAY causes ArrayOutOfBoundException -- PLC4X-134 S7 is terminating the connection during handshake -- PLC4X-139 PLC4X leaks sockets in case of connection problems -- PLC4X-141 String with real length of greater 127 throw an exception -- PLC4X-144 When requesting invalid addresses, the DefaultS7MessageProcessor produces errors - -============================================================== -Apache PLC4X 0.4.0 -============================================================== - -This is the first release of Apache PLC4X as top-level project. - -New Features ------------- - -- The PlcConnection now supports a `ping` method to allow checking if an existing connection is still alive. -- Support of the OPC-UA protocol with the `opc-ua-driver`. -- Other Languages Support: --- Added first versions of a C# .Net PLC4X API (`plc4net`) --- Added first versions of a Python PLC4X API (`plc4py`) -- Added an Interop server which allows to relay requests from other languages to a Java Server - -Incompatible changes --------------------- - -- ElasticSearch example was updated to use ElasticSearch 7.0.1, this might cause problems with older Kibana versions. - -Bug Fixes ---------- - - -============================================================== -Apache PLC4X (incubating) 0.3.1 -============================================================== - -This is a bugfix-release, that fixes some problems with S7 driver. - -Bug Fixes ---------- - -- The S7 driver didn't correctly handle "fill-bytes" in multi-item read-responses and multi-item write-requests -- PLC4X-83: fixed NPE when reading odd-length array of one-byte base types -- PLC4X-82: renamed flags "F" to Siemens Standard "M" (Marker) -- PLC4X-84: Fixed a bug in the DefaultS7MessageProcessor which didn't correctly merge together split up items - - -============================================================== -Apache PLC4X (incubating) 0.3.0 -============================================================== - -This is the third official release of Apache PLC4X. - -Some new features have been added (e.g. plc-scraper) multiple -new integrations are included (apache-karaf, apache-calcite) -and a lot of (technical) refactoring has been done to prepare -future work on adapters in different languages. - -New Features ------------- - -- Object PLC Mapping (OPM) now has a Alias Registry to allow - variable substitution at runtime and write support -- New module `plc-scraper` for applications that have to - scrape a lot of sps fields with high frequency -- New integration `apache-karaf` to enable plc4j in a karaf - runtime environment - -Incompatible changes --------------------- -- The 'plc4j-core' module has been merged into 'plc4j-api'. - So there is no 'plc4j-core' module anymore. Just remove that - dependency. -- The driver artifact names have changed so if you were using - a `plc4j-protocol-{name}` you now need to change this to - `plc4j-driver-{name}` - -Bug Fixes ---------- - -PLC4X-75 Fixing dependency to the wrap url-handler -PLC4X-76 When receiving responses with more than 512 byte, - the IsoOnTcp protocol doesn't work -PLC4X-77 When the last item in a request is a DINT, the - DefaultS7MessageProcessor dies -PLC4X-78 Write operations seem to fail -- Fixed a Bug where S7 was not able to read arrays. - - -============================================================== -Apache PLC4X (incubating) 0.2.0 -============================================================== - -This is the second official release of Apache PLC4X. - -Especially have we addressed all issues reported during -our first release, that were of non-technical nature. -These were tracked in: - -PLC4X-60 Fix findings by the last release - -New Features ------------- -A new connection-pool was added, which allows automatic -pooling and reuse of PLC connections. - -A new OPM module was added, which allows JPA like read- -communication using POJOs, very similar to JPA. - -A stub of a new driver for the Emerson DeltaV protocol -has been added, but is not yet a fully functional PLC4X -driver. This is also a first test of our new `passive- -mode-driver` concept. - -Incompatible changes --------------------- - -We have refactored the API in order to eliminate the -need of passing `x-requests` to `x-methods` and added -an `execute` method to each request type. This greatly -simplifies the client code. However this requires -refactoring of applications using the direct PLC4X API. - -Miscellaneous changes ---------------------- - -We have increased the test coverage greatly and fixed -a lot of little errors we found on the way. - -Known Issues ------------- - -Bug Fixes ---------- - -PLC4X-56 [S7] S7Field does not recognize addresses - with numElements present -PLC4X-57 [S7] Response for address with numElements - contains only first item -PLC4X-61 Installation fails plc4j-protocoll-ethernetip - needs license -PLC4X-62 Modbus results deliver null-Value due to missing - implementation of getShort, getLong ... - - - -============================================================== -Apache PLC4X (incubating) 0.1.0 -============================================================== - -This is the first official release of Apache PLC4X. -It contains drivers for the following protocols: -- Siemens S7comm (0x32) -- Beckhoff ADS -- Modbus -- EtherNet/IP - -However the Siemens driver definitely is the most -mature driver, the rest should be treated experimental. - -New Features ------------- - -PLC4X-29 [S7] Implement PDU Fragmentation -PLC4X-39 Extend the Edgent integration with the new Subscription features of PLC4X - -Incompatible changes --------------------- - -- NONE - - -Miscellaneous changes ---------------------- - -- NONE - - -Known Issues ------------- - -- NONE - - -Most drivers should be treated experimental and are not near production ready. -The S7 driver is probably the furthest implemented and tested driver and hereby can be -considered to be the most mature. - -Bug Fixes ---------- - -PLC4X-20 Jacoco doesn't seem to be working at all -PLC4X-21 Code coverage doesn't seem to work -PLC4X-47 S7 driver silently ignores surplus ReadRequestItems -PLC4X-48 S7 driver failes to parse response with multiple items - - - - +============================================================== +(Unreleased) Apache PLC4X 0.6.0-SNAPSHOT +============================================================== + +New Features +------------ + +Incompatible changes +-------------------- + +- Moved the C++, C# and Python drivers into the `sandbox` + +Bug Fixes +--------- + +============================================================== +Apache PLC4X 0.6.0-SNAPSHOT +============================================================== + +This is the first release containing our new generaed drivers (AB-ETH) + +New Features +------------ + +- Implemented a new Apache Kafka Connect integration module +- Implemented a new Apache NiFi integration module +- Implemented a new Logstash integration module +- Implemented a driver for the AB-ETH protocol +- Implemented Apache Karaf features for S7 OSGI drivers +- PLC4X-121 Develop Code Generation to allow Generated Drivers in multiple Languages + +Sandbox (Beta-Features) +- Implemented a new BACnet/IP passive mode driver +- Implemented a new Serial DF1 driver + +Incompatible changes +-------------------- + +Bug Fixes +--------- + +- PLC4X-104 S7 Driver Datatype TIME_OF_DAY causes ArrayOutOfBoundException +- PLC4X-134 S7 is terminating the connection during handshake +- PLC4X-139 PLC4X leaks sockets in case of connection problems +- PLC4X-141 String with real length of greater 127 throw an exception +- PLC4X-144 When requesting invalid addresses, the DefaultS7MessageProcessor produces errors + +============================================================== +Apache PLC4X 0.4.0 +============================================================== + +This is the first release of Apache PLC4X as top-level project. + +New Features +------------ + +- The PlcConnection now supports a `ping` method to allow checking if an existing connection is still alive. +- Support of the OPC-UA protocol with the `opc-ua-driver`. +- Other Languages Support: +-- Added first versions of a C# .Net PLC4X API (`plc4net`) +-- Added first versions of a Python PLC4X API (`plc4py`) +- Added an Interop server which allows to relay requests from other languages to a Java Server + +Incompatible changes +-------------------- + +- ElasticSearch example was updated to use ElasticSearch 7.0.1, this might cause problems with older Kibana versions. + +Bug Fixes +--------- + + +============================================================== +Apache PLC4X (incubating) 0.3.1 +============================================================== + +This is a bugfix-release, that fixes some problems with S7 driver. + +Bug Fixes +--------- + +- The S7 driver didn't correctly handle "fill-bytes" in multi-item read-responses and multi-item write-requests +- PLC4X-83: fixed NPE when reading odd-length array of one-byte base types +- PLC4X-82: renamed flags "F" to Siemens Standard "M" (Marker) +- PLC4X-84: Fixed a bug in the DefaultS7MessageProcessor which didn't correctly merge together split up items + + +============================================================== +Apache PLC4X (incubating) 0.3.0 +============================================================== + +This is the third official release of Apache PLC4X. + +Some new features have been added (e.g. plc-scraper) multiple +new integrations are included (apache-karaf, apache-calcite) +and a lot of (technical) refactoring has been done to prepare +future work on adapters in different languages. + +New Features +------------ + +- Object PLC Mapping (OPM) now has a Alias Registry to allow + variable substitution at runtime and write support +- New module `plc-scraper` for applications that have to + scrape a lot of sps fields with high frequency +- New integration `apache-karaf` to enable plc4j in a karaf + runtime environment + +Incompatible changes +-------------------- +- The 'plc4j-core' module has been merged into 'plc4j-api'. + So there is no 'plc4j-core' module anymore. Just remove that + dependency. +- The driver artifact names have changed so if you were using + a `plc4j-protocol-{name}` you now need to change this to + `plc4j-driver-{name}` + +Bug Fixes +--------- + +PLC4X-75 Fixing dependency to the wrap url-handler +PLC4X-76 When receiving responses with more than 512 byte, + the IsoOnTcp protocol doesn't work +PLC4X-77 When the last item in a request is a DINT, the + DefaultS7MessageProcessor dies +PLC4X-78 Write operations seem to fail +- Fixed a Bug where S7 was not able to read arrays. + + +============================================================== +Apache PLC4X (incubating) 0.2.0 +============================================================== + +This is the second official release of Apache PLC4X. + +Especially have we addressed all issues reported during +our first release, that were of non-technical nature. +These were tracked in: + +PLC4X-60 Fix findings by the last release + +New Features +------------ +A new connection-pool was added, which allows automatic +pooling and reuse of PLC connections. + +A new OPM module was added, which allows JPA like read- +communication using POJOs, very similar to JPA. + +A stub of a new driver for the Emerson DeltaV protocol +has been added, but is not yet a fully functional PLC4X +driver. This is also a first test of our new `passive- +mode-driver` concept. + +Incompatible changes +-------------------- + +We have refactored the API in order to eliminate the +need of passing `x-requests` to `x-methods` and added +an `execute` method to each request type. This greatly +simplifies the client code. However this requires +refactoring of applications using the direct PLC4X API. + +Miscellaneous changes +--------------------- + +We have increased the test coverage greatly and fixed +a lot of little errors we found on the way. + +Known Issues +------------ + +Bug Fixes +--------- + +PLC4X-56 [S7] S7Field does not recognize addresses + with numElements present +PLC4X-57 [S7] Response for address with numElements + contains only first item +PLC4X-61 Installation fails plc4j-protocoll-ethernetip + needs license +PLC4X-62 Modbus results deliver null-Value due to missing + implementation of getShort, getLong ... + + + +============================================================== +Apache PLC4X (incubating) 0.1.0 +============================================================== + +This is the first official release of Apache PLC4X. +It contains drivers for the following protocols: +- Siemens S7comm (0x32) +- Beckhoff ADS +- Modbus +- EtherNet/IP + +However the Siemens driver definitely is the most +mature driver, the rest should be treated experimental. + +New Features +------------ + +PLC4X-29 [S7] Implement PDU Fragmentation +PLC4X-39 Extend the Edgent integration with the new Subscription features of PLC4X + +Incompatible changes +-------------------- + +- NONE - + +Miscellaneous changes +--------------------- + +- NONE - + +Known Issues +------------ + +- NONE - + +Most drivers should be treated experimental and are not near production ready. +The S7 driver is probably the furthest implemented and tested driver and hereby can be +considered to be the most mature. + +Bug Fixes +--------- + +PLC4X-20 Jacoco doesn't seem to be working at all +PLC4X-21 Code coverage doesn't seem to work +PLC4X-47 S7 driver silently ignores surplus ReadRequestItems +PLC4X-48 S7 driver failes to parse response with multiple items + + + + diff --git a/Sometimes-Failling-Tests.md b/Sometimes-Failling-Tests.md index 818bfa31d52..017bfac5c56 100644 --- a/Sometimes-Failling-Tests.md +++ b/Sometimes-Failling-Tests.md @@ -1,32 +1,32 @@ - - -# Sometimes Failing Tests - -This File contains the names and outputs of some tests that have been seen to fail without direct code-changes. -It's sort of a collection of places we should keep an eye out for improving tests- - -## Module: plc4l-opm - -[ERROR] ConnectedEntityTest.useCache_timeout_refetches:83 -mockDevice.read(); -Wanted 2 times: --> at org.apache.plc4x.java.opm.ConnectedEntityTest.useCache_timeout_refetches(ConnectedEntityTest.java:83) -But was 1 time: --> at org.apache.plc4x.java.mock.PlcMockConnection.lambda$null$0(PlcMockConnection.java:111) + + +# Sometimes Failing Tests + +This File contains the names and outputs of some tests that have been seen to fail without direct code-changes. +It's sort of a collection of places we should keep an eye out for improving tests- + +## Module: plc4l-opm + +[ERROR] ConnectedEntityTest.useCache_timeout_refetches:83 +mockDevice.read(); +Wanted 2 times: +-> at org.apache.plc4x.java.opm.ConnectedEntityTest.useCache_timeout_refetches(ConnectedEntityTest.java:83) +But was 1 time: +-> at org.apache.plc4x.java.mock.PlcMockConnection.lambda$null$0(PlcMockConnection.java:111) diff --git a/build-reproducible.sh b/build-reproducible.sh index 885dbf5992b..8cc0081bd40 100755 --- a/build-reproducible.sh +++ b/build-reproducible.sh @@ -1,68 +1,68 @@ -#!/bin/bash -# ---------------------------------------------------------------------------- -# 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. -# ---------------------------------------------------------------------------- - -# Run a standard build -function build() { - echo "Building ..." - mvn -U -P apache-release,with-boost,with-dotnet,with-cpp,with-python,with-proxies,with-sandbox,with-logstash -DaltDeploymentRepository=snapshot-repo::default::file:./local-snapshots-dir clean deploy - echo "Done" -} - -# Just remove all the metadata information and all the hashes and signatures -function clean() { - echo "Cleaning ..." - cd local-snapshots-dir || exit - find ./ -name "*.asc" -exec rm -rf {} \; - find ./ -name "*.md5" -exec rm -rf {} \; - find ./ -name "*.sha1" -exec rm -rf {} \; - find ./ -name "maven-metadata.xml" -exec rm -rf {} \; - find ./ -name "maven-metadata.xml.md5" -exec rm -rf {} \; - find ./ -name "maven-metadata.xml.sha1" -exec rm -rf {} \; - cd .. - echo "Done" - pwd -} - -# Rename all snapshot files to not contain the timestamps -function renameArtifacts() { - echo "Renaming ..." - cd local-snapshots-dir || exit - # Remove the timestamp from the file-names - find . -type f | rename 's/-\d{8}\.\d{6}-\d{1,2}//' - cd .. - echo "Done" - pwd -} - -# Package the remaiing files into one tgz archive -function packageDirectory() { - echo "Packaging ..." - tar -cvf reproducible-build-candidate.tgz local-snapshots-dir/ - echo "Done" - pwd -} - -# Remove any pre-existing directory -rm -r local-snapshots-dir - -build -clean -renameArtifacts -packageDirectory +#!/bin/bash +# ---------------------------------------------------------------------------- +# 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. +# ---------------------------------------------------------------------------- + +# Run a standard build +function build() { + echo "Building ..." + mvn -U -P apache-release,with-boost,with-dotnet,with-cpp,with-python,with-proxies,with-sandbox,with-logstash -DaltDeploymentRepository=snapshot-repo::default::file:./local-snapshots-dir clean deploy + echo "Done" +} + +# Just remove all the metadata information and all the hashes and signatures +function clean() { + echo "Cleaning ..." + cd local-snapshots-dir || exit + find ./ -name "*.asc" -exec rm -rf {} \; + find ./ -name "*.md5" -exec rm -rf {} \; + find ./ -name "*.sha1" -exec rm -rf {} \; + find ./ -name "maven-metadata.xml" -exec rm -rf {} \; + find ./ -name "maven-metadata.xml.md5" -exec rm -rf {} \; + find ./ -name "maven-metadata.xml.sha1" -exec rm -rf {} \; + cd .. + echo "Done" + pwd +} + +# Rename all snapshot files to not contain the timestamps +function renameArtifacts() { + echo "Renaming ..." + cd local-snapshots-dir || exit + # Remove the timestamp from the file-names + find . -type f | rename 's/-\d{8}\.\d{6}-\d{1,2}//' + cd .. + echo "Done" + pwd +} + +# Package the remaiing files into one tgz archive +function packageDirectory() { + echo "Packaging ..." + tar -cvf reproducible-build-candidate.tgz local-snapshots-dir/ + echo "Done" + pwd +} + +# Remove any pre-existing directory +rm -r local-snapshots-dir + +build +clean +renameArtifacts +packageDirectory diff --git a/build-utils/language-base-freemarker/pom.xml b/build-utils/language-base-freemarker/pom.xml index 6d01362a086..fe703adface 100644 --- a/build-utils/language-base-freemarker/pom.xml +++ b/build-utils/language-base-freemarker/pom.xml @@ -1,56 +1,56 @@ - - - - - 4.0.0 - - - org.apache.plc4x - plc4x-build-utils - 0.6.0-SNAPSHOT - - - plc4x-build-utils-language-base-freemarker - - PLC4X: Build Utils: Language Base: Freemarker - Base code for building language outputs based on Freemarker - - - - org.apache.plc4x.plugins - plc4x-code-generation-language-base - - - - org.freemarker - freemarker - - - org.apache.commons - commons-text - - - - org.slf4j - slf4j-api - - - + + + + + 4.0.0 + + + org.apache.plc4x + plc4x-build-utils + 0.6.0-SNAPSHOT + + + plc4x-build-utils-language-base-freemarker + + PLC4X: Build Utils: Language Base: Freemarker + Base code for building language outputs based on Freemarker + + + + org.apache.plc4x.plugins + plc4x-code-generation-language-base + + + + org.freemarker + freemarker + + + org.apache.commons + commons-text + + + + org.slf4j + slf4j-api + + + \ No newline at end of file diff --git a/build-utils/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/FreemarkerLanguageOutput.java b/build-utils/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/FreemarkerLanguageOutput.java index 5ca25bca445..dde911c34ff 100644 --- a/build-utils/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/FreemarkerLanguageOutput.java +++ b/build-utils/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/FreemarkerLanguageOutput.java @@ -1,129 +1,129 @@ -/* - 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.plugins.codegenerator.protocol.freemarker; - -import freemarker.cache.ClassTemplateLoader; -import freemarker.core.ParseException; -import freemarker.template.*; -import org.apache.plc4x.plugins.codegenerator.language.LanguageOutput; -import org.apache.plc4x.plugins.codegenerator.types.definitions.EnumTypeDefinition; -import org.apache.plc4x.plugins.codegenerator.types.definitions.TypeDefinition; -import org.apache.plc4x.plugins.codegenerator.types.exceptions.GenerationException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public abstract class FreemarkerLanguageOutput implements LanguageOutput { - - private static final Logger LOGGER = LoggerFactory.getLogger(FreemarkerLanguageOutput.class); - - @Override - public void generate(File outputDir, String languageName, String protocolName, String outputFlavor, Map types) - throws GenerationException { - - try { - // Configure the Freemarker template engine - Configuration freemarkerConfiguration = getFreemarkerConfiguration(); - - ClassTemplateLoader classTemplateLoader = new ClassTemplateLoader(FreemarkerLanguageOutput.class, "/"); - freemarkerConfiguration.setTemplateLoader(classTemplateLoader); - - // Initialize all templates - List