diff --git a/images/s7h_image01.png b/images/s7h_image01.png new file mode 100644 index 00000000000..e474902b2fb Binary files /dev/null and b/images/s7h_image01.png differ diff --git a/images/s7h_image02.png b/images/s7h_image02.png new file mode 100644 index 00000000000..9dc9db266ad Binary files /dev/null and b/images/s7h_image02.png differ diff --git a/images/s7h_image03.png b/images/s7h_image03.png new file mode 100644 index 00000000000..d4a0c0ad81d Binary files /dev/null and b/images/s7h_image03.png differ diff --git a/images/s7h_image04.png b/images/s7h_image04.png new file mode 100644 index 00000000000..782b2bbc7e4 Binary files /dev/null and b/images/s7h_image04.png differ diff --git a/images/s7h_image05.png b/images/s7h_image05.png new file mode 100644 index 00000000000..4db044b8874 Binary files /dev/null and b/images/s7h_image05.png differ diff --git a/images/s7h_image06.png b/images/s7h_image06.png new file mode 100644 index 00000000000..7c742206dcb Binary files /dev/null and b/images/s7h_image06.png differ diff --git a/images/s7h_image07.png b/images/s7h_image07.png new file mode 100644 index 00000000000..a69e853e00e Binary files /dev/null and b/images/s7h_image07.png differ diff --git a/images/s7h_szlxy11demo.png b/images/s7h_szlxy11demo.png new file mode 100644 index 00000000000..4f9d1ad3806 Binary files /dev/null and b/images/s7h_szlxy11demo.png differ diff --git a/plc4j/drivers/s7/pom.xml b/plc4j/drivers/s7/pom.xml index 488790f6cf4..0d22747f9ee 100644 --- a/plc4j/drivers/s7/pom.xml +++ b/plc4j/drivers/s7/pom.xml @@ -33,6 +33,25 @@ + + org.apache.plc4x.plugins + plc4x-maven-plugin + + + generate-driver + generate-sources + + generate-driver + + + s7 + java + read-write + src/main/generated + + + + org.apache.karaf.tooling karaf-maven-plugin @@ -81,6 +100,16 @@ + + org.apache.maven.plugins + maven-dependency-plugin + + + org.apache.plc4x:plc4x-code-generation-language-java + org.apache.plc4x:plc4x-protocols-s7 + + + @@ -118,26 +147,10 @@ io.netty netty-transport - - io.netty - netty-handler - - - io.netty - netty-codec - - - io.netty - netty-common - io.vavr vavr - - org.json - json - org.apache.plc4x @@ -145,19 +158,34 @@ 0.12.0-SNAPSHOT test - org.skyscreamer jsonassert + 1.5.1 test + + + com.vaadin.external.google + android-json + + - com.fasterxml.jackson.core - jackson-annotations - test + org.apache.plc4x + plc4x-code-generation-language-java + 0.12.0-SNAPSHOT + + provided + + org.apache.plc4x + plc4x-protocols-s7 + 0.12.0-SNAPSHOT + + provided + org.apache.plc4x plc4x-protocols-s7 @@ -166,53 +194,32 @@ test-jar test + + io.netty + netty-handler + ${netty.version} + + + io.netty + netty-codec + ${netty.version} + + + io.netty + netty-common + ${netty.version} + + + org.json + json + 20230618 + jar + + + com.fasterxml.jackson.core + jackson-annotations + test + - - - update-generated-code - - - - org.apache.plc4x.plugins - plc4x-maven-plugin - - - generate-driver - generate-sources - - generate-driver - - - s7 - java - read-write - src/main/generated - - - - - - - - - - org.apache.plc4x - plc4x-code-generation-language-java - 0.12.0-SNAPSHOT - - provided - - - - org.apache.plc4x - plc4x-protocols-s7 - 0.12.0-SNAPSHOT - - provided - - - - - diff --git a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/CycServiceItemAnyType.java b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/CycServiceItemAnyType.java index 6676675a724..c15002a449e 100644 --- a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/CycServiceItemAnyType.java +++ b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/CycServiceItemAnyType.java @@ -89,13 +89,13 @@ protected void serializeCycServiceItemTypeChild(WriteBuffer writeBuffer) boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); writeBuffer.pushContext("CycServiceItemAnyType"); - // Simple Field (transportSize) - writeSimpleEnumField( + // Enum field (transportSize) + writeEnumField( "transportSize", "TransportSize", transportSize, new DataWriterEnumDefault<>( - TransportSize::getValue, TransportSize::name, writeUnsignedShort(writeBuffer, 8))); + TransportSize::getCode, TransportSize::name, writeUnsignedShort(writeBuffer, 8))); // Simple Field (length) writeSimpleField("length", length, writeUnsignedInt(writeBuffer, 16)); @@ -128,7 +128,7 @@ public int getLengthInBits() { CycServiceItemAnyType _value = this; boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); - // Simple field (transportSize) + // Enum Field (transportSize) lengthInBits += 8; // Simple field (length) @@ -156,8 +156,7 @@ public static CycServiceItemTypeBuilder staticParseCycServiceItemTypeBuilder( readEnumField( "transportSize", "TransportSize", - new DataReaderEnumDefault<>( - TransportSize::enumForValue, readUnsignedShort(readBuffer, 8))); + readEnum(TransportSize::firstEnumForFieldCode, readUnsignedShort(readBuffer, 8))); int length = readSimpleField("length", readUnsignedInt(readBuffer, 16)); diff --git a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/DataItem.java b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/DataItem.java index 40dfd1d4d61..66f58e40f42 100644 --- a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/DataItem.java +++ b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/DataItem.java @@ -491,10 +491,10 @@ public static int getLengthInBits(PlcValue _value, String dataProtocolId, Intege sizeInBits += 16; } else if (EvaluationHelper.equals(dataProtocolId, "IEC61131_STRING")) { // STRING // Manual Field (value) - sizeInBits += (((stringLength) * (8))) + (16); + sizeInBits += (STR_LEN(_value)) + (2); } else if (EvaluationHelper.equals(dataProtocolId, "IEC61131_WSTRING")) { // STRING // Manual Field (value) - sizeInBits += (((stringLength) * (16))) + (32); + sizeInBits += (((STR_LEN(_value)) * (2))) + (2); } else if (EvaluationHelper.equals(dataProtocolId, "IEC61131_TIME")) { // TIME // Simple Field (milliseconds) sizeInBits += 32; diff --git a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7PayloadUserDataItem.java b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7PayloadUserDataItem.java index 89e58d08883..16ef4c273d8 100644 --- a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7PayloadUserDataItem.java +++ b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7PayloadUserDataItem.java @@ -383,6 +383,42 @@ public static S7PayloadUserDataItem staticParse( S7PayloadUserDataItemCpuFunctionAlarmQueryResponse .staticParseS7PayloadUserDataItemBuilder( readBuffer, dataLength, cpuFunctionGroup, cpuFunctionType, cpuSubfunction); + } else if (EvaluationHelper.equals(cpuFunctionGroup, (byte) 0x07) + && EvaluationHelper.equals(cpuFunctionType, (byte) 0x04) + && EvaluationHelper.equals(cpuSubfunction, (short) 0x01)) { + builder = + S7PayloadUserDataItemClkRequest.staticParseS7PayloadUserDataItemBuilder( + readBuffer, cpuFunctionGroup, cpuFunctionType, cpuSubfunction); + } else if (EvaluationHelper.equals(cpuFunctionGroup, (byte) 0x07) + && EvaluationHelper.equals(cpuFunctionType, (byte) 0x08) + && EvaluationHelper.equals(cpuSubfunction, (short) 0x01)) { + builder = + S7PayloadUserDataItemClkResponse.staticParseS7PayloadUserDataItemBuilder( + readBuffer, dataLength, cpuFunctionGroup, cpuFunctionType, cpuSubfunction); + } else if (EvaluationHelper.equals(cpuFunctionGroup, (byte) 0x07) + && EvaluationHelper.equals(cpuFunctionType, (byte) 0x04) + && EvaluationHelper.equals(cpuSubfunction, (short) 0x03)) { + builder = + S7PayloadUserDataItemClkFRequest.staticParseS7PayloadUserDataItemBuilder( + readBuffer, cpuFunctionGroup, cpuFunctionType, cpuSubfunction); + } else if (EvaluationHelper.equals(cpuFunctionGroup, (byte) 0x07) + && EvaluationHelper.equals(cpuFunctionType, (byte) 0x08) + && EvaluationHelper.equals(cpuSubfunction, (short) 0x03)) { + builder = + S7PayloadUserDataItemClkFResponse.staticParseS7PayloadUserDataItemBuilder( + readBuffer, dataLength, cpuFunctionGroup, cpuFunctionType, cpuSubfunction); + } else if (EvaluationHelper.equals(cpuFunctionGroup, (byte) 0x07) + && EvaluationHelper.equals(cpuFunctionType, (byte) 0x04) + && EvaluationHelper.equals(cpuSubfunction, (short) 0x04)) { + builder = + S7PayloadUserDataItemClkSetRequest.staticParseS7PayloadUserDataItemBuilder( + readBuffer, cpuFunctionGroup, cpuFunctionType, cpuSubfunction); + } else if (EvaluationHelper.equals(cpuFunctionGroup, (byte) 0x07) + && EvaluationHelper.equals(cpuFunctionType, (byte) 0x08) + && EvaluationHelper.equals(cpuSubfunction, (short) 0x04)) { + builder = + S7PayloadUserDataItemClkSetResponse.staticParseS7PayloadUserDataItemBuilder( + readBuffer, cpuFunctionGroup, cpuFunctionType, cpuSubfunction); } if (builder == null) { throw new ParseException( diff --git a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7PayloadUserDataItemClkFRequest.java b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7PayloadUserDataItemClkFRequest.java new file mode 100644 index 00000000000..4c527a9242a --- /dev/null +++ b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7PayloadUserDataItemClkFRequest.java @@ -0,0 +1,134 @@ +/* + * 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 + * + * https://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.readwrite; + +import static org.apache.plc4x.java.spi.codegen.fields.FieldReaderFactory.*; +import static org.apache.plc4x.java.spi.codegen.fields.FieldWriterFactory.*; +import static org.apache.plc4x.java.spi.codegen.io.DataReaderFactory.*; +import static org.apache.plc4x.java.spi.codegen.io.DataWriterFactory.*; +import static org.apache.plc4x.java.spi.generation.StaticHelper.*; + +import java.time.*; +import java.util.*; +import org.apache.plc4x.java.api.exceptions.*; +import org.apache.plc4x.java.api.value.*; +import org.apache.plc4x.java.spi.codegen.*; +import org.apache.plc4x.java.spi.codegen.fields.*; +import org.apache.plc4x.java.spi.codegen.io.*; +import org.apache.plc4x.java.spi.generation.*; + +// Code generated by code-generation. DO NOT EDIT. + +public class S7PayloadUserDataItemClkFRequest extends S7PayloadUserDataItem implements Message { + + // Accessors for discriminator values. + public Byte getCpuFunctionGroup() { + return (byte) 0x07; + } + + public Byte getCpuFunctionType() { + return (byte) 0x04; + } + + public Short getCpuSubfunction() { + return (short) 0x03; + } + + public S7PayloadUserDataItemClkFRequest( + DataTransportErrorCode returnCode, DataTransportSize transportSize, int dataLength) { + super(returnCode, transportSize, dataLength); + } + + @Override + protected void serializeS7PayloadUserDataItemChild(WriteBuffer writeBuffer) + throws SerializationException { + PositionAware positionAware = writeBuffer; + boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); + writeBuffer.pushContext("S7PayloadUserDataItemClkFRequest"); + + writeBuffer.popContext("S7PayloadUserDataItemClkFRequest"); + } + + @Override + public int getLengthInBytes() { + return (int) Math.ceil((float) getLengthInBits() / 8.0); + } + + @Override + public int getLengthInBits() { + int lengthInBits = super.getLengthInBits(); + S7PayloadUserDataItemClkFRequest _value = this; + boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); + + return lengthInBits; + } + + public static S7PayloadUserDataItemBuilder staticParseS7PayloadUserDataItemBuilder( + ReadBuffer readBuffer, Byte cpuFunctionGroup, Byte cpuFunctionType, Short cpuSubfunction) + throws ParseException { + readBuffer.pullContext("S7PayloadUserDataItemClkFRequest"); + PositionAware positionAware = readBuffer; + boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); + + readBuffer.closeContext("S7PayloadUserDataItemClkFRequest"); + // Create the instance + return new S7PayloadUserDataItemClkFRequestBuilderImpl(); + } + + public static class S7PayloadUserDataItemClkFRequestBuilderImpl + implements S7PayloadUserDataItem.S7PayloadUserDataItemBuilder { + + public S7PayloadUserDataItemClkFRequestBuilderImpl() {} + + public S7PayloadUserDataItemClkFRequest build( + DataTransportErrorCode returnCode, DataTransportSize transportSize, int dataLength) { + S7PayloadUserDataItemClkFRequest s7PayloadUserDataItemClkFRequest = + new S7PayloadUserDataItemClkFRequest(returnCode, transportSize, dataLength); + return s7PayloadUserDataItemClkFRequest; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof S7PayloadUserDataItemClkFRequest)) { + return false; + } + S7PayloadUserDataItemClkFRequest that = (S7PayloadUserDataItemClkFRequest) o; + return super.equals(that) && true; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + @Override + public String toString() { + WriteBufferBoxBased writeBufferBoxBased = new WriteBufferBoxBased(true, true); + try { + writeBufferBoxBased.writeSerializable(this); + } catch (SerializationException e) { + throw new RuntimeException(e); + } + return "\n" + writeBufferBoxBased.getBox().toString() + "\n"; + } +} diff --git a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7PayloadUserDataItemClkFResponse.java b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7PayloadUserDataItemClkFResponse.java new file mode 100644 index 00000000000..6f7d4540f79 --- /dev/null +++ b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7PayloadUserDataItemClkFResponse.java @@ -0,0 +1,203 @@ +/* + * 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 + * + * https://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.readwrite; + +import static org.apache.plc4x.java.spi.codegen.fields.FieldReaderFactory.*; +import static org.apache.plc4x.java.spi.codegen.fields.FieldWriterFactory.*; +import static org.apache.plc4x.java.spi.codegen.io.DataReaderFactory.*; +import static org.apache.plc4x.java.spi.codegen.io.DataWriterFactory.*; +import static org.apache.plc4x.java.spi.generation.StaticHelper.*; + +import java.time.*; +import java.util.*; +import org.apache.plc4x.java.api.exceptions.*; +import org.apache.plc4x.java.api.value.*; +import org.apache.plc4x.java.spi.codegen.*; +import org.apache.plc4x.java.spi.codegen.fields.*; +import org.apache.plc4x.java.spi.codegen.io.*; +import org.apache.plc4x.java.spi.generation.*; + +// Code generated by code-generation. DO NOT EDIT. + +public class S7PayloadUserDataItemClkFResponse extends S7PayloadUserDataItem implements Message { + + // Accessors for discriminator values. + public Byte getCpuFunctionGroup() { + return (byte) 0x07; + } + + public Byte getCpuFunctionType() { + return (byte) 0x08; + } + + public Short getCpuSubfunction() { + return (short) 0x03; + } + + // Properties. + protected final short Reserved; + protected final short Year1; + protected final DateAndTime TimeStamp; + + public S7PayloadUserDataItemClkFResponse( + DataTransportErrorCode returnCode, + DataTransportSize transportSize, + int dataLength, + short Reserved, + short Year1, + DateAndTime TimeStamp) { + super(returnCode, transportSize, dataLength); + this.Reserved = Reserved; + this.Year1 = Year1; + this.TimeStamp = TimeStamp; + } + + public short getReserved() { + return Reserved; + } + + public short getYear1() { + return Year1; + } + + public DateAndTime getTimeStamp() { + return TimeStamp; + } + + @Override + protected void serializeS7PayloadUserDataItemChild(WriteBuffer writeBuffer) + throws SerializationException { + PositionAware positionAware = writeBuffer; + boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); + writeBuffer.pushContext("S7PayloadUserDataItemClkFResponse"); + + // Simple Field (Reserved) + writeSimpleField("Reserved", Reserved, writeUnsignedShort(writeBuffer, 8)); + + // Simple Field (Year1) + writeSimpleField("Year1", Year1, writeUnsignedShort(writeBuffer, 8)); + + // Simple Field (TimeStamp) + writeSimpleField("TimeStamp", TimeStamp, new DataWriterComplexDefault<>(writeBuffer)); + + writeBuffer.popContext("S7PayloadUserDataItemClkFResponse"); + } + + @Override + public int getLengthInBytes() { + return (int) Math.ceil((float) getLengthInBits() / 8.0); + } + + @Override + public int getLengthInBits() { + int lengthInBits = super.getLengthInBits(); + S7PayloadUserDataItemClkFResponse _value = this; + boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); + + // Simple field (Reserved) + lengthInBits += 8; + + // Simple field (Year1) + lengthInBits += 8; + + // Simple field (TimeStamp) + lengthInBits += TimeStamp.getLengthInBits(); + + return lengthInBits; + } + + public static S7PayloadUserDataItemBuilder staticParseS7PayloadUserDataItemBuilder( + ReadBuffer readBuffer, + Integer dataLength, + Byte cpuFunctionGroup, + Byte cpuFunctionType, + Short cpuSubfunction) + throws ParseException { + readBuffer.pullContext("S7PayloadUserDataItemClkFResponse"); + PositionAware positionAware = readBuffer; + boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); + + short Reserved = readSimpleField("Reserved", readUnsignedShort(readBuffer, 8)); + + short Year1 = readSimpleField("Year1", readUnsignedShort(readBuffer, 8)); + + DateAndTime TimeStamp = + readSimpleField( + "TimeStamp", + new DataReaderComplexDefault<>(() -> DateAndTime.staticParse(readBuffer), readBuffer)); + + readBuffer.closeContext("S7PayloadUserDataItemClkFResponse"); + // Create the instance + return new S7PayloadUserDataItemClkFResponseBuilderImpl(Reserved, Year1, TimeStamp); + } + + public static class S7PayloadUserDataItemClkFResponseBuilderImpl + implements S7PayloadUserDataItem.S7PayloadUserDataItemBuilder { + private final short Reserved; + private final short Year1; + private final DateAndTime TimeStamp; + + public S7PayloadUserDataItemClkFResponseBuilderImpl( + short Reserved, short Year1, DateAndTime TimeStamp) { + this.Reserved = Reserved; + this.Year1 = Year1; + this.TimeStamp = TimeStamp; + } + + public S7PayloadUserDataItemClkFResponse build( + DataTransportErrorCode returnCode, DataTransportSize transportSize, int dataLength) { + S7PayloadUserDataItemClkFResponse s7PayloadUserDataItemClkFResponse = + new S7PayloadUserDataItemClkFResponse( + returnCode, transportSize, dataLength, Reserved, Year1, TimeStamp); + return s7PayloadUserDataItemClkFResponse; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof S7PayloadUserDataItemClkFResponse)) { + return false; + } + S7PayloadUserDataItemClkFResponse that = (S7PayloadUserDataItemClkFResponse) o; + return (getReserved() == that.getReserved()) + && (getYear1() == that.getYear1()) + && (getTimeStamp() == that.getTimeStamp()) + && super.equals(that) + && true; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), getReserved(), getYear1(), getTimeStamp()); + } + + @Override + public String toString() { + WriteBufferBoxBased writeBufferBoxBased = new WriteBufferBoxBased(true, true); + try { + writeBufferBoxBased.writeSerializable(this); + } catch (SerializationException e) { + throw new RuntimeException(e); + } + return "\n" + writeBufferBoxBased.getBox().toString() + "\n"; + } +} diff --git a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7PayloadUserDataItemClkRequest.java b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7PayloadUserDataItemClkRequest.java new file mode 100644 index 00000000000..2ac4fc7b39f --- /dev/null +++ b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7PayloadUserDataItemClkRequest.java @@ -0,0 +1,134 @@ +/* + * 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 + * + * https://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.readwrite; + +import static org.apache.plc4x.java.spi.codegen.fields.FieldReaderFactory.*; +import static org.apache.plc4x.java.spi.codegen.fields.FieldWriterFactory.*; +import static org.apache.plc4x.java.spi.codegen.io.DataReaderFactory.*; +import static org.apache.plc4x.java.spi.codegen.io.DataWriterFactory.*; +import static org.apache.plc4x.java.spi.generation.StaticHelper.*; + +import java.time.*; +import java.util.*; +import org.apache.plc4x.java.api.exceptions.*; +import org.apache.plc4x.java.api.value.*; +import org.apache.plc4x.java.spi.codegen.*; +import org.apache.plc4x.java.spi.codegen.fields.*; +import org.apache.plc4x.java.spi.codegen.io.*; +import org.apache.plc4x.java.spi.generation.*; + +// Code generated by code-generation. DO NOT EDIT. + +public class S7PayloadUserDataItemClkRequest extends S7PayloadUserDataItem implements Message { + + // Accessors for discriminator values. + public Byte getCpuFunctionGroup() { + return (byte) 0x07; + } + + public Byte getCpuFunctionType() { + return (byte) 0x04; + } + + public Short getCpuSubfunction() { + return (short) 0x01; + } + + public S7PayloadUserDataItemClkRequest( + DataTransportErrorCode returnCode, DataTransportSize transportSize, int dataLength) { + super(returnCode, transportSize, dataLength); + } + + @Override + protected void serializeS7PayloadUserDataItemChild(WriteBuffer writeBuffer) + throws SerializationException { + PositionAware positionAware = writeBuffer; + boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); + writeBuffer.pushContext("S7PayloadUserDataItemClkRequest"); + + writeBuffer.popContext("S7PayloadUserDataItemClkRequest"); + } + + @Override + public int getLengthInBytes() { + return (int) Math.ceil((float) getLengthInBits() / 8.0); + } + + @Override + public int getLengthInBits() { + int lengthInBits = super.getLengthInBits(); + S7PayloadUserDataItemClkRequest _value = this; + boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); + + return lengthInBits; + } + + public static S7PayloadUserDataItemBuilder staticParseS7PayloadUserDataItemBuilder( + ReadBuffer readBuffer, Byte cpuFunctionGroup, Byte cpuFunctionType, Short cpuSubfunction) + throws ParseException { + readBuffer.pullContext("S7PayloadUserDataItemClkRequest"); + PositionAware positionAware = readBuffer; + boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); + + readBuffer.closeContext("S7PayloadUserDataItemClkRequest"); + // Create the instance + return new S7PayloadUserDataItemClkRequestBuilderImpl(); + } + + public static class S7PayloadUserDataItemClkRequestBuilderImpl + implements S7PayloadUserDataItem.S7PayloadUserDataItemBuilder { + + public S7PayloadUserDataItemClkRequestBuilderImpl() {} + + public S7PayloadUserDataItemClkRequest build( + DataTransportErrorCode returnCode, DataTransportSize transportSize, int dataLength) { + S7PayloadUserDataItemClkRequest s7PayloadUserDataItemClkRequest = + new S7PayloadUserDataItemClkRequest(returnCode, transportSize, dataLength); + return s7PayloadUserDataItemClkRequest; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof S7PayloadUserDataItemClkRequest)) { + return false; + } + S7PayloadUserDataItemClkRequest that = (S7PayloadUserDataItemClkRequest) o; + return super.equals(that) && true; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + @Override + public String toString() { + WriteBufferBoxBased writeBufferBoxBased = new WriteBufferBoxBased(true, true); + try { + writeBufferBoxBased.writeSerializable(this); + } catch (SerializationException e) { + throw new RuntimeException(e); + } + return "\n" + writeBufferBoxBased.getBox().toString() + "\n"; + } +} diff --git a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7PayloadUserDataItemClkResponse.java b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7PayloadUserDataItemClkResponse.java new file mode 100644 index 00000000000..3ebeb32ca99 --- /dev/null +++ b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7PayloadUserDataItemClkResponse.java @@ -0,0 +1,203 @@ +/* + * 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 + * + * https://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.readwrite; + +import static org.apache.plc4x.java.spi.codegen.fields.FieldReaderFactory.*; +import static org.apache.plc4x.java.spi.codegen.fields.FieldWriterFactory.*; +import static org.apache.plc4x.java.spi.codegen.io.DataReaderFactory.*; +import static org.apache.plc4x.java.spi.codegen.io.DataWriterFactory.*; +import static org.apache.plc4x.java.spi.generation.StaticHelper.*; + +import java.time.*; +import java.util.*; +import org.apache.plc4x.java.api.exceptions.*; +import org.apache.plc4x.java.api.value.*; +import org.apache.plc4x.java.spi.codegen.*; +import org.apache.plc4x.java.spi.codegen.fields.*; +import org.apache.plc4x.java.spi.codegen.io.*; +import org.apache.plc4x.java.spi.generation.*; + +// Code generated by code-generation. DO NOT EDIT. + +public class S7PayloadUserDataItemClkResponse extends S7PayloadUserDataItem implements Message { + + // Accessors for discriminator values. + public Byte getCpuFunctionGroup() { + return (byte) 0x07; + } + + public Byte getCpuFunctionType() { + return (byte) 0x08; + } + + public Short getCpuSubfunction() { + return (short) 0x01; + } + + // Properties. + protected final short Reserved; + protected final short Year1; + protected final DateAndTime TimeStamp; + + public S7PayloadUserDataItemClkResponse( + DataTransportErrorCode returnCode, + DataTransportSize transportSize, + int dataLength, + short Reserved, + short Year1, + DateAndTime TimeStamp) { + super(returnCode, transportSize, dataLength); + this.Reserved = Reserved; + this.Year1 = Year1; + this.TimeStamp = TimeStamp; + } + + public short getReserved() { + return Reserved; + } + + public short getYear1() { + return Year1; + } + + public DateAndTime getTimeStamp() { + return TimeStamp; + } + + @Override + protected void serializeS7PayloadUserDataItemChild(WriteBuffer writeBuffer) + throws SerializationException { + PositionAware positionAware = writeBuffer; + boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); + writeBuffer.pushContext("S7PayloadUserDataItemClkResponse"); + + // Simple Field (Reserved) + writeSimpleField("Reserved", Reserved, writeUnsignedShort(writeBuffer, 8)); + + // Simple Field (Year1) + writeSimpleField("Year1", Year1, writeUnsignedShort(writeBuffer, 8)); + + // Simple Field (TimeStamp) + writeSimpleField("TimeStamp", TimeStamp, new DataWriterComplexDefault<>(writeBuffer)); + + writeBuffer.popContext("S7PayloadUserDataItemClkResponse"); + } + + @Override + public int getLengthInBytes() { + return (int) Math.ceil((float) getLengthInBits() / 8.0); + } + + @Override + public int getLengthInBits() { + int lengthInBits = super.getLengthInBits(); + S7PayloadUserDataItemClkResponse _value = this; + boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); + + // Simple field (Reserved) + lengthInBits += 8; + + // Simple field (Year1) + lengthInBits += 8; + + // Simple field (TimeStamp) + lengthInBits += TimeStamp.getLengthInBits(); + + return lengthInBits; + } + + public static S7PayloadUserDataItemBuilder staticParseS7PayloadUserDataItemBuilder( + ReadBuffer readBuffer, + Integer dataLength, + Byte cpuFunctionGroup, + Byte cpuFunctionType, + Short cpuSubfunction) + throws ParseException { + readBuffer.pullContext("S7PayloadUserDataItemClkResponse"); + PositionAware positionAware = readBuffer; + boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); + + short Reserved = readSimpleField("Reserved", readUnsignedShort(readBuffer, 8)); + + short Year1 = readSimpleField("Year1", readUnsignedShort(readBuffer, 8)); + + DateAndTime TimeStamp = + readSimpleField( + "TimeStamp", + new DataReaderComplexDefault<>(() -> DateAndTime.staticParse(readBuffer), readBuffer)); + + readBuffer.closeContext("S7PayloadUserDataItemClkResponse"); + // Create the instance + return new S7PayloadUserDataItemClkResponseBuilderImpl(Reserved, Year1, TimeStamp); + } + + public static class S7PayloadUserDataItemClkResponseBuilderImpl + implements S7PayloadUserDataItem.S7PayloadUserDataItemBuilder { + private final short Reserved; + private final short Year1; + private final DateAndTime TimeStamp; + + public S7PayloadUserDataItemClkResponseBuilderImpl( + short Reserved, short Year1, DateAndTime TimeStamp) { + this.Reserved = Reserved; + this.Year1 = Year1; + this.TimeStamp = TimeStamp; + } + + public S7PayloadUserDataItemClkResponse build( + DataTransportErrorCode returnCode, DataTransportSize transportSize, int dataLength) { + S7PayloadUserDataItemClkResponse s7PayloadUserDataItemClkResponse = + new S7PayloadUserDataItemClkResponse( + returnCode, transportSize, dataLength, Reserved, Year1, TimeStamp); + return s7PayloadUserDataItemClkResponse; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof S7PayloadUserDataItemClkResponse)) { + return false; + } + S7PayloadUserDataItemClkResponse that = (S7PayloadUserDataItemClkResponse) o; + return (getReserved() == that.getReserved()) + && (getYear1() == that.getYear1()) + && (getTimeStamp() == that.getTimeStamp()) + && super.equals(that) + && true; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), getReserved(), getYear1(), getTimeStamp()); + } + + @Override + public String toString() { + WriteBufferBoxBased writeBufferBoxBased = new WriteBufferBoxBased(true, true); + try { + writeBufferBoxBased.writeSerializable(this); + } catch (SerializationException e) { + throw new RuntimeException(e); + } + return "\n" + writeBufferBoxBased.getBox().toString() + "\n"; + } +} diff --git a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7PayloadUserDataItemClkSetRequest.java b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7PayloadUserDataItemClkSetRequest.java new file mode 100644 index 00000000000..9de7ca3487d --- /dev/null +++ b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7PayloadUserDataItemClkSetRequest.java @@ -0,0 +1,177 @@ +/* + * 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 + * + * https://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.readwrite; + +import static org.apache.plc4x.java.spi.codegen.fields.FieldReaderFactory.*; +import static org.apache.plc4x.java.spi.codegen.fields.FieldWriterFactory.*; +import static org.apache.plc4x.java.spi.codegen.io.DataReaderFactory.*; +import static org.apache.plc4x.java.spi.codegen.io.DataWriterFactory.*; +import static org.apache.plc4x.java.spi.generation.StaticHelper.*; + +import java.time.*; +import java.util.*; +import org.apache.plc4x.java.api.exceptions.*; +import org.apache.plc4x.java.api.value.*; +import org.apache.plc4x.java.spi.codegen.*; +import org.apache.plc4x.java.spi.codegen.fields.*; +import org.apache.plc4x.java.spi.codegen.io.*; +import org.apache.plc4x.java.spi.generation.*; + +// Code generated by code-generation. DO NOT EDIT. + +public class S7PayloadUserDataItemClkSetRequest extends S7PayloadUserDataItem implements Message { + + // Accessors for discriminator values. + public Byte getCpuFunctionGroup() { + return (byte) 0x07; + } + + public Byte getCpuFunctionType() { + return (byte) 0x04; + } + + public Short getCpuSubfunction() { + return (short) 0x04; + } + + // Properties. + protected final DateAndTime TimeStamp; + + public S7PayloadUserDataItemClkSetRequest( + DataTransportErrorCode returnCode, + DataTransportSize transportSize, + int dataLength, + DateAndTime TimeStamp) { + super(returnCode, transportSize, dataLength); + this.TimeStamp = TimeStamp; + } + + public DateAndTime getTimeStamp() { + return TimeStamp; + } + + @Override + protected void serializeS7PayloadUserDataItemChild(WriteBuffer writeBuffer) + throws SerializationException { + PositionAware positionAware = writeBuffer; + boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); + writeBuffer.pushContext("S7PayloadUserDataItemClkSetRequest"); + + // Reserved Field (reserved) + writeReservedField("reserved", (short) 0x00, writeUnsignedShort(writeBuffer, 8)); + + // Reserved Field (reserved) + writeReservedField("reserved", (short) 0x00, writeUnsignedShort(writeBuffer, 8)); + + // Simple Field (TimeStamp) + writeSimpleField("TimeStamp", TimeStamp, new DataWriterComplexDefault<>(writeBuffer)); + + writeBuffer.popContext("S7PayloadUserDataItemClkSetRequest"); + } + + @Override + public int getLengthInBytes() { + return (int) Math.ceil((float) getLengthInBits() / 8.0); + } + + @Override + public int getLengthInBits() { + int lengthInBits = super.getLengthInBits(); + S7PayloadUserDataItemClkSetRequest _value = this; + boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); + + // Reserved Field (reserved) + lengthInBits += 8; + + // Reserved Field (reserved) + lengthInBits += 8; + + // Simple field (TimeStamp) + lengthInBits += TimeStamp.getLengthInBits(); + + return lengthInBits; + } + + public static S7PayloadUserDataItemBuilder staticParseS7PayloadUserDataItemBuilder( + ReadBuffer readBuffer, Byte cpuFunctionGroup, Byte cpuFunctionType, Short cpuSubfunction) + throws ParseException { + readBuffer.pullContext("S7PayloadUserDataItemClkSetRequest"); + PositionAware positionAware = readBuffer; + boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); + + Short reservedField0 = + readReservedField("reserved", readUnsignedShort(readBuffer, 8), (short) 0x00); + + Short reservedField1 = + readReservedField("reserved", readUnsignedShort(readBuffer, 8), (short) 0x00); + + DateAndTime TimeStamp = + readSimpleField( + "TimeStamp", + new DataReaderComplexDefault<>(() -> DateAndTime.staticParse(readBuffer), readBuffer)); + + readBuffer.closeContext("S7PayloadUserDataItemClkSetRequest"); + // Create the instance + return new S7PayloadUserDataItemClkSetRequestBuilderImpl(TimeStamp); + } + + public static class S7PayloadUserDataItemClkSetRequestBuilderImpl + implements S7PayloadUserDataItem.S7PayloadUserDataItemBuilder { + private final DateAndTime TimeStamp; + + public S7PayloadUserDataItemClkSetRequestBuilderImpl(DateAndTime TimeStamp) { + this.TimeStamp = TimeStamp; + } + + public S7PayloadUserDataItemClkSetRequest build( + DataTransportErrorCode returnCode, DataTransportSize transportSize, int dataLength) { + S7PayloadUserDataItemClkSetRequest s7PayloadUserDataItemClkSetRequest = + new S7PayloadUserDataItemClkSetRequest(returnCode, transportSize, dataLength, TimeStamp); + return s7PayloadUserDataItemClkSetRequest; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof S7PayloadUserDataItemClkSetRequest)) { + return false; + } + S7PayloadUserDataItemClkSetRequest that = (S7PayloadUserDataItemClkSetRequest) o; + return (getTimeStamp() == that.getTimeStamp()) && super.equals(that) && true; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), getTimeStamp()); + } + + @Override + public String toString() { + WriteBufferBoxBased writeBufferBoxBased = new WriteBufferBoxBased(true, true); + try { + writeBufferBoxBased.writeSerializable(this); + } catch (SerializationException e) { + throw new RuntimeException(e); + } + return "\n" + writeBufferBoxBased.getBox().toString() + "\n"; + } +} diff --git a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7PayloadUserDataItemClkSetResponse.java b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7PayloadUserDataItemClkSetResponse.java new file mode 100644 index 00000000000..ece52dd08ee --- /dev/null +++ b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/S7PayloadUserDataItemClkSetResponse.java @@ -0,0 +1,134 @@ +/* + * 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 + * + * https://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.readwrite; + +import static org.apache.plc4x.java.spi.codegen.fields.FieldReaderFactory.*; +import static org.apache.plc4x.java.spi.codegen.fields.FieldWriterFactory.*; +import static org.apache.plc4x.java.spi.codegen.io.DataReaderFactory.*; +import static org.apache.plc4x.java.spi.codegen.io.DataWriterFactory.*; +import static org.apache.plc4x.java.spi.generation.StaticHelper.*; + +import java.time.*; +import java.util.*; +import org.apache.plc4x.java.api.exceptions.*; +import org.apache.plc4x.java.api.value.*; +import org.apache.plc4x.java.spi.codegen.*; +import org.apache.plc4x.java.spi.codegen.fields.*; +import org.apache.plc4x.java.spi.codegen.io.*; +import org.apache.plc4x.java.spi.generation.*; + +// Code generated by code-generation. DO NOT EDIT. + +public class S7PayloadUserDataItemClkSetResponse extends S7PayloadUserDataItem implements Message { + + // Accessors for discriminator values. + public Byte getCpuFunctionGroup() { + return (byte) 0x07; + } + + public Byte getCpuFunctionType() { + return (byte) 0x08; + } + + public Short getCpuSubfunction() { + return (short) 0x04; + } + + public S7PayloadUserDataItemClkSetResponse( + DataTransportErrorCode returnCode, DataTransportSize transportSize, int dataLength) { + super(returnCode, transportSize, dataLength); + } + + @Override + protected void serializeS7PayloadUserDataItemChild(WriteBuffer writeBuffer) + throws SerializationException { + PositionAware positionAware = writeBuffer; + boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); + writeBuffer.pushContext("S7PayloadUserDataItemClkSetResponse"); + + writeBuffer.popContext("S7PayloadUserDataItemClkSetResponse"); + } + + @Override + public int getLengthInBytes() { + return (int) Math.ceil((float) getLengthInBits() / 8.0); + } + + @Override + public int getLengthInBits() { + int lengthInBits = super.getLengthInBits(); + S7PayloadUserDataItemClkSetResponse _value = this; + boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); + + return lengthInBits; + } + + public static S7PayloadUserDataItemBuilder staticParseS7PayloadUserDataItemBuilder( + ReadBuffer readBuffer, Byte cpuFunctionGroup, Byte cpuFunctionType, Short cpuSubfunction) + throws ParseException { + readBuffer.pullContext("S7PayloadUserDataItemClkSetResponse"); + PositionAware positionAware = readBuffer; + boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); + + readBuffer.closeContext("S7PayloadUserDataItemClkSetResponse"); + // Create the instance + return new S7PayloadUserDataItemClkSetResponseBuilderImpl(); + } + + public static class S7PayloadUserDataItemClkSetResponseBuilderImpl + implements S7PayloadUserDataItem.S7PayloadUserDataItemBuilder { + + public S7PayloadUserDataItemClkSetResponseBuilderImpl() {} + + public S7PayloadUserDataItemClkSetResponse build( + DataTransportErrorCode returnCode, DataTransportSize transportSize, int dataLength) { + S7PayloadUserDataItemClkSetResponse s7PayloadUserDataItemClkSetResponse = + new S7PayloadUserDataItemClkSetResponse(returnCode, transportSize, dataLength); + return s7PayloadUserDataItemClkSetResponse; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof S7PayloadUserDataItemClkSetResponse)) { + return false; + } + S7PayloadUserDataItemClkSetResponse that = (S7PayloadUserDataItemClkSetResponse) o; + return super.equals(that) && true; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + @Override + public String toString() { + WriteBufferBoxBased writeBufferBoxBased = new WriteBufferBoxBased(true, true); + try { + writeBufferBoxBased.writeSerializable(this); + } catch (SerializationException e) { + throw new RuntimeException(e); + } + return "\n" + writeBufferBoxBased.getBox().toString() + "\n"; + } +} diff --git a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/TransportSize.java b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/TransportSize.java index b15a9817d8b..d99705e7540 100644 --- a/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/TransportSize.java +++ b/plc4j/drivers/s7/src/main/generated/org/apache/plc4x/java/s7/readwrite/TransportSize.java @@ -231,7 +231,7 @@ public enum TransportSize { (boolean) true, (short) 'B', (boolean) true, - DataTransportSize.OCTET_STRING, + DataTransportSize.BYTE_WORD_DWORD, (String) "IEC61131_CHAR", null), WCHAR( @@ -244,7 +244,7 @@ public enum TransportSize { (boolean) true, (short) 'X', (boolean) true, - DataTransportSize.OCTET_STRING, + null, (String) "IEC61131_WCHAR", null), STRING( @@ -257,7 +257,7 @@ public enum TransportSize { (boolean) true, (short) 'X', (boolean) true, - DataTransportSize.OCTET_STRING, + DataTransportSize.BYTE_WORD_DWORD, (String) "IEC61131_STRING", null), WSTRING( @@ -270,7 +270,7 @@ public enum TransportSize { (boolean) true, (short) 'X', (boolean) true, - DataTransportSize.OCTET_STRING, + null, (String) "IEC61131_WSTRING", null), TIME( @@ -325,6 +325,19 @@ public enum TransportSize { DataTransportSize.BYTE_WORD_DWORD, (String) "IEC61131_TIME_OF_DAY", null), + TOD( + (short) 0x19, + (boolean) true, + (boolean) true, + (short) 0x06, + (short) 4, + (boolean) true, + (boolean) true, + (short) 'X', + (boolean) true, + DataTransportSize.BYTE_WORD_DWORD, + (String) "IEC61131_TIME_OF_DAY", + null), DATE_AND_TIME( (short) 0x1A, (boolean) true, @@ -337,6 +350,19 @@ public enum TransportSize { (boolean) true, null, (String) "IEC61131_DATE_AND_TIME", + null), + DT( + (short) 0x1B, + (boolean) true, + (boolean) false, + (short) 0x0F, + (short) 12, + (boolean) true, + (boolean) false, + (short) 'X', + (boolean) true, + null, + (String) "IEC61131_DATE_AND_TIME", null); private static final Map map; diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/events/S7AlarmEvent.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/events/S7AlarmEvent.java index d338e1f0937..d88475ef091 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/events/S7AlarmEvent.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/events/S7AlarmEvent.java @@ -141,8 +141,8 @@ public enum Fields{ SIG_7_DATA_LENGTH, SIG_8_DATA_LENGTH, - } - + }; + private final Instant timeStamp; private final Map map; @@ -291,9 +291,10 @@ public S7AlarmEvent(Object obj) { } - } - - + }; + + + @Override public Map getMap() { return map; diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/events/S7CyclicEvent.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/events/S7CyclicEvent.java index a6d9fc37b9e..1010e3eee3a 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/events/S7CyclicEvent.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/events/S7CyclicEvent.java @@ -7,7 +7,7 @@ * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * 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 @@ -20,136 +20,205 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import org.apache.plc4x.java.api.messages.PlcReadRequest; -import org.apache.plc4x.java.api.messages.PlcSubscriptionRequest; -import org.apache.plc4x.java.api.model.PlcTag; -import org.apache.plc4x.java.api.types.PlcResponseCode; -import org.apache.plc4x.java.api.value.PlcValue; -import org.apache.plc4x.java.s7.readwrite.*; - import java.math.BigDecimal; import java.math.BigInteger; import java.nio.charset.Charset; +import java.time.Duration; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; -import java.util.*; +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 java.util.stream.Collectors; import java.util.stream.IntStream; +import org.apache.plc4x.java.api.messages.PlcReadRequest; +import org.apache.plc4x.java.api.messages.PlcSubscriptionRequest; +import org.apache.plc4x.java.api.model.PlcTag; +import org.apache.plc4x.java.api.types.PlcResponseCode; +import org.apache.plc4x.java.api.value.PlcValue; +import org.apache.plc4x.java.s7.readwrite.S7PayloadUserDataItemCyclicServicesChangeDrivenPush; +import org.apache.plc4x.java.s7.readwrite.S7PayloadUserDataItemCyclicServicesChangeDrivenSubscribeResponse; +import org.apache.plc4x.java.s7.readwrite.S7PayloadUserDataItemCyclicServicesPush; +import org.apache.plc4x.java.s7.readwrite.S7PayloadUserDataItemCyclicServicesSubscribeResponse; +import org.apache.plc4x.java.s7.readwrite.utils.StaticHelper; /** + * * @author cgarcia */ public class S7CyclicEvent implements S7Event { - public enum Fields { + public enum Fields{ TYPE, JOBID, - TIMESTAMP, + TIMESTAMP, ITEMSCOUNT, REQUEST, MAP, RETURNCODE_, TRANSPORTSIZE_, DATA_ - } - + } + private final PlcSubscriptionRequest request; - + private final Instant timeStamp; - private final Map map; - + private final Map map; + private int j; - - public S7CyclicEvent(PlcSubscriptionRequest request, short jobId, S7PayloadUserDataItemCyclicServicesPush event) { - this.map = new HashMap<>(); - this.timeStamp = Instant.now(); - this.request = request; - map.put(Fields.TYPE.name(), "CYCEVENT"); - map.put(Fields.TIMESTAMP.name(), this.timeStamp); - map.put(Fields.JOBID.name(), jobId); - map.put(Fields.ITEMSCOUNT.name(), event.getItemsCount()); - for (int i = 0; i < event.getItemsCount(); i++) { - AssociatedValueType associatedValueType = event.getItems().get(i); - map.put(Fields.RETURNCODE_.name() + i, associatedValueType.getReturnCode().getValue()); - map.put(Fields.TRANSPORTSIZE_.name() + i, associatedValueType.getTransportSize().getValue()); - byte[] buffer = new byte[associatedValueType.getData().size()]; + + public S7CyclicEvent(PlcSubscriptionRequest request, short jobid, S7PayloadUserDataItemCyclicServicesPush event) { + this.map = new HashMap(); + this.timeStamp = Instant.now(); + this.request = request; + map.put(Fields.TYPE.name(), "CYCEVENT"); + map.put(Fields.TIMESTAMP.name(),this.timeStamp); + map.put(Fields.JOBID.name(), jobid); + map.put(Fields.ITEMSCOUNT.name(), event.getItemsCount()); + int[] n = new int[1]; + n[0] = 0; + request.getTagNames().forEach(tagname -> { + int i = n[0]; + map.put(Fields.RETURNCODE_.name()+i, event.getItems().get(i).getReturnCode().getValue()); + map.put(Fields.TRANSPORTSIZE_.name()+i, event.getItems().get(i).getTransportSize().getValue()); + byte[] buffer = new byte[event.getItems().get(i).getData().size()]; j = 0; - associatedValueType.getData().forEach(s -> { - buffer[j] = s.byteValue(); - j++; - }); - map.put(Fields.DATA_.name() + i, buffer); - } - } - - public S7CyclicEvent(PlcSubscriptionRequest request, short jobId, S7PayloadUserDataItemCyclicServicesChangeDrivenPush event) { - this.map = new HashMap<>(); - this.timeStamp = Instant.now(); + event.getItems().get(i).getData().forEach(s->{ + buffer[j] = s.byteValue(); + j ++; + }); + map.put(tagname, buffer); + n[0]++; + }); + + +// for (int i=0; i{ +// buffer[j] = s.byteValue(); +// j ++; +// }); +// map.put(Fields.DATA_.name()+i, buffer); +// } + } + + public S7CyclicEvent(PlcSubscriptionRequest request, short jobid, S7PayloadUserDataItemCyclicServicesChangeDrivenPush event) { + this.map = new HashMap(); + this.timeStamp = Instant.now(); this.request = request; - map.put(Fields.TYPE.name(), "CYCEVENT"); - map.put(Fields.TIMESTAMP.name(), this.timeStamp); - map.put(Fields.JOBID.name(), jobId); - map.put(Fields.ITEMSCOUNT.name(), event.getItemsCount()); - for (int i = 0; i < event.getItemsCount(); i++) { - AssociatedQueryValueType associatedQueryValueType = event.getItems().get(i); - map.put(Fields.RETURNCODE_.name() + i, associatedQueryValueType.getReturnCode().getValue()); - map.put(Fields.TRANSPORTSIZE_.name() + i, associatedQueryValueType.getTransportSize().getValue()); - byte[] buffer = new byte[associatedQueryValueType.getData().size()]; + map.put(Fields.TYPE.name(), "CYCEVENT"); + map.put(Fields.TIMESTAMP.name(),this.timeStamp); + map.put(Fields.JOBID.name(), jobid); + map.put(Fields.ITEMSCOUNT.name(), event.getItemsCount()); + int[] n = new int[1]; + n[0] = 0; + request.getTagNames().forEach(tagname -> { + int i = n[0]; + map.put(Fields.RETURNCODE_.name()+i, event.getItems().get(i).getReturnCode().getValue()); + map.put(Fields.TRANSPORTSIZE_.name()+i, event.getItems().get(i).getTransportSize().getValue()); + byte[] buffer = new byte[event.getItems().get(i).getData().size()]; j = 0; - associatedQueryValueType.getData().forEach(s -> { - buffer[j] = s.byteValue(); - j++; - }); - map.put(Fields.DATA_.name() + i, buffer); - } - } - - public S7CyclicEvent(PlcSubscriptionRequest request, short jobId, S7PayloadUserDataItemCyclicServicesSubscribeResponse event) { - this.map = new HashMap<>(); - this.timeStamp = Instant.now(); + event.getItems().get(i).getData().forEach(s->{ + buffer[j] = s.byteValue(); + j ++; + }); + map.put(tagname, buffer); + n[0]++; + }); +// for (int i=0; i{ +// buffer[j] = s.byteValue(); +// j ++; +// }); +// map.put(Fields.DATA_.name()+i, buffer); +// } + } + + public S7CyclicEvent(PlcSubscriptionRequest request, short jobid, S7PayloadUserDataItemCyclicServicesSubscribeResponse event) { + this.map = new HashMap(); + this.timeStamp = Instant.now(); this.request = request; - map.put(Fields.TYPE.name(), "CYCEVENT"); - map.put(Fields.TIMESTAMP.name(), this.timeStamp); - map.put(Fields.JOBID.name(), jobId); + map.put(Fields.TYPE.name(), "CYCEVENT"); + map.put(Fields.TIMESTAMP.name(),this.timeStamp); + map.put(Fields.JOBID.name(), jobid); map.put(Fields.ITEMSCOUNT.name(), event.getItemsCount()); - for (int i = 0; i < event.getItemsCount(); i++) { - AssociatedValueType associatedValueType = event.getItems().get(i); - map.put(Fields.RETURNCODE_.name() + i, associatedValueType.getReturnCode().getValue()); - map.put(Fields.TRANSPORTSIZE_.name() + i, associatedValueType.getTransportSize().getValue()); - byte[] buffer = new byte[associatedValueType.getData().size()]; + int[] n = new int[1]; + n[0] = 0; + request.getTagNames().forEach(tagname -> { + int i = n[0]; + map.put(Fields.RETURNCODE_.name()+i, event.getItems().get(i).getReturnCode().getValue()); + map.put(Fields.TRANSPORTSIZE_.name()+i, event.getItems().get(i).getTransportSize().getValue()); + byte[] buffer = new byte[event.getItems().get(i).getData().size()]; j = 0; - associatedValueType.getData().forEach(s -> { - buffer[j] = s.byteValue(); - j++; - }); - map.put(Fields.DATA_.name() + i, buffer); - } - } - - public S7CyclicEvent(PlcSubscriptionRequest request, short jobId, S7PayloadUserDataItemCyclicServicesChangeDrivenSubscribeResponse event) { - this.map = new HashMap<>(); - this.timeStamp = Instant.now(); + event.getItems().get(i).getData().forEach(s->{ + buffer[j] = s.byteValue(); + j ++; + }); + map.put(tagname, buffer); + n[0]++; + }); +// for (int i=0; i{ +// buffer[j] = s.byteValue(); +// j ++; +// }); +// map.put(Fields.DATA_.name()+i, buffer); +// } + } + + public S7CyclicEvent(PlcSubscriptionRequest request, short jobid, S7PayloadUserDataItemCyclicServicesChangeDrivenSubscribeResponse event) { + this.map = new HashMap(); + this.timeStamp = Instant.now(); this.request = request; - map.put(Fields.TYPE.name(), "CYCEVENT"); - map.put(Fields.TIMESTAMP.name(), this.timeStamp); - map.put(Fields.JOBID.name(), jobId); + map.put(Fields.TYPE.name(), "CYCEVENT"); + map.put(Fields.TIMESTAMP.name(),this.timeStamp); + map.put(Fields.JOBID.name(), jobid); map.put(Fields.ITEMSCOUNT.name(), event.getItemsCount()); - for (int i = 0; i < event.getItemsCount(); i++) { - AssociatedQueryValueType associatedQueryValueType = event.getItems().get(i); - map.put(Fields.RETURNCODE_.name() + i, associatedQueryValueType.getReturnCode().getValue()); - map.put(Fields.TRANSPORTSIZE_.name() + i, associatedQueryValueType.getTransportSize().getValue()); - byte[] buffer = new byte[associatedQueryValueType.getData().size()]; + int[] n = new int[1]; + n[0] = 0; + request.getTagNames().forEach(tagname -> { + int i = n[0]; + map.put(Fields.RETURNCODE_.name()+i, event.getItems().get(i).getReturnCode().getValue()); + map.put(Fields.TRANSPORTSIZE_.name()+i, event.getItems().get(i).getTransportSize().getValue()); + byte[] buffer = new byte[event.getItems().get(i).getData().size()]; j = 0; - associatedQueryValueType.getData().forEach(s -> { - buffer[j] = s.byteValue(); - j++; - }); - map.put(Fields.DATA_.name() + i, buffer); - } - } - + event.getItems().get(i).getData().forEach(s->{ + buffer[j] = s.byteValue(); + j ++; + }); + map.put(tagname, buffer); + n[0]++; + }); +// for (int i=0; i{ +// buffer[j] = s.byteValue(); +// j ++; +// }); +// map.put(Fields.DATA_.name()+i, buffer); +// } + } + @Override public Map getMap() { return this.map; @@ -162,22 +231,22 @@ public Instant getTimestamp() { @Override public PlcReadRequest getRequest() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); } @Override public PlcValue getAsPlcValue() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); } @Override public PlcValue getPlcValue(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); } @Override public int getNumberOfValues(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); } @Override @@ -188,60 +257,72 @@ public Object getObject(String name) { @Override public Object getObject(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); } @Override public Collection getAllObjects(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); } @Override public boolean isValidBoolean(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return isValidBoolean(name, 0); } @Override public boolean isValidBoolean(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + try { + boolean dummy = getBoolean(name, index); + return true; + } catch (Exception ex) { + return false; + } } @Override public Boolean getBoolean(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return getBoolean(name, 0); } @Override public Boolean getBoolean(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + if (!(map.get(name) instanceof byte[])) + throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); + ByteBuf byteBuf = Unpooled.wrappedBuffer((byte[]) map.get(name)); + int pos = index * 1; + return byteBuf.getBoolean(pos); } @Override public Collection getAllBooleans(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); } @Override public boolean isValidByte(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return isValidByte(name, 0); } @Override public boolean isValidByte(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + try { + byte dummy = getByte(name, index); + return true; + } catch (Exception ex) { + return false; + } } @Override public Byte getByte(String name) { - if (!(map.get(name) instanceof Byte)) - throw new UnsupportedOperationException("Field is not a Byte. Required Byte type."); - return (byte) map.get(name); + return getByte(name, 0); } @Override public Byte getByte(String name, int index) { - if (!(map.get(name) instanceof byte[])) - throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); + if (!(map.get(name) instanceof byte[])) + throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); ByteBuf byteBuf = Unpooled.wrappedBuffer((byte[]) map.get(name)); int pos = index * Byte.BYTES; return byteBuf.getByte(pos); @@ -249,68 +330,79 @@ public Byte getByte(String name, int index) { @Override public Collection getAllBytes(String name) { - if (!(map.get(name) instanceof byte[])) + if (!(map.get(name) instanceof byte[])) throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); byte[] array = (byte[]) map.get(name); - - return IntStream.range(0, array.length). - mapToObj(i -> array[i]).collect(Collectors.toList()); + + List list = IntStream.range(0, array.length). + mapToObj(i -> array[i]).collect(Collectors.toList()); + + return list; } @Override public boolean isValidShort(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return isValidShort(name, 0); } @Override public boolean isValidShort(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + try { + short dummy = getShort(name, index); + return true; + } catch (Exception ex) { + return false; + } } @Override public Short getShort(String name) { - if (!(map.get(name) instanceof Short)) return null; - return (short) map.get(name); + return getShort(name, 0); } @Override public Short getShort(String name, int index) { - if (!(map.get(name) instanceof byte[])) - throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); + if (!(map.get(name) instanceof byte[])) + throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); ByteBuf byteBuf = Unpooled.wrappedBuffer((byte[]) map.get(name)); int pos = index * Short.BYTES; - return byteBuf.getShort(index); + return byteBuf.getShort(pos); } @Override public Collection getAllShorts(String name) { - if (!(map.get(name) instanceof byte[])) + if (!(map.get(name) instanceof byte[])) throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); ByteBuf byteBuf = Unpooled.wrappedBuffer((byte[]) map.get(name)); - List list = new ArrayList<>(); - while (byteBuf.isReadable(Short.BYTES)) list.add(byteBuf.readShort()); + List list = new ArrayList(); + while(byteBuf.isReadable(Short.BYTES)) list.add(byteBuf.readShort()); return list; } @Override public boolean isValidInteger(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return isValidInteger(name, 0); } @Override public boolean isValidInteger(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + try { + int dummy = getInteger(name, index); + return true; + } catch (Exception ex) { + return false; + } } @Override public Integer getInteger(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return getInteger(name, 0); } @Override public Integer getInteger(String name, int index) { - if (!(map.get(name) instanceof byte[])) - throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); + if (!(map.get(name) instanceof byte[])) + throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); ByteBuf byteBuf = Unpooled.wrappedBuffer((byte[]) map.get(name)); int pos = index * Integer.BYTES; return byteBuf.getInt(pos); @@ -318,179 +410,199 @@ public Integer getInteger(String name, int index) { @Override public Collection getAllIntegers(String name) { - if (!(map.get(name) instanceof byte[])) - throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); + if (!(map.get(name) instanceof byte[])) + throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); ByteBuf byteBuf = Unpooled.wrappedBuffer((byte[]) map.get(name)); - List list = new ArrayList<>(); - while (byteBuf.isReadable(Integer.BYTES)) list.add(byteBuf.readInt()); + List list = new ArrayList(); + while(byteBuf.isReadable(Integer.BYTES)) list.add(byteBuf.readInt()); return list; } @Override public boolean isValidBigInteger(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); } @Override public boolean isValidBigInteger(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); } @Override public BigInteger getBigInteger(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); } @Override public BigInteger getBigInteger(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); } @Override public Collection getAllBigIntegers(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); } @Override public boolean isValidLong(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return isValidLong(name, 0); } @Override public boolean isValidLong(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + try { + long dummy = getLong(name, index); + return true; + } catch (Exception ex) { + return false; + } } @Override public Long getLong(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return getLong(name, 0); } @Override public Long getLong(String name, int index) { - if (!(map.get(name) instanceof byte[])) - throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); + if (!(map.get(name) instanceof byte[])) + throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); ByteBuf byteBuf = Unpooled.wrappedBuffer((byte[]) map.get(name)); - int pos = index * Long.BYTES; + int pos = index*Long.BYTES; return byteBuf.getLong(pos); } @Override public Collection getAllLongs(String name) { - if (!(map.get(name) instanceof byte[])) - throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); + if (!(map.get(name) instanceof byte[])) + throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); ByteBuf byteBuf = Unpooled.wrappedBuffer((byte[]) map.get(name)); - List list = new ArrayList<>(); - while (byteBuf.isReadable(Long.BYTES)) list.add(byteBuf.readLong()); + List list = new ArrayList(); + while(byteBuf.isReadable(Long.BYTES)) list.add(byteBuf.readLong()); return list; } @Override public boolean isValidFloat(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return isValidFloat(name, 0); } @Override public boolean isValidFloat(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + try { + float dummy = getFloat(name, index); + return true; + } catch (Exception ex) { + return false; + } } @Override public Float getFloat(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return getFloat(name, 0); } @Override public Float getFloat(String name, int index) { - if (!(map.get(name) instanceof byte[])) - throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); + if (!(map.get(name) instanceof byte[])) + throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); ByteBuf byteBuf = Unpooled.wrappedBuffer((byte[]) map.get(name)); - int pos = index * Float.BYTES; + int pos = index*Float.BYTES; return byteBuf.getFloat(pos); } @Override public Collection getAllFloats(String name) { - if (!(map.get(name) instanceof byte[])) - throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); + if (!(map.get(name) instanceof byte[])) + throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); ByteBuf byteBuf = Unpooled.wrappedBuffer((byte[]) map.get(name)); - List list = new ArrayList<>(); - while (byteBuf.isReadable(Float.BYTES)) list.add(byteBuf.readFloat()); + List list = new ArrayList(); + while(byteBuf.isReadable(Float.BYTES)) list.add(byteBuf.readFloat()); return list; } @Override public boolean isValidDouble(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return isValidDouble(name, 0); } @Override public boolean isValidDouble(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + try { + double dummy = getDouble(name, index); + return true; + } catch (Exception ex) { + return false; + } } @Override public Double getDouble(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return getDouble(name, 0); } @Override public Double getDouble(String name, int index) { - if (!(map.get(name) instanceof byte[])) - throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); + if (!(map.get(name) instanceof byte[])) + throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); ByteBuf byteBuf = Unpooled.wrappedBuffer((byte[]) map.get(name)); - int pos = index * Double.BYTES; + int pos = index*Double.BYTES; return byteBuf.getDouble(pos); } @Override public Collection getAllDoubles(String name) { - if (!(map.get(name) instanceof byte[])) - throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); + if (!(map.get(name) instanceof byte[])) + throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); ByteBuf byteBuf = Unpooled.wrappedBuffer((byte[]) map.get(name)); - List list = new ArrayList<>(); - while (byteBuf.isReadable(Double.BYTES)) list.add(byteBuf.readDouble()); + List list = new ArrayList(); + while(byteBuf.isReadable(Double.BYTES)) list.add(byteBuf.readDouble()); return list; } @Override public boolean isValidBigDecimal(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); } @Override public boolean isValidBigDecimal(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); } @Override public BigDecimal getBigDecimal(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); } @Override public BigDecimal getBigDecimal(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); } @Override public Collection getAllBigDecimals(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); } @Override public boolean isValidString(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return isValidString(name, 0); } @Override public boolean isValidString(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + try { + String dummy = getString(name, index); + return true; + } catch (Exception ex) { + return false; + } } @Override public String getString(String name) { - if (!(map.get(name) instanceof byte[])) + if (!(map.get(name) instanceof byte[])) throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); ByteBuf byteBuf = Unpooled.wrappedBuffer((byte[]) map.get(name)); return byteBuf.toString(Charset.defaultCharset()); @@ -498,103 +610,176 @@ public String getString(String name) { @Override public String getString(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); } @Override public Collection getAllStrings(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + throw new UnsupportedOperationException("Not supported yet."); } @Override public boolean isValidTime(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return isValidTime(name, 0); } @Override public boolean isValidTime(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + try { + LocalTime dummy = getTime(name, index); + return true; + } catch (Exception ex) { + return false; + } } @Override public LocalTime getTime(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return getTime(name, 0); } + /* + * In S7, data type TIME occupies one double word. + * The value is in milliseconds (ms). + */ @Override public LocalTime getTime(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + if (!(map.get(name) instanceof byte[])) + throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); + ByteBuf byteBuf = Unpooled.wrappedBuffer((byte[]) map.get(name)); + int pos = index * Integer.BYTES; + int value = byteBuf.getInt(pos); + Duration dr = StaticHelper.S7TimeToDuration(value); + LocalTime time = LocalTime.of((int) dr.toHoursPart(), (int) dr.toMinutesPart(), (int) dr.toSecondsPart(), (int) dr.toNanosPart()); + return time; } @Override public Collection getAllTimes(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + if (!(map.get(name) instanceof byte[])) + throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); + ByteBuf byteBuf = Unpooled.wrappedBuffer((byte[]) map.get(name)); + int nitems = (byteBuf.capacity() / Integer.BYTES); + + List items = new ArrayList(); + + for (int i = 0; i < nitems; i++) { + items.add(getTime(name, i)); + } + + return items; } @Override public boolean isValidDate(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return isValidDate(name, 0); } @Override public boolean isValidDate(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + try { + LocalDate dummy = getDate(name, index); + return true; + } catch (Exception ex) { + return false; + } } @Override public LocalDate getDate(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return getDate(name, 0); } @Override public LocalDate getDate(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + if (!(map.get(name) instanceof byte[])) + throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); + ByteBuf byteBuf = Unpooled.wrappedBuffer((byte[]) map.get(name)); + int pos = index * Short.BYTES; + short value = byteBuf.getShort(pos); + LocalDate date = StaticHelper.S7DateToLocalDate(value); + + return date; } @Override public Collection getAllDates(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + if (!(map.get(name) instanceof byte[])) + throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); + ByteBuf byteBuf = Unpooled.wrappedBuffer((byte[]) map.get(name)); + int nitems = (byteBuf.capacity() / Short.BYTES); + + List items = new ArrayList(); + + for (int i = 0; i < nitems; i++) { + items.add(getDate(name, i)); + } + + return items; } @Override public boolean isValidDateTime(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return isValidDateTime(name, 0); } @Override public boolean isValidDateTime(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + try { + LocalDateTime dummy = getDateTime(name, index); + return true; + } catch (Exception ex) { + return false; + } } @Override public LocalDateTime getDateTime(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + return getDateTime(name, 0); } @Override public LocalDateTime getDateTime(String name, int index) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + if (!(map.get(name) instanceof byte[])) + throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); + ByteBuf byteBuf = Unpooled.wrappedBuffer((byte[]) map.get(name)); + int pos = index * Long.BYTES; + + LocalDateTime datetime = StaticHelper.S7DateTimeToLocalDateTime(byteBuf.slice(pos, Long.BYTES)); + + return datetime; } @Override public Collection getAllDateTimes(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + if (!(map.get(name) instanceof byte[])) + throw new UnsupportedOperationException("Field is not a buffer of bytes. Required byte[] type."); + ByteBuf byteBuf = Unpooled.wrappedBuffer((byte[]) map.get(name)); + int nitems = (byteBuf.capacity() / Long.BYTES); + + List items = new ArrayList(); + + for (int i = 0; i < nitems; i++) { + items.add(getDateTime(name, i)); + } + + return items; } @Override public Collection getTagNames() { - throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody + throw new UnsupportedOperationException("Not supported yet."); } @Override public PlcTag getTag(String name) { - throw new UnsupportedOperationException("Not supported yet."); // Generated from nbfs://nbhost/SystemFileSystem/Templates/Classes/Code/GeneratedMethodBody - } + throw new UnsupportedOperationException("Not supported yet."); + } @Override public PlcResponseCode getResponseCode(String name) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - + throw new UnsupportedOperationException("Not supported yet."); + } + + } diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/events/S7Event.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/events/S7Event.java index db3a97d94d1..6dab4537870 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/events/S7Event.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/events/S7Event.java @@ -46,7 +46,7 @@ public interface S7Event extends PlcSubscriptionEvent{ - Map getMap(); + public Map getMap(); } \ No newline at end of file diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/events/S7ModeEvent.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/events/S7ModeEvent.java index aeb1923ec85..d84122a60ac 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/events/S7ModeEvent.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/events/S7ModeEvent.java @@ -56,6 +56,7 @@ public S7ModeEvent(S7ParameterModeTransition parameter) { map.put(Fields.CURRENT_MODE.name(), parameter.getCurrentMode()); this.timeStamp = Instant.now(); map.put(Fields.TIMESTAMP .name(), this.timeStamp ); + map.put(Fields.MAP.name(), map); } diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/S7Driver.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/S7Driver.java index 28aa403c080..a619af0de3c 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/S7Driver.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/S7Driver.java @@ -27,12 +27,15 @@ import org.apache.plc4x.java.s7.readwrite.tag.S7PlcTagHandler; import org.apache.plc4x.java.spi.configuration.Configuration; import org.apache.plc4x.java.spi.connection.ProtocolStackConfigurer; +import org.apache.plc4x.java.spi.connection.GeneratedDriverBase; import org.apache.plc4x.java.spi.connection.SingleProtocolStackConfigurer; import org.apache.plc4x.java.spi.optimizer.BaseOptimizer; import org.apache.plc4x.java.spi.values.PlcValueHandler; import java.util.function.Consumer; import java.util.function.ToIntFunction; +import org.apache.plc4x.java.s7.readwrite.protocol.S7HGeneratedDriverBase; +import org.apache.plc4x.java.s7.readwrite.protocol.S7HSingleProtocolStackConfigurer; public class S7Driver extends S7HGeneratedDriverBase { @@ -100,7 +103,7 @@ protected boolean awaitDisconnectComplete() { @Override protected ProtocolStackConfigurer getStackConfigurer() { - return SingleProtocolStackConfigurer.builder(TPKTPacket.class, TPKTPacket::staticParse) + return S7HSingleProtocolStackConfigurer.builder(TPKTPacket.class, TPKTPacket::staticParse) .withProtocol(S7ProtocolLogic.class) .withDriverContext(S7DriverContext.class) .withPacketSizeEstimator(ByteLengthEstimator.class) @@ -134,5 +137,7 @@ public void accept(ByteBuf byteBuf) { public S7Tag prepareTag(String tagAddress){ return S7Tag.of(tagAddress); } + + } diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/S7HGeneratedDriverBase.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/S7HGeneratedDriverBase.java index a259f99fb94..e253b92aef4 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/S7HGeneratedDriverBase.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/S7HGeneratedDriverBase.java @@ -22,7 +22,6 @@ import org.apache.plc4x.java.api.authentication.PlcAuthentication; import org.apache.plc4x.java.api.exceptions.PlcConnectionException; import org.apache.plc4x.java.api.value.PlcValueHandler; -import org.apache.plc4x.java.s7.readwrite.configuration.S7TcpTransportConfiguration; import org.apache.plc4x.java.s7.readwrite.connection.S7HDefaultNettyPlcConnection; import org.apache.plc4x.java.spi.configuration.Configuration; import org.apache.plc4x.java.spi.configuration.ConfigurationFactory; @@ -31,8 +30,6 @@ import org.apache.plc4x.java.spi.connection.PlcTagHandler; import org.apache.plc4x.java.spi.connection.ProtocolStackConfigurer; import org.apache.plc4x.java.spi.transport.Transport; -import org.apache.plc4x.java.spi.transport.TransportConfiguration; -import org.apache.plc4x.java.spi.transport.TransportConfigurationTypeProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,7 +42,7 @@ /** * Customized version of a GeneratedDriverBase that supports opening two connections to a remote host. */ -public class S7HGeneratedDriverBase extends GeneratedDriverBase implements TransportConfigurationTypeProvider { +public class S7HGeneratedDriverBase extends GeneratedDriverBase { private static final Logger logger = LoggerFactory.getLogger(S7HGeneratedDriverBase.class); @@ -57,7 +54,6 @@ public class S7HGeneratedDriverBase extends GeneratedDriverBase impl @Override public PlcConnection getConnection(String connectionString) throws PlcConnectionException { - ConfigurationFactory configurationFactory = new ConfigurationFactory(); // Split up the connection string into its individual segments. Matcher smatcher = URI_PATTERN.matcher(connectionString); Matcher hmatcher = URI_H_PATTERN.matcher(connectionString); @@ -83,7 +79,7 @@ public PlcConnection getConnection(String connectionString) throws PlcConnection } // Create the configuration object. - Configuration configuration = configurationFactory.createConfiguration( + Configuration configuration = new ConfigurationFactory().createConfiguration( getConfigurationType(), protocolCode, transportCode, transportConfig, paramString); if (configuration == null) { throw new PlcConnectionException("Unsupported configuration"); @@ -103,19 +99,8 @@ public PlcConnection getConnection(String connectionString) throws PlcConnection throw new PlcConnectionException("Unsupported transport " + transportCode); } - // Find out the type of the transport configuration. - Class transportConfigurationType = transport.getTransportConfigType(); - Class driverTransportConfigurationType = getTransportConfigurationType(transportCode); - if(driverTransportConfigurationType != null) { - transportConfigurationType = driverTransportConfigurationType; - } - // Use the transport configuration type to actually configure the transport instance. - if(transportConfigurationType != null) { - Configuration transportConfiguration = configurationFactory - .createPrefixedConfiguration(transportConfigurationType, - transportCode, protocolCode, transportCode, transportConfig, paramString); - configure(transportConfiguration, transport); - } + // Inject the configuration into the transport. + configure(configuration, transport); // Create an instance of the communication channel which the driver should use. ChannelFactory channelFactory = transport.createChannelFactory(transportConfig); @@ -139,12 +124,6 @@ public PlcConnection getConnection(String connectionString) throws PlcConnection } } - // Make the "fire discover event" overridable via system property. - boolean fireDiscoverEvent = fireDiscoverEvent(); - if(System.getProperty(PROPERTY_PLC4X_FORCE_FIRE_DISCOVER_EVENT) != null) { - fireDiscoverEvent = Boolean.parseBoolean(System.getProperty(PROPERTY_PLC4X_FORCE_FIRE_DISCOVER_EVENT)); - } - // Make the "await setup complete" overridable via system property. boolean awaitSetupComplete = awaitSetupComplete(); if (System.getProperty(PROPERTY_PLC4X_FORCE_AWAIT_SETUP_COMPLETE) != null) { @@ -164,13 +143,14 @@ public PlcConnection getConnection(String connectionString) throws PlcConnection } return new S7HDefaultNettyPlcConnection( - canPing(), canRead(), canWrite(), canSubscribe(), canBrowse(), + canPing(), + canRead(), canWrite(), canSubscribe(), canBrowse(), getTagHandler(), getValueHandler(), configuration, channelFactory, secondaryChannelFactory, - fireDiscoverEvent, + false, awaitSetupComplete, awaitDisconnectComplete, awaitDiscoverComplete, @@ -219,13 +199,5 @@ public PlcAuthentication getAuthentication() { return null; } - @Override - public Class getTransportConfigurationType(String transportCode) { - switch (transportCode) { - case "tcp": - return S7TcpTransportConfiguration.class; - } - return null; - } } diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/configuration/S7Configuration.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/configuration/S7Configuration.java index 5b42c530725..7f71bfbff2d 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/configuration/S7Configuration.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/configuration/S7Configuration.java @@ -1,4 +1,4 @@ -/* +/* * 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 @@ -7,7 +7,7 @@ * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * 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 @@ -18,12 +18,14 @@ */ package org.apache.plc4x.java.s7.readwrite.configuration; +import org.apache.plc4x.java.s7.readwrite.S7Driver; import org.apache.plc4x.java.spi.configuration.Configuration; import org.apache.plc4x.java.spi.configuration.annotations.ConfigurationParameter; import org.apache.plc4x.java.spi.configuration.annotations.defaults.BooleanDefaultValue; import org.apache.plc4x.java.spi.configuration.annotations.defaults.IntDefaultValue; +import org.apache.plc4x.java.transport.tcp.TcpTransportConfiguration; -public class S7Configuration implements Configuration { +public class S7Configuration extends S7TcpTransportConfiguration implements Configuration { @ConfigurationParameter("local-rack") @IntDefaultValue(1) @@ -32,7 +34,7 @@ public class S7Configuration implements Configuration { @ConfigurationParameter("local-slot") @IntDefaultValue(1) public int localSlot = 1; - + @ConfigurationParameter("local-tsap") @IntDefaultValue(0) public int localTsap = 0; @@ -44,15 +46,15 @@ public class S7Configuration implements Configuration { @ConfigurationParameter("remote-slot") @IntDefaultValue(0) public int remoteSlot = 0; - + @ConfigurationParameter("remote-rack2") @IntDefaultValue(0) public int remoteRack2 = 0; @ConfigurationParameter("remote-slot2") @IntDefaultValue(0) - public int remoteSlot2 = 0; - + public int remoteSlot2 = 0; + @ConfigurationParameter("remote-tsap") @IntDefaultValue(0) @@ -72,22 +74,23 @@ public class S7Configuration implements Configuration { @ConfigurationParameter("controller-type") public String controllerType; - + @ConfigurationParameter("read-timeout") - @IntDefaultValue(8) - public int readTimeout = 8; - - @ConfigurationParameter("ping") - @BooleanDefaultValue(false) - public boolean ping = false; - - @ConfigurationParameter("ping-time") - @IntDefaultValue(-1) - public int pingTime = -1; - - @ConfigurationParameter("retry-time") - @IntDefaultValue(4) - public int retryTime = 4; + @IntDefaultValue(0) + public int readTimeout = 0; + + @ConfigurationParameter("ping") + @BooleanDefaultValue(false) + public boolean ping = false; + + @ConfigurationParameter("ping-time") + @IntDefaultValue(0) + public int pingTime = 0; + + @ConfigurationParameter("retry-time") + @IntDefaultValue(0) + public int retryTime = 0; + public int getLocalRack() { return localRack; @@ -112,7 +115,7 @@ public int getLocalTsap() { public void setLocalTsap(int localTsap) { this.localTsap = localTsap; } - + public int getRemoteRack() { return remoteRack; } @@ -128,7 +131,7 @@ public int getRemoteSlot() { public void setRemoteSlot(int remoteSlot) { this.remoteSlot = remoteSlot; } - + public int getRemoteRack2() { return remoteRack2; } @@ -143,7 +146,7 @@ public int getRemoteSlot2() { public void setRemoteSlot2(int remoteSlot2) { this.remoteSlot2 = remoteSlot2; - } + } public int getRemoteTsap() { return remoteTsap; @@ -152,7 +155,7 @@ public int getRemoteTsap() { public void setRemoteTsap(int remoteTsap) { this.remoteTsap = remoteTsap; } - + public int getPduSize() { return pduSize; } @@ -184,37 +187,47 @@ public String getControllerType() { public void setControllerType(String controllerType) { this.controllerType = controllerType; } - + public int getReadTimeout() { return readTimeout; } public void setReadTimeout(int readTimeOut) { this.readTimeout = readTimeOut; - } - + } + public boolean getPing() { return ping; } public void setPing(boolean ping) { this.ping = ping; - } - + } + public int getPingTime() { return pingTime; } public void setPingTime(int pingTime) { this.pingTime = pingTime; - } - + } + public int getRetryTime() { - return pingTime; + return retryTime; } public void setRetryTime(int retryTime) { this.retryTime = retryTime; + } + + + /** + * Per default port for the S7 protocol is 102. + * @return 102 + */ + @Override + public int getDefaultPort() { + return S7Driver.ISO_ON_TCP_PORT; } @Override @@ -226,16 +239,17 @@ public String toString() { ", remote-rack=" + remoteRack + ", remote-slot=" + remoteSlot + ", remote-rack2=" + remoteRack2 + - ", remote-slot2=" + remoteSlot2 + + ", remote-slot2=" + remoteSlot2 + ", remote-tsap=" + remoteTsap + ", pduSize=" + pduSize + ", maxAmqCaller=" + maxAmqCaller + ", maxAmqCallee=" + maxAmqCallee + - ", controllerType=" + controllerType + - ", readTimeOut=" + readTimeout + - ", ping=" + ping + - ", pingTime=" + pingTime + - ", retryTime=" + retryTime + + ", controllerType='" + controllerType + + ", readTimeOut='" + readTimeout + + ", ping='" + ping + + ", pingTime='" + pingTime + + ", retryTime='" + retryTime + + '\'' + '}'; } diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/connection/S7HDefaultNettyPlcConnection.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/connection/S7HDefaultNettyPlcConnection.java index 446be1ffd54..85ef85f0cdc 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/connection/S7HDefaultNettyPlcConnection.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/connection/S7HDefaultNettyPlcConnection.java @@ -26,7 +26,6 @@ import io.netty.handler.logging.LoggingHandler; import org.apache.plc4x.java.api.authentication.PlcAuthentication; import org.apache.plc4x.java.api.exceptions.PlcConnectionException; -import org.apache.plc4x.java.api.messages.PlcPingResponse; import org.apache.plc4x.java.api.messages.PlcReadRequest; import org.apache.plc4x.java.api.messages.PlcReadResponse; import org.apache.plc4x.java.api.value.PlcValueHandler; @@ -47,6 +46,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import org.apache.plc4x.java.api.messages.PlcPingResponse; /** * @author cgarcia @@ -78,14 +78,15 @@ public S7HDefaultNettyPlcConnection(boolean canPing, Configuration configuration, ChannelFactory channelFactory, ChannelFactory secondaryChannelFactory, - boolean fireDiscoverEvent, + boolean fireDiscoverEvent, boolean awaitSessionSetupComplete, boolean awaitSessionDisconnectComplete, boolean awaitSessionDiscoverComplete, ProtocolStackConfigurer stackConfigurer, BaseOptimizer optimizer, PlcAuthentication authentication) { - super(canPing, + super( + canPing, canRead, canWrite, canSubscribe, @@ -94,7 +95,7 @@ public S7HDefaultNettyPlcConnection(boolean canPing, valueHandler, configuration, channelFactory, - fireDiscoverEvent, + fireDiscoverEvent, awaitSessionSetupComplete, awaitSessionDisconnectComplete, awaitSessionDiscoverComplete, @@ -303,7 +304,6 @@ public void run() { } @Override - // TODO: This method needs some cleaning up ... public CompletableFuture ping() { if (channel.attr(S7HMuxImpl.IS_CONNECTED).get()) { channel.eventLoop().execute(() -> { diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/connection/S7HMuxImpl.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/connection/S7HMuxImpl.java index e73032c7b55..122ce4b309d 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/connection/S7HMuxImpl.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/connection/S7HMuxImpl.java @@ -115,6 +115,7 @@ public class S7HMuxImpl extends MessageToMessageCodec implemen */ @Override protected void encode(ChannelHandlerContext ctx, ByteBuf outbb, List list) throws Exception { + logger.debug("ENCODE: " + outbb.toString()); if ((embed_ctx == null) && (ctx.channel() instanceof EmbeddedChannel)) embed_ctx = ctx; if ((tcp_channel != null) && (embed_ctx == ctx)) { tcp_channel.writeAndFlush(outbb.copy()); diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/context/S7DriverContext.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/context/S7DriverContext.java index 01bcbbc97af..40e6806c8d4 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/context/S7DriverContext.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/context/S7DriverContext.java @@ -7,7 +7,7 @@ * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * 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 @@ -36,12 +36,12 @@ public class S7DriverContext implements DriverContext, HasConfiguration 0) { - this.callingTsapId = configuration.localTsap; + this.callingTsapId = configuration.localTsap; } if (configuration.remoteTsap > 0) { - this.calledTsapId = configuration.remoteTsap; + this.calledTsapId = configuration.remoteTsap; } this.controllerType = configuration.controllerType == null ? S7ControllerType.ANY : S7ControllerType.valueOf(configuration.controllerType); @@ -81,10 +81,10 @@ public void setConfiguration(S7Configuration configuration) { this.maxAmqCaller = configuration.maxAmqCaller; this.maxAmqCallee = configuration.maxAmqCallee; - + this.readTimeout = configuration.readTimeout; this.ping = configuration.ping; - this.pingTime = configuration.pingTime; + this.pingTime = (configuration.pingTime == 0)?10:configuration.pingTime; this.retryTime = configuration.retryTime; } @@ -111,14 +111,14 @@ public int getCalledTsapId() { public void setCalledTsapId(int calledTsapId) { this.calledTsapId = calledTsapId; } - + public int getCalledTsapId2() { return calledTsapId2; } public void setCalledTsapId2(int calledTsapId2) { this.calledTsapId2 = calledTsapId2; - } + } public COTPTpduSize getCotpTpduSize() { return cotpTpduSize; @@ -159,30 +159,30 @@ public S7ControllerType getControllerType() { public void setControllerType(S7ControllerType controllerType) { this.controllerType = controllerType; } - + public int getReadTimeout() { return readTimeout; } public void setReadTimeout(int readTimeout) { this.readTimeout = readTimeout; - } - + } + public boolean getPing() { return ping; } public void setPing(boolean ping) { this.ping = ping; - } - + } + public int getPingTime() { return pingTime; } public void setPingTime(int pingTime) { this.pingTime = pingTime; - } + } public int getRetryTime() { return retryTime; @@ -190,7 +190,7 @@ public int getRetryTime() { public void setRetryTime(int retryTime) { this.retryTime = retryTime; - } + } /** * Iterate over all values until one is found that the given tpdu size will fit. diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/optimizer/DefaultS7MessageProcessor.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/optimizer/DefaultS7MessageProcessor.java index 02d316a3b5f..8e4a51347ad 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/optimizer/DefaultS7MessageProcessor.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/optimizer/DefaultS7MessageProcessor.java @@ -43,7 +43,7 @@ */ public class DefaultS7MessageProcessor implements S7MessageProcessor { - private final AtomicInteger tpduRefGen; + private AtomicInteger tpduRefGen; public static final int EMPTY_READ_REQUEST_SIZE = new S7MessageRequest(0, new S7ParameterReadVarRequest( Collections.emptyList()), null).getLengthInBytes(); diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/optimizer/S7Optimizer.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/optimizer/S7Optimizer.java index 2badc5352c6..bcb82f75252 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/optimizer/S7Optimizer.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/optimizer/S7Optimizer.java @@ -34,6 +34,7 @@ import org.apache.plc4x.java.spi.optimizer.BaseOptimizer; import java.util.*; +import org.apache.plc4x.java.s7.readwrite.tag.S7ClkTag; import org.apache.plc4x.java.s7.readwrite.tag.S7SzlTag; public class S7Optimizer extends BaseOptimizer { @@ -63,7 +64,9 @@ protected List processReadRequest(PlcReadRequest readRequest, Dr LinkedHashMap curTags = new LinkedHashMap<>(); for (String tagName : readRequest.getTagNames()) { - if (readRequest.getTag(tagName) instanceof S7SzlTag){ + + if ((readRequest.getTag(tagName) instanceof S7SzlTag) || + (readRequest.getTag(tagName) instanceof S7ClkTag)) { curTags.put(tagName, readRequest.getTag(tagName)); continue; } @@ -115,8 +118,16 @@ protected List processReadRequest(PlcReadRequest readRequest, Dr return processedRequests; } + @Override protected List processWriteRequest(PlcWriteRequest writeRequest, DriverContext driverContext) { + + for (String tagName : writeRequest.getTagNames()) { + if (writeRequest.getTag(tagName) instanceof S7ClkTag) { + return Collections.singletonList( writeRequest); + } + } + S7DriverContext s7DriverContext = (S7DriverContext) driverContext; List processedRequests = new LinkedList<>(); @@ -127,7 +138,7 @@ protected List processWriteRequest(PlcWriteRequest writeRequest // List of all items in the current request. LinkedHashMap curTags = new LinkedHashMap<>(); - + for (String tagName : writeRequest.getTagNames()) { S7Tag tag = (S7Tag) writeRequest.getTag(tagName); PlcValue value = writeRequest.getPlcValue(tagName); diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7HAbortRequestException.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7HAbortRequestException.java new file mode 100644 index 00000000000..c75ac9f7eb8 --- /dev/null +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7HAbortRequestException.java @@ -0,0 +1,27 @@ +/* + * 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.readwrite.protocol; + +/** + * + * @author cgarcia + */ +public class S7HAbortRequestException { + +} diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7HGeneratedDriverBase.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7HGeneratedDriverBase.java new file mode 100644 index 00000000000..f74c8fe2354 --- /dev/null +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7HGeneratedDriverBase.java @@ -0,0 +1,210 @@ +/* + * 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.readwrite.protocol; + +import java.util.ServiceLoader; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.plc4x.java.api.PlcConnection; +import org.apache.plc4x.java.api.authentication.PlcAuthentication; +import org.apache.plc4x.java.api.exceptions.PlcConnectionException; +import org.apache.plc4x.java.api.value.PlcValueHandler; +import org.apache.plc4x.java.s7.readwrite.TPKTPacket; +import org.apache.plc4x.java.spi.configuration.Configuration; +import org.apache.plc4x.java.spi.configuration.ConfigurationFactory; +import static org.apache.plc4x.java.spi.configuration.ConfigurationFactory.configure; +import org.apache.plc4x.java.spi.connection.ChannelFactory; +import org.apache.plc4x.java.spi.connection.DefaultNettyPlcConnection; +import org.apache.plc4x.java.spi.connection.GeneratedDriverBase; +import static org.apache.plc4x.java.spi.connection.GeneratedDriverBase.PROPERTY_PLC4X_FORCE_AWAIT_DISCONNECT_COMPLETE; +import static org.apache.plc4x.java.spi.connection.GeneratedDriverBase.PROPERTY_PLC4X_FORCE_AWAIT_DISCOVER_COMPLETE; +import static org.apache.plc4x.java.spi.connection.GeneratedDriverBase.PROPERTY_PLC4X_FORCE_AWAIT_SETUP_COMPLETE; +import org.apache.plc4x.java.spi.connection.PlcTagHandler; +import org.apache.plc4x.java.spi.connection.ProtocolStackConfigurer; +import org.apache.plc4x.java.spi.transport.Transport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * @author cgarcia + */ +public class S7HGeneratedDriverBase extends GeneratedDriverBase{ + + private static final Logger logger = LoggerFactory.getLogger(S7HGeneratedDriverBase.class); + + private static final Pattern URI_PATTERN = Pattern.compile( + "^(?[a-z0-9\\-]*)(:(?[a-z0-9]*))?://(?[^?^/]*)(\\?(?.*))?"); + + private static final Pattern URI_H_PATTERN = Pattern.compile( + "^(?[a-z0-9\\-]*)(:(?[a-z0-9]*))?://(?[^?]*)/(?[^?]*)\\?(?.*)?"); + + @Override + public PlcConnection getConnection(String connectionString) throws PlcConnectionException { + // Split up the connection string into it's individual segments. + Matcher smatcher = URI_PATTERN.matcher(connectionString); + Matcher hmatcher = URI_H_PATTERN.matcher(connectionString); + if (!smatcher.matches() && !hmatcher.matches()) { + throw new PlcConnectionException( + "Connection string doesn't match the format '{protocol-code}:({transport-code})?//{transport-address}(?{parameter-string)?'"); + } + + Matcher matcher = (smatcher.matches())?smatcher:hmatcher; + + final String protocolCode = matcher.group("protocolCode"); + final String transportCode = (matcher.group("transportCode") != null) ? + matcher.group("transportCode") : getDefaultTransport(); + final String transportConfig = matcher.group("transportConfig"); + final String transportConfig2 = (hmatcher.matches())?matcher.group("transportConfig2"):null; + final String paramString = matcher.group("paramString"); + + // Check if the protocol code matches this driver. + if (!protocolCode.equals(getProtocolCode())) { + // Actually this shouldn't happen as the DriverManager should have not used this driver in the first place. + throw new PlcConnectionException( + "This driver is not suited to handle this connection string"); + } + + // Create the configuration object. + Configuration configuration = new ConfigurationFactory().createConfiguration( + getConfigurationType(), protocolCode, transportCode, transportConfig, paramString); + if (configuration == null) { + throw new PlcConnectionException("Unsupported configuration"); + } + + // Try to find a transport in order to create a communication channel. + Transport transport = null; + ServiceLoader transportLoader = ServiceLoader.load( + Transport.class, Thread.currentThread().getContextClassLoader()); + for (Transport curTransport : transportLoader) { + if (curTransport.getTransportCode().equals(transportCode)) { + transport = curTransport; + break; + } + } + if (transport == null) { + throw new PlcConnectionException("Unsupported transport " + transportCode); + } + + // Inject the configuration into the transport. + configure(configuration, transport); + + // Create an instance of the communication channel which the driver should use. + ChannelFactory channelFactory = transport.createChannelFactory(transportConfig); + if(channelFactory == null) { + throw new PlcConnectionException("Unable to get channel factory from url " + transportConfig); + } + configure(configuration, channelFactory); + + // Create an instance of the communication channel which the driver should use. + ChannelFactory secondaryChannelFactory = null; + if (hmatcher.matches()) { + secondaryChannelFactory = transport.createChannelFactory(transportConfig2); + if(secondaryChannelFactory == null) { + logger.info("Unable to get channel factory from url " + transportConfig2); + } + } + + if (hmatcher.matches()) + configure(configuration, secondaryChannelFactory); + + // Give drivers the option to customize the channel. + initializePipeline(channelFactory); + + // Give drivers the option to customize the channel. + if (hmatcher.matches()) + initializePipeline(secondaryChannelFactory); + + // Make the "await setup complete" overridable via system property. + boolean awaitSetupComplete = awaitSetupComplete(); + if(System.getProperty(PROPERTY_PLC4X_FORCE_AWAIT_SETUP_COMPLETE) != null) { + awaitSetupComplete = Boolean.parseBoolean(System.getProperty(PROPERTY_PLC4X_FORCE_AWAIT_SETUP_COMPLETE)); + } + + // Make the "await disconnect complete" overridable via system property. + boolean awaitDisconnectComplete = awaitDisconnectComplete(); + if(System.getProperty(PROPERTY_PLC4X_FORCE_AWAIT_DISCONNECT_COMPLETE) != null) { + awaitDisconnectComplete = Boolean.parseBoolean(System.getProperty(PROPERTY_PLC4X_FORCE_AWAIT_DISCONNECT_COMPLETE)); + } + + // Make the "await disconnect complete" overridable via system property. + boolean awaitDiscoverComplete = awaitDiscoverComplete(); + if(System.getProperty(PROPERTY_PLC4X_FORCE_AWAIT_DISCOVER_COMPLETE) != null) { + awaitDiscoverComplete = Boolean.parseBoolean(System.getProperty(PROPERTY_PLC4X_FORCE_AWAIT_DISCOVER_COMPLETE)); + } + + return new S7HPlcConnection( + canPing(), + canRead(), canWrite(), canSubscribe(), canBrowse(), + getTagHandler(), + getValueHandler(), + configuration, + channelFactory, + secondaryChannelFactory, + false, + awaitSetupComplete, + awaitDisconnectComplete, + awaitDiscoverComplete, + getStackConfigurer(transport), + getOptimizer(), + getAuthentication()); + } + + + @Override + protected Class getConfigurationType() { + throw new UnsupportedOperationException("getConfigurationType, Not supported yet."); + } + + @Override + protected PlcTagHandler getTagHandler() { + throw new UnsupportedOperationException("getTagHandler, Not supported yet."); + } + + @Override + protected PlcValueHandler getValueHandler() { + throw new UnsupportedOperationException("getValueHandler, Not supported yet."); + } + + @Override + protected String getDefaultTransport() { + throw new UnsupportedOperationException("getDefaultTransport, Not supported yet."); + } + + @Override + protected ProtocolStackConfigurer getStackConfigurer() { + throw new UnsupportedOperationException("getStackConfigurer, Not supported yet."); + } + + @Override + public String getProtocolCode() { + throw new UnsupportedOperationException("getProtocolCode, Not supported yet."); + } + + @Override + public String getProtocolName() { + throw new UnsupportedOperationException("getProtocolName, Not supported yet."); + } + + public PlcAuthentication getAuthentication() { + return null; + } + + +} diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7HMux.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7HMux.java new file mode 100644 index 00000000000..1f027cc654a --- /dev/null +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7HMux.java @@ -0,0 +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. + */ +package org.apache.plc4x.java.s7.readwrite.protocol; + +import io.netty.channel.Channel; +import org.apache.plc4x.java.spi.configuration.Configuration; + +public interface S7HMux { + +public void setEmbededhannel(Channel embeded_channel, Configuration configuration); +public void setPrimaryChannel(Channel primary_channel); +public void setSecondaryChannel(Channel secondary_channel); +public Channel getTCPChannel(); + +} diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7HMuxImpl.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7HMuxImpl.java new file mode 100644 index 00000000000..26ba62b8e9d --- /dev/null +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7HMuxImpl.java @@ -0,0 +1,359 @@ +/* + * 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.readwrite.protocol; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandler.Sharable; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.embedded.EmbeddedChannel; + +import io.netty.handler.codec.MessageToMessageCodec; +import io.netty.handler.timeout.ReadTimeoutHandler; +import io.netty.util.AttributeKey; +import java.time.LocalTime; +import java.util.List; +import java.util.concurrent.TimeUnit; +import org.apache.plc4x.java.s7.readwrite.configuration.S7Configuration; +import org.apache.plc4x.java.spi.configuration.Configuration; +import org.apache.plc4x.java.spi.events.ConnectEvent; +import org.apache.plc4x.java.spi.events.ConnectedEvent; +import org.apache.plc4x.java.spi.events.DisconnectEvent; +import org.apache.plc4x.java.spi.events.DisconnectedEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Implementation of a multiplexing channel, from an embedded channel to two + * possible TCP connections, primary and secondary. + * The objective is to allow connections to individual systems + * with a two CP (PN CPUs, CP343-1, CP443-1 or similar), or H-type systems + * (S7-400H or S7-1500H). + * + * The user App must be in charge of restoring the requests or + * subscriptions that it is requesting. + * + * @author cgarcia + */ +@Sharable +public class S7HMuxImpl extends MessageToMessageCodec implements S7HMux { + + private static final Logger logger = LoggerFactory.getLogger(S7HMuxImpl.class); + + /* + * This attribute indicates to the other handlers that the channel is connected + * or disconnected because a switch is being made between TCP channels or + * both TCP channels are disconnected. + * Default value: false + */ + final static AttributeKey IS_CONNECTED = AttributeKey.valueOf("IS_CONNECTED"); + + /* + * This attribute indicates to the other handlers that the channel is connected + * or disconnected because a switch is being made between TCP channels or + * both TCP channels are disconnected. + * Default value: false + */ + final static AttributeKey WAS_CONNECTED = AttributeKey.valueOf("WAS_CONNECTED"); + + + /* + * This attribute indicates to the other handlers which channel is being used, + * this allows the request to be properly prepared. + * For example, in the case of a CPU with two CPs, you should change + * the "slot", in the case of H systems, you should change the "rack", + * the correct values will be defined in the connection URL. + * Default value: true + */ + final static AttributeKey IS_PRIMARY = AttributeKey.valueOf("IS_PRIMARY"); + + /* + * This is the maximum waiting time for reading on the TCP channel. + * As there is no traffic, it must be assumed that the connection with the + * interlocutor was lost and it must be restarted. + * When the channel is closed, the "fail over" is carried out + * in case of having the secondary channel, or it is expected that it + * will be restored automatically, which is done every 4 seconds. + * Default value: 8 sec. + */ + final static AttributeKey READ_TIME_OUT = AttributeKey.valueOf("READ_TIME_OUT"); + + /* + * If your application requires sampling times greater than the + * set "watchdog" time, it is important that the PING option is activated, + * this will prevent the TCP channel from being closed unnecessarily. + * Default value: false + */ + final static AttributeKey IS_PING_ACTIVE = AttributeKey.valueOf("IS_PIN_ACTIVE"); + + /* + * Time value in seconds at which the execution of the PING will be scheduled. + * Generally set by developer experience, but generally should be the same + * as READ_TIME_OUT / 2. + * Default value: -1 + */ + final static AttributeKey PING_TIME = AttributeKey.valueOf("PING_TIME"); + + /* + * Time for supervision of TCP channels. If the channel is not active, + * a safe stop of the EventLoop must be performed, to ensure that + * no additional tasks are created. + * Default value: 4 + */ + final static AttributeKey RETRY_TIME = AttributeKey.valueOf("RETRY_TIME"); + + ChannelHandlerContext embed_ctx = null; + protected Channel embeded_channel = null; + protected Channel tcp_channel = null; + protected Channel primary_channel = null; + protected Channel secondary_channel = null; + + /* + * From S7ProtocolLogic + * TODO: Evaluate if the "embed_ctx" is really required since we set + * the Embeded channel when we created it. + */ + @Override + protected void encode(ChannelHandlerContext ctx, ByteBuf outbb, List list) throws Exception { + logger.debug("ENCODE: " + outbb.toString()); + if ((embed_ctx == null) && (ctx.channel() instanceof EmbeddedChannel)) embed_ctx = ctx; + if ((tcp_channel != null) && (embed_ctx == ctx)){ + tcp_channel.writeAndFlush(outbb.copy()); + } else { + list.add(outbb.copy()); + } + } + + /* + * To S7ProtocolLogic + * The information received here from the channel "tcp_channel" is sent to + * the pipeline of the channel "embeded_channel" + */ + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf inbb, List list) throws Exception { + embed_ctx.fireChannelRead(inbb.copy()); + } + + @Override + public void channelRegistered(ChannelHandlerContext ctx) throws Exception { + super.channelRegistered(ctx); + logger.debug("channelRegistered: " + ctx.name()); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + super.exceptionCaught(ctx, cause); + logger.debug("exceptionCaught: " + ctx.name()); + } + + @Override + public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception { + super.channelWritabilityChanged(ctx); + logger.debug("channelWritabilityChanged: " + ctx.name() ); + } + + /* + * The events detected here flow from the S7ProtocolLogic object. + * Upon receiving the "ConnectedEvent" event, we must safely add the watchdog + * to the pipeline of the "tcp_channel" connection. + * The supervision time can be defined in the connection URL, + * the default value being 0 secs disabling this function. + * This value being defined experimentally, a typical value is 8 seconds. + */ + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + super.userEventTriggered(ctx, evt); + logger.info(LocalTime.now().toString() + " userEventTriggered: " + ctx.name() + " Event: " + evt); + if (evt instanceof ConnectedEvent) { + try { + tcp_channel.pipeline().remove("watchdog"); + } catch (Exception ex){ + logger.info(ex.toString()); + } + try { + if ((embeded_channel.attr(READ_TIME_OUT).get() > 0) && + (embeded_channel.attr(IS_PING_ACTIVE ).get() == true)) + tcp_channel.pipeline().addFirst("watchdog", + new ReadTimeoutHandler(embeded_channel.attr(READ_TIME_OUT).get())); + if (tcp_channel.isActive()) { + embeded_channel.attr(IS_CONNECTED).set(true); + } else { + embeded_channel.attr(IS_CONNECTED).set(false); + } + } catch (Exception ex){ + logger.info(ex.toString()); + } + } + + if (evt instanceof DisconnectEvent) { + logger.info("DisconnectEvent"); + } + + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { + super.channelReadComplete(ctx); + logger.debug(LocalTime.now().toString() + " channelReadComplete: " + ctx.name() ); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + super.channelInactive(ctx); + logger.debug("channelInactive: " + ctx.name()); + } + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + super.channelActive(ctx); + logger.debug("channelActive: " + ctx.name()); + } + + @Override + public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { + super.channelUnregistered(ctx); + logger.debug(LocalTime.now().toString() + " channelUnregistered: " + ctx.name() ); + String strCanal = (tcp_channel == primary_channel)?"PRIMARY":"SECONDARY"; + logger.info("Unregistered of channel: " + strCanal); + //TODO: If embedded channel is closed, we need close all channels + if (ctx == embed_ctx) return; + + if (tcp_channel == ctx.channel()) { + embeded_channel.attr(IS_CONNECTED).set(false); + embeded_channel.attr(WAS_CONNECTED).set(true); + embeded_channel.pipeline().fireUserEventTriggered(new DisconnectedEvent()); + } + + logger.info(embed_ctx.executor().toString()); + + if ((tcp_channel == primary_channel) && + (primary_channel == ctx.channel())) + if ((!primary_channel.isActive()) && + (secondary_channel != null)) + if (secondary_channel.isActive()) { + synchronized(tcp_channel) { + logger.info("Using secondary TCP channel."); + tcp_channel = secondary_channel; + embeded_channel.attr(IS_PRIMARY).set(false); + embeded_channel.pipeline().fireUserEventTriggered(new ConnectEvent()); + } + }; + + + if ((tcp_channel == secondary_channel) && + (secondary_channel == ctx.channel())) + if ((!secondary_channel.isActive()) && + (primary_channel != null)) + if (primary_channel.isActive()) { + synchronized(tcp_channel) { + logger.info("Using primary TCP channel."); + tcp_channel = primary_channel; + embeded_channel.attr(IS_PRIMARY).set(true); + embeded_channel.pipeline().fireUserEventTriggered(new ConnectEvent()); + } + } + + } + + + @Override + public void setEmbededhannel(Channel embeded_channel, Configuration configuration) { + final S7Configuration conf = (S7Configuration) configuration; + this.embeded_channel = embeded_channel; + this.embeded_channel.attr(IS_CONNECTED).set(false); + this.embeded_channel.attr(WAS_CONNECTED).set(false); + this.embeded_channel.attr(IS_PRIMARY).set(true); + + //From the URL + this.embeded_channel.attr(READ_TIME_OUT).set(conf.getReadTimeout()); + this.embeded_channel.attr(IS_PING_ACTIVE).set(conf.getPing()); + this.embeded_channel.attr(PING_TIME).set(conf.getPingTime()); + this.embeded_channel.attr(RETRY_TIME).set(conf.getRetryTime()); + } + + @Override + public void setPrimaryChannel(Channel primary_channel) { + if ((this.primary_channel == null) && (tcp_channel == null)){ + if (primary_channel != null){ + this.primary_channel = primary_channel; + tcp_channel = primary_channel; + embeded_channel.attr(IS_PRIMARY).set(true); + } + } else if ((this.primary_channel == null) || + ((tcp_channel == secondary_channel)) && (tcp_channel.isActive())){ + this.primary_channel = primary_channel; + + } else if ((!this.primary_channel.isActive()) && (tcp_channel == secondary_channel)){ + this.primary_channel = primary_channel; + + } else if (((!this.primary_channel.isActive()) && (tcp_channel == this.primary_channel)) || + (primary_channel.isActive())) { + synchronized(tcp_channel) { + tcp_channel.close(); + this.primary_channel = primary_channel; + tcp_channel = primary_channel; + embeded_channel.attr(IS_PRIMARY).set(true); + + if (tcp_channel.isActive()) { + embed_ctx.fireUserEventTriggered(new ConnectEvent()); + } + } + } else if (primary_channel.isActive()) { + + } + } + + @Override + public void setSecondaryChannel(Channel secondary_channel) { + if ((this.primary_channel == null) && (tcp_channel == null)) { + if (secondary_channel != null){ + this.secondary_channel = secondary_channel; + tcp_channel = secondary_channel; + embeded_channel.attr(IS_PRIMARY).set(false); + } + + } else if ((this.secondary_channel == null) || + ((tcp_channel == primary_channel)) && (tcp_channel.isActive())){ + this.secondary_channel = secondary_channel; + + } else if ((!this.secondary_channel.isActive()) && (tcp_channel == primary_channel)){ + this.secondary_channel = secondary_channel; + + } else if (((!this.secondary_channel.isActive()) && (tcp_channel == this.secondary_channel)) || + (secondary_channel.isActive())){ + synchronized(tcp_channel) { + tcp_channel.close(); + this.secondary_channel = secondary_channel; + tcp_channel = secondary_channel; + embeded_channel.attr(IS_PRIMARY).set(false); + } + if (tcp_channel.isActive()) { + embed_ctx.fireUserEventTriggered(new ConnectEvent()); + } + } + } + + @Override + public Channel getTCPChannel() { + return tcp_channel; + } + + +} diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7HPlcConnection.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7HPlcConnection.java new file mode 100644 index 00000000000..5ae7ede7a1c --- /dev/null +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7HPlcConnection.java @@ -0,0 +1,419 @@ +/* + * 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.readwrite.protocol; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.EventLoop; +import io.netty.channel.embedded.EmbeddedChannel; +import io.netty.handler.codec.MessageToMessageCodec; +import io.netty.handler.logging.LogLevel; +import io.netty.handler.logging.LoggingHandler; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; +import org.apache.plc4x.java.api.authentication.PlcAuthentication; +import org.apache.plc4x.java.api.exceptions.PlcConnectionException; +import org.apache.plc4x.java.api.listener.ConnectionStateListener; +import org.apache.plc4x.java.api.messages.PlcPingResponse; +import org.apache.plc4x.java.api.messages.PlcReadRequest; +import org.apache.plc4x.java.api.messages.PlcReadResponse; +import org.apache.plc4x.java.api.value.PlcValueHandler; +import org.apache.plc4x.java.spi.configuration.Configuration; +import org.apache.plc4x.java.spi.configuration.ConfigurationFactory; +import org.apache.plc4x.java.spi.connection.ChannelFactory; +import org.apache.plc4x.java.spi.connection.DefaultNettyPlcConnection; +import org.apache.plc4x.java.spi.connection.PlcTagHandler; +import org.apache.plc4x.java.spi.connection.ProtocolStackConfigurer; +import org.apache.plc4x.java.spi.events.CloseConnectionEvent; +import org.apache.plc4x.java.spi.events.ConnectEvent; +import org.apache.plc4x.java.spi.events.ConnectedEvent; +import org.apache.plc4x.java.spi.events.DisconnectEvent; +import org.apache.plc4x.java.spi.events.DisconnectedEvent; +import org.apache.plc4x.java.spi.optimizer.BaseOptimizer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This object generates the main connection and includes the management + * of multiple connections to the PLC, in the case of S7H there + * are two connections. + * Here the reference to the multiplexer object (S7HMuxImpl) is maintained, + * which is in charge of managing the physical TCP connections. + * + * TODO: It should be able to run in the "channel" executor. + * You should be able to remove the "executor". + */ +public class S7HPlcConnection extends DefaultNettyPlcConnection implements Runnable { + + private static final Logger logger = LoggerFactory.getLogger(S7HPlcConnection.class); + + private static final String MULTIPLEXOR = "MULTIPLEXOR"; + private Boolean closed = false; + + private ScheduledFuture scf = null; + private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(new BasicThreadFactory.Builder() + .namingPattern("plc4x-s7ha-thread-%d") + .daemon(true) + .priority(Thread.MAX_PRIORITY) + .build()); + + protected final ChannelFactory secondaryChannelFactory; + protected Channel primary_channel = null; + protected Channel secondary_channel = null; + protected final MessageToMessageCodec s7hmux; + + protected int slice_ping = 0; + protected int slice_retry_time = 0; + + public S7HPlcConnection( + boolean canPing, + boolean canRead, + boolean canWrite, + boolean canSubscribe, + boolean canBrowse, + PlcTagHandler tagHandler, + PlcValueHandler valueHandler, + Configuration configuration, + ChannelFactory channelFactory, + ChannelFactory secondaryChannelFactory, + boolean fireDiscoverEvent, + boolean awaitSessionSetupComplete, + boolean awaitSessionDisconnectComplete, + boolean awaitSessionDiscoverComplete, + ProtocolStackConfigurer stackConfigurer, + BaseOptimizer optimizer, + PlcAuthentication authentication) { + super( canPing, + canRead, + canWrite, + canSubscribe, + canBrowse, + tagHandler, + valueHandler, + configuration, + channelFactory, + fireDiscoverEvent, + awaitSessionSetupComplete, + awaitSessionDisconnectComplete, + awaitSessionDiscoverComplete, + stackConfigurer, + optimizer, + authentication); + this.secondaryChannelFactory = secondaryChannelFactory; + this.s7hmux = new S7HMuxImpl(); + } + + @Override + public void connect() throws PlcConnectionException { + try { + // As we don't just want to wait till the connection is established, + // define a future we can use to signal back that the s7 session is + // finished initializing. + CompletableFuture sessionSetupCompleteFuture = new CompletableFuture<>(); + CompletableFuture sessionDiscoveredCompleteFuture = new CompletableFuture<>(); + + if(channelFactory == null) { + throw new PlcConnectionException("No primary channel factory provided"); + } + + // Inject the configuration + ConfigurationFactory.configure(configuration, channelFactory); + + if (secondaryChannelFactory != null ) + ConfigurationFactory.configure(configuration, secondaryChannelFactory); + + if (null == channel) { + channel = new EmbeddedChannel( + getChannelHandler(sessionSetupCompleteFuture, + sessionDisconnectCompleteFuture, + sessionDiscoveredCompleteFuture)); + + channel.pipeline().addFirst(new LoggingHandler("DOOM")); + channel.pipeline().addFirst("Multiplexor",s7hmux); + } + + ((S7HMux) s7hmux).setEmbededhannel(channel, configuration); + //channel.pipeline().addFirst((new LoggingHandler(LogLevel.INFO))); + /* + channel.closeFuture().addListener(future -> { + if (!sessionSetupCompleteFuture.isDone()) { + sessionSetupCompleteFuture.completeExceptionally( + new PlcIoException("Connection terminated by remote")); + } + }); + */ + doPrimaryTcpConnections(); + + if (secondaryChannelFactory != null ) + doSecondaryTcpConnections(); + + //If it is not possible to generate a TCP connection. + //Safety shutdownn all executors in the channels. + if (primary_channel == null) + if (secondary_channel == null) { + sendChannelDisconectEvent(); + throw new PlcConnectionException("Connection is not possible."); + } + + scf = executor.scheduleAtFixedRate(this, 1, 1, TimeUnit.SECONDS); + + /* + primary_channel.closeFuture().addListener(future -> {/watch?v=TmENMZFUU_0&list=RDlBlx1JffMQ4&index=27 + if (!sessionDiscoveredCompleteFuture.isDone()) { + //Do Nothing + try { + sessionDiscoveredCompleteFuture.complete(null); + } catch (Exception e) { + //Do Nothing + } + + } + }); + */ + + // Send an event to the pipeline telling the Protocol filters what's going on. + sendChannelCreatedEvent(); + + // Wait till the connection is established. + if (awaitSessionSetupComplete) { + sessionSetupCompleteFuture.get(); + } + //channel.pipeline().write(new ConnectedEvent()); + // Set the connection to "connected" + connected = true; + //((EmbeddedChannel) channel).runPendingTasks(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new PlcConnectionException(e); + } catch (ExecutionException e) { + throw new PlcConnectionException(e); + } + } + + @Override + public void close() throws PlcConnectionException { + if (closed) return; + try { + scf.cancel(true); + } catch (Exception ex) { + logger.info(ex.toString()); + } + if (primary_channel != null) + if (primary_channel.isActive()){ + try { + primary_channel.pipeline().remove(MULTIPLEXOR); + primary_channel.pipeline().fireUserEventTriggered(new CloseConnectionEvent()); + primary_channel.eventLoop().shutdownGracefully(); + + } catch (Exception ex){ + logger.info(ex.toString()); + } + }; + + if (secondary_channel != null) + if (secondary_channel.isActive()){ + secondary_channel.pipeline().remove(MULTIPLEXOR); + secondary_channel.pipeline().fireUserEventTriggered(new CloseConnectionEvent()); + secondary_channel.eventLoop().shutdownGracefully(); + } + + channel.pipeline().fireUserEventTriggered(new DisconnectEvent()); + scf.cancel(true); + executor.shutdown(); + closed = true; + } + + @Override + public boolean isConnected() { + return channel.attr(S7HMuxImpl.IS_CONNECTED).get(); + } + + + + public void doPrimaryTcpConnections(){ + try { + primary_channel = channelFactory.createChannel(new LoggingHandler(LogLevel.TRACE) ); + } catch (Exception ex){ + primary_channel = null; + logger.info(ex.toString()); + } + if (primary_channel != null) + if (primary_channel.isActive()) { + primary_channel.pipeline().addFirst(MULTIPLEXOR,s7hmux); + ((S7HMux) s7hmux).setPrimaryChannel(primary_channel); + } + } + + public void doSecondaryTcpConnections(){ + try { + secondary_channel = secondaryChannelFactory.createChannel(new LoggingHandler(LogLevel.TRACE) ); + } catch (Exception ex){ + secondary_channel = null; + logger.info(ex.toString()); + } + if (secondary_channel != null) + if (secondary_channel.isActive()) { + secondary_channel.pipeline().addFirst(MULTIPLEXOR,s7hmux); + ((S7HMux) s7hmux).setSecondaryChannel(secondary_channel); + } + } + + /* + * All handlers on the channel are notified that a disconnection has been + * generated, generally during the first connection. + * In this way, a controlled shutdown of the execution services is achieved. + * The user application must take the measures to make the connection again. + */ + protected void sendChannelDisconectEvent() { + logger.trace("Channels was not created, firing DisconnectEvent Event"); + // Send an event to the pipeline telling the Protocol filters what's going on. + channel.pipeline().fireUserEventTriggered(new DisconnectEvent()); + } + + /* + * To avoid creating new tasks associated with the supervision of the + * driver, I execute these tasks in a few slices of time. This allows me + * to keep a simple control of the state machines. + * Verifies disconnection of the channel, which notifies the client + * that they are listening. + */ + @Override + public void run() { + + /* + * Here a driver reconnection is detected. If so, a connection event + * is generated, so the user application can generate its requests again. + */ + if ((channel.attr(S7HMuxImpl.WAS_CONNECTED).get()) && + (channel.attr(S7HMuxImpl.IS_CONNECTED).get())) { + (channel.attr(S7HMuxImpl.WAS_CONNECTED)).set(false); + channel.pipeline().fireUserEventTriggered(new ConnectedEvent()); + } + + /* + * Execute the ping towards the PLC. Its purpose is to keep + * the TCP channel active, for very long sampling periods. + */ + if ((channel.attr(S7HMuxImpl.IS_PING_ACTIVE).get())) { + if (slice_ping >= channel.attr(S7HMuxImpl.PING_TIME).get()) { + ping(); + slice_ping = 0; + }; + slice_ping++; + } else slice_ping = 0; + + /* + * Here it is verified if the channels are active. If they are not, + * the connection is created again. + * For H type systems, at least one of the connections must be active, + * and if the other is down, the connection must be lifted. + * S7HMuxImpl, includes the switching logic between the TCP links. + */ + if (slice_retry_time >= channel.attr(S7HMuxImpl.RETRY_TIME).get()) { + + if (primary_channel != null){ + if (!primary_channel.isActive()){ + logger.info("Creating prymary connection."); + primary_channel.eventLoop().shutdownGracefully(); + doPrimaryTcpConnections(); + } else if (null == secondary_channel) + if ((channel.attr(S7HMuxImpl.WAS_CONNECTED).get()) && + (!channel.attr(S7HMuxImpl.IS_CONNECTED).get())) { + logger.info("Reconnecting primary channel."); + if (null != ((S7HMux) s7hmux).getTCPChannel()) { + ((S7HMux) s7hmux).setPrimaryChannel(primary_channel); + } + } + } else { + logger.info("Creating firts prymary connection."); + doPrimaryTcpConnections(); + } + + if (secondary_channel != null){ + if (!secondary_channel.isActive()){ + logger.info("Creating secondary connection."); + secondary_channel.eventLoop().shutdownGracefully(); + doSecondaryTcpConnections(); + } else if (null == primary_channel) + if ((channel.attr(S7HMuxImpl.WAS_CONNECTED).get()) && + (!channel.attr(S7HMuxImpl.IS_CONNECTED).get())) { + logger.info("Reconnecting secondary channel."); + if (null != ((S7HMux) s7hmux).getTCPChannel()) { + ((S7HMux) s7hmux).setSecondaryChannel(secondary_channel); + } + } + } else { + if (secondaryChannelFactory != null ) { + logger.info("Creating firts secondary connection."); + doSecondaryTcpConnections(); + } + } + slice_retry_time = 0; + }; + + if (channel.attr(S7HMuxImpl.RETRY_TIME).get() > 0) + slice_retry_time++; + + connected = channel.attr(S7HMuxImpl.IS_CONNECTED).get(); + logger.trace("*************************************************\r\n" + +"INSTAMCIA PRIMARIO : " + ((null == primary_channel)?"NULL":primary_channel.toString()) + "\r\n" + +"ACTIVO PRIMARIO : " + ((null == primary_channel)?"NULL":primary_channel.isActive()) + "\r\n" + +"INSTAMCIA SECUNDARIO : " + ((null == secondary_channel)?"NULL":secondary_channel.toString()) + "\r\n" + +"ACTIVO SECUNDARIO : " + ((null == secondary_channel)?"NULL":secondary_channel.isActive()) + "\r\n" + +"CANAL CONECTADO? : " + channel.attr(S7HMuxImpl.IS_CONNECTED).get() + "\r\n" + +"CANAL ESTUVO CONECTADO? : " + channel.attr(S7HMuxImpl.WAS_CONNECTED).get() + "\r\n" + +"CONTADORES : " + slice_ping + " : " + slice_retry_time + "\r\n" + +"*************************************************"); + } + + /* + * PING to PLC. + */ + @Override + public CompletableFuture ping() { + if (channel.attr(S7HMuxImpl.IS_CONNECTED).get()) { + + //channel.eventLoop().execute(()->{ + executor.execute(()->{ + PlcReadRequest.Builder builder = readRequestBuilder(); + + builder.addTagAddress("value", "%MX1.0:BOOL"); + PlcReadRequest readRequest = builder.build(); + try + { + PlcReadResponse readResponse = readRequest.execute().get(2, TimeUnit.SECONDS); + logger.debug("PING: " + readResponse.getResponseCode("value")); + } catch (Exception ex){ + logger.info("PING: " + ex.toString()); + } + }); + } + return null; + } + +} diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7HSingleProtocolStackConfigurer.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7HSingleProtocolStackConfigurer.java new file mode 100644 index 00000000000..15d414316ed --- /dev/null +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7HSingleProtocolStackConfigurer.java @@ -0,0 +1,220 @@ +/* + * 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 + * + * https://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.readwrite.protocol; + +import static org.apache.plc4x.java.spi.configuration.ConfigurationFactory.*; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelPipeline; +import io.netty.handler.codec.MessageToMessageCodec; +import org.apache.plc4x.java.api.authentication.PlcAuthentication; +import org.apache.plc4x.java.api.exceptions.PlcRuntimeException; +import org.apache.plc4x.java.api.listener.EventListener; +import org.apache.plc4x.java.spi.Plc4xNettyWrapper; +import org.apache.plc4x.java.spi.Plc4xProtocolBase; +import org.apache.plc4x.java.spi.configuration.Configuration; +import org.apache.plc4x.java.spi.context.DriverContext; +import org.apache.plc4x.java.spi.generation.ByteOrder; +import org.apache.plc4x.java.spi.generation.Message; +import org.apache.plc4x.java.spi.generation.MessageInput; +import org.apache.plc4x.java.spi.generation.MessageOutput; +import org.apache.plc4x.java.spi.netty.NettyHashTimerTimeoutManager; + +import java.lang.reflect.InvocationTargetException; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.ToIntFunction; +import org.apache.plc4x.java.spi.connection.GeneratedProtocolMessageCodec; +import org.apache.plc4x.java.spi.connection.ProtocolStackConfigurer; +import org.apache.plc4x.java.spi.connection.SingleProtocolStackConfigurer; + +/** + * Builds a Protocol Stack. + */ +public class S7HSingleProtocolStackConfigurer implements ProtocolStackConfigurer { + + private final Class basePacketClass; + private final ByteOrder byteOrder; + private final Class> protocolClass; + private final Class driverContextClass; + private final MessageInput messageInput; + private final MessageOutput messageOutput; + private final Class> packetSizeEstimatorClass; + private final Class> corruptPacketRemoverClass; + private final MessageToMessageCodec encryptionHandler; + private final Object[] parserArgs; + + private Plc4xProtocolBase protocol = null; + + public static S7HSingleProtocolStackBuilder builder(Class basePacketClass, MessageInput messageInput) { + return new S7HSingleProtocolStackBuilder<>(basePacketClass, messageInput, null); + } + + public static S7HSingleProtocolStackBuilder builder(Class basePacketClass, MessageInput messageInput, MessageOutput messageOutput) { + return new S7HSingleProtocolStackBuilder<>(basePacketClass, messageInput, messageOutput); + } + + /** + * Only accessible via Builder + */ + S7HSingleProtocolStackConfigurer(Class basePacketClass, + ByteOrder byteOrder, + Object[] parserArgs, + Class> protocol, + Class driverContextClass, + MessageInput messageInput, + MessageOutput messageOutput, + Class> packetSizeEstimatorClass, + Class> corruptPacketRemoverClass, + MessageToMessageCodec encryptionHandler) { + this.basePacketClass = basePacketClass; + this.byteOrder = byteOrder; + this.parserArgs = parserArgs; + this.protocolClass = protocol; + this.driverContextClass = driverContextClass; + this.messageInput = messageInput; + this.messageOutput = messageOutput; + this.packetSizeEstimatorClass = packetSizeEstimatorClass; + this.corruptPacketRemoverClass = corruptPacketRemoverClass; + this.encryptionHandler = encryptionHandler; + } + + private ChannelHandler getMessageCodec(Configuration configuration) { + return new GeneratedProtocolMessageCodec<>(basePacketClass, messageInput, messageOutput, byteOrder, parserArgs, + packetSizeEstimatorClass != null ? configure(configuration, createInstance(packetSizeEstimatorClass)) : null, + corruptPacketRemoverClass != null ? configure(configuration, createInstance(corruptPacketRemoverClass)) : null); + } + + /** + * Applies the given Stack to the Pipeline + */ + @Override + public Plc4xProtocolBase configurePipeline(Configuration configuration, ChannelPipeline pipeline, + PlcAuthentication authentication, boolean passive, + List ignore) { + if (null == protocol) { + if (this.encryptionHandler != null) { + pipeline.addLast("ENCRYPT",this.encryptionHandler); + } + pipeline.addLast("CODEC",getMessageCodec(configuration)); + protocol = configure(configuration, createInstance(protocolClass)); + if (driverContextClass != null) { + protocol.setDriverContext(configure(configuration, createInstance(driverContextClass))); + } + Plc4xNettyWrapper context = new Plc4xNettyWrapper<>(new NettyHashTimerTimeoutManager(), pipeline, passive, protocol, + authentication, basePacketClass); + pipeline.addLast("WRAPPER",context); + }; + + return protocol; + + } + + private T createInstance(Class clazz, Object... args) { + try { + Class[] parameterTypes = new Class[args.length]; + for (int i = 0; i < args.length; i++) { + parameterTypes[i] = args[i].getClass(); + } + return clazz.getDeclaredConstructor(parameterTypes).newInstance(args); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + throw new PlcRuntimeException("Error creating instance of class " + clazz.getName()); + } + } + + /** + * Used to Build Instances of {@link SingleProtocolStackConfigurer}. + * + * @param Type of Created Message that is Exchanged. + */ + public static final class S7HSingleProtocolStackBuilder { + + private final Class basePacketClass; + private final MessageInput messageInput; + private final MessageOutput messageOutput; + private Class driverContextClass; + private ByteOrder byteOrder = ByteOrder.BIG_ENDIAN; + private Object[] parserArgs; + private Class> protocol; + private Class> packetSizeEstimator; + private Class> corruptPacketRemover; + private MessageToMessageCodec encryptionHandler; + + public S7HSingleProtocolStackBuilder(Class basePacketClass, MessageInput messageInput, MessageOutput messageOutput) { + this.basePacketClass = basePacketClass; + this.messageInput = messageInput; + this.messageOutput = messageOutput; + } + + public S7HSingleProtocolStackBuilder withDriverContext(Class driverContextClass) { + this.driverContextClass = driverContextClass; + return this; + } + + public S7HSingleProtocolStackBuilder byteOrder(ByteOrder byteOrder) { + this.byteOrder = byteOrder; + return this; + } + + public S7HSingleProtocolStackBuilder bigEndian() { + this.byteOrder = ByteOrder.BIG_ENDIAN; + return this; + } + + public S7HSingleProtocolStackBuilder littleEndian() { + this.byteOrder = ByteOrder.LITTLE_ENDIAN; + return this; + } + + public S7HSingleProtocolStackBuilder withParserArgs(Object... parserArgs) { + this.parserArgs = parserArgs; + return this; + } + + public S7HSingleProtocolStackBuilder withProtocol(Class> protocol) { + this.protocol = protocol; + return this; + } + + public S7HSingleProtocolStackBuilder withPacketSizeEstimator(Class> packetSizeEstimator) { + this.packetSizeEstimator = packetSizeEstimator; + return this; + } + + public S7HSingleProtocolStackBuilder withCorruptPacketRemover(Class> corruptPacketRemover) { + this.corruptPacketRemover = corruptPacketRemover; + return this; + } + + public S7HSingleProtocolStackBuilder withEncryptionHandler(MessageToMessageCodec encryptionHandler) { + this.encryptionHandler = encryptionHandler; + return this; + } + + public S7HSingleProtocolStackConfigurer build() { + assert this.protocol != null; + return new S7HSingleProtocolStackConfigurer<>(basePacketClass, byteOrder, parserArgs, protocol, + driverContextClass, messageInput, messageOutput, packetSizeEstimator, corruptPacketRemover, + encryptionHandler); + } + + } + +} diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolEventLogic.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolEventLogic.java index eb6939432ed..774e1e441d6 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolEventLogic.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolEventLogic.java @@ -18,18 +18,6 @@ */ package org.apache.plc4x.java.s7.readwrite.protocol; -import org.apache.plc4x.java.api.messages.*; -import org.apache.plc4x.java.api.model.PlcConsumerRegistration; -import org.apache.plc4x.java.api.model.PlcSubscriptionHandle; -import org.apache.plc4x.java.s7.events.*; -import org.apache.plc4x.java.s7.readwrite.EventType; -import org.apache.plc4x.java.s7.readwrite.S7ParameterModeTransition; -import org.apache.plc4x.java.s7.readwrite.S7PayloadDiagnosticMessage; -import org.apache.plc4x.java.s7.readwrite.utils.S7PlcSubscriptionHandle; -import org.apache.plc4x.java.spi.messages.PlcSubscriber; -import org.apache.plc4x.java.spi.model.DefaultPlcConsumerRegistration; -import org.slf4j.LoggerFactory; - import java.util.Collection; import java.util.HashMap; import java.util.Map; @@ -38,40 +26,74 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; +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.model.PlcConsumerRegistration; +import org.apache.plc4x.java.api.model.PlcSubscriptionHandle; +import org.apache.plc4x.java.s7.events.S7AlarmEvent; +import org.apache.plc4x.java.s7.events.S7CyclicEvent; +import org.apache.plc4x.java.s7.events.S7ModeEvent; +import org.apache.plc4x.java.s7.events.S7SysEvent; +import org.apache.plc4x.java.s7.events.S7UserEvent; +import org.apache.plc4x.java.s7.readwrite.S7ParameterModeTransition; +import org.apache.plc4x.java.s7.readwrite.S7PayloadDiagnosticMessage; +import org.apache.plc4x.java.s7.readwrite.EventType; +import org.apache.plc4x.java.s7.readwrite.utils.S7PlcSubscriptionHandle; +import org.apache.plc4x.java.spi.messages.PlcSubscriber; +import org.apache.plc4x.java.spi.model.DefaultPlcConsumerRegistration; +import org.slf4j.LoggerFactory; public class S7ProtocolEventLogic implements PlcSubscriber { - private final org.slf4j.Logger logger = LoggerFactory.getLogger(S7ProtocolEventLogic.class); - private final BlockingQueue eventQueue; - private final BlockingQueue dispachQueue = new ArrayBlockingQueue<>(1024); - - private final Map>> mapIndex = new HashMap<>(); - private final Map eventTypeHandles = new HashMap<>(); - + + private final BlockingQueue eventqueue; + private final BlockingQueue dispachqueue = new ArrayBlockingQueue<>(1024); + + private Map> mapIndex = new HashMap(); + private Map eventtypehandles = new HashMap(); + private final Runnable runProcessor; private final Runnable runDispacher; - private final Thread processor; - private final Thread dispacher; + + private Thread processor; + private Thread dispacher; - public S7ProtocolEventLogic(BlockingQueue eventQueue) { - this.eventQueue = eventQueue; - runProcessor = new ObjectProcessor(eventQueue, dispachQueue); - runDispacher = new EventDispatcher(dispachQueue); - processor = new Thread(runProcessor); - dispacher = new Thread(runDispacher); + public S7ProtocolEventLogic(BlockingQueue eventqueue) { + this.eventqueue = eventqueue; + runProcessor = new ObjectProcessor(eventqueue,dispachqueue); + runDispacher = new EventDispacher(dispachqueue); +// processor = new Thread(runnProcessor); +// dispacher = new Thread(runnDispacher); + processor = new BasicThreadFactory.Builder() + .namingPattern("plc4x-evt-processor-thread-%d") + .daemon(true) + .priority(Thread.MAX_PRIORITY) + .build().newThread(runProcessor); + + dispacher = new BasicThreadFactory.Builder() + .namingPattern("plc4x-evt-dispacher-thread-%d") + .daemon(true) + .priority(Thread.MAX_PRIORITY) + .build().newThread(runDispacher); } - + public void start() { processor.start(); - dispacher.start(); + dispacher.start(); } - - public void stop() { + + public void stop(){ ((ObjectProcessor) runProcessor).doShutdown(); - ((EventDispatcher) runDispacher).doShutdown(); + ((EventDispacher) runDispacher).doShutdown(); } - + @Override public CompletableFuture subscribe(PlcSubscriptionRequest subscriptionRequest) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. @@ -84,151 +106,151 @@ public CompletableFuture unsubscribe(PlcUnsubscriptio @Override public PlcConsumerRegistration register(Consumer consumer, Collection handles) { - Map> mapConsumers = null; + Map mapConsumers = null; S7PlcSubscriptionHandle handle = (S7PlcSubscriptionHandle) handles.toArray()[0]; if (!mapIndex.containsKey(handle.getEventType())) { - mapConsumers = new HashMap<>(); + mapConsumers = new HashMap(); mapIndex.put(handle.getEventType(), mapConsumers); } mapConsumers = mapIndex.get(handle.getEventType()); //TODO: Check the implementation of "DefaultPlcConsumerRegistration". List<> vs Collection<> DefaultPlcConsumerRegistration registro = new DefaultPlcConsumerRegistration(this, - consumer, handles.toArray(new PlcSubscriptionHandle[0])); + consumer, handles.toArray(new PlcSubscriptionHandle[handles.size()])); mapConsumers.put(registro, consumer); return registro; } @Override public void unregister(PlcConsumerRegistration registration) { - S7PlcSubscriptionHandle handle = (S7PlcSubscriptionHandle) registration.getSubscriptionHandles().get(0); - Map> mapConsumers = mapIndex.get(handle.getEventType()); + S7PlcSubscriptionHandle handle = (S7PlcSubscriptionHandle)registration.getSubscriptionHandles().get(0); + Map mapConsumers = mapIndex.get(handle.getEventType()); mapConsumers.remove(registration); } - - private static class ObjectProcessor implements Runnable { - - private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(ObjectProcessor.class); - - private final BlockingQueue eventQueue; - private final BlockingQueue dispatchQueue; + + private class ObjectProcessor implements Runnable { + + private final BlockingQueue eventqueue; + private final BlockingQueue dispathqueue; private boolean shutdown = false; - private final int delay = 100; - - public ObjectProcessor(BlockingQueue eventQueue, BlockingQueue dispatchQueue) { - this.eventQueue = eventQueue; - this.dispatchQueue = dispatchQueue; + private int delay = 100; + + public ObjectProcessor(BlockingQueue eventqueue, BlockingQueue dispathqueue) { + this.eventqueue = eventqueue; + this.dispathqueue = dispathqueue; } - + @Override public void run() { - while (!shutdown) { + while(!shutdown){ try { - Object obj = eventQueue.poll(delay, TimeUnit.MILLISECONDS); - if (obj == null) { - continue; - } - if (obj instanceof S7ParameterModeTransition) { - S7ModeEvent modeEvent = new S7ModeEvent((S7ParameterModeTransition) obj); - dispatchQueue.add(modeEvent); - } else if (obj instanceof S7PayloadDiagnosticMessage) { - S7PayloadDiagnosticMessage msg = (S7PayloadDiagnosticMessage) obj; - if ((msg.getEventId() >= 0x0A000) && (msg.getEventId() <= 0x0BFFF)) { - S7UserEvent userEvent = new S7UserEvent(msg); - dispatchQueue.add(userEvent); + Object obj = eventqueue.poll(delay, TimeUnit.MILLISECONDS); + if (obj != null){ + if (obj instanceof S7ParameterModeTransition){ + S7ModeEvent modeEvent = new S7ModeEvent((S7ParameterModeTransition) obj); + dispathqueue.add(modeEvent); + } else + if (obj instanceof S7PayloadDiagnosticMessage){ + S7PayloadDiagnosticMessage msg = (S7PayloadDiagnosticMessage) obj; + if ((msg.getEventId() >= 0x0A000) & (msg.getEventId() <= 0x0BFFF)) { + S7UserEvent userevent = new S7UserEvent(msg); + dispathqueue.add(userevent); + } else { + S7SysEvent sysevent = new S7SysEvent(msg); + dispathqueue.add(sysevent); + } + } else + if (obj instanceof S7CyclicEvent){ + dispathqueue.add(obj); } else { - S7SysEvent sysEvent = new S7SysEvent(msg); - dispatchQueue.add(sysEvent); + S7AlarmEvent alarmevent = new S7AlarmEvent(obj); + dispathqueue.add(alarmevent); } - } else if (obj instanceof S7CyclicEvent) { - dispatchQueue.add((S7CyclicEvent) obj); - } else { - S7AlarmEvent alarmEvent = new S7AlarmEvent(obj); - dispatchQueue.add(alarmEvent); - } - } catch (InterruptedException e) { - LOGGER.error("oh no", e); - Thread.currentThread().interrupt(); + } + } catch (InterruptedException ex) { + Logger.getLogger(S7ProtocolEventLogic.class.getName()).log(Level.SEVERE, null, ex); } } - LOGGER.trace("ObjectProcessor Bye!"); + logger.info("ObjectProcessor Bye!"); } - public void doShutdown() { + public void doShutdown(){ shutdown = true; } - } - - private class EventDispatcher implements Runnable { - - private final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(EventDispatcher.class); - - private final BlockingQueue dispachQueue; + } + + private class EventDispacher implements Runnable { + private final BlockingQueue dispachqueue; private boolean shutdown = false; - private final int delay = 100; - private PlcSubscriptionEvent cycDelayedObject = null; + private int delay = 100; + private Object cycDelayedObject = null; - public EventDispatcher(BlockingQueue dispachQueue) { - this.dispachQueue = dispachQueue; + public EventDispacher(BlockingQueue dispachqueue) { + this.dispachqueue = dispachqueue; } - + @Override public void run() { try { Thread.sleep(500); - } catch (InterruptedException e) { - logger.warn("Error sleeping", e); - Thread.currentThread().interrupt(); + } catch (InterruptedException ex) { + logger.warn(ex.toString()); } - while (!shutdown) { + while(!shutdown){ try { - PlcSubscriptionEvent obj = dispachQueue.poll(delay, TimeUnit.MILLISECONDS); - if (obj != null) { - if (obj instanceof S7ModeEvent) { + Object obj = dispachqueue.poll(delay, TimeUnit.MILLISECONDS); + if (obj != null){ + if (obj instanceof S7ModeEvent){ if (mapIndex.containsKey(EventType.MODE)) { - Map> mapConsumers = mapIndex.get(EventType.MODE); - mapConsumers.forEach((x, y) -> y.accept(obj)); + Map mapConsumers = mapIndex.get(EventType.MODE); + mapConsumers.forEach((x,y) -> y.accept(obj)); } } else if (obj instanceof S7UserEvent) { if (mapIndex.containsKey(EventType.USR)) { - Map> mapConsumers = mapIndex.get(EventType.USR); - mapConsumers.forEach((x, y) -> y.accept(obj)); + Map mapConsumers = mapIndex.get(EventType.USR); + mapConsumers.forEach((x,y) -> y.accept(obj)); } } else if (obj instanceof S7SysEvent) { if (mapIndex.containsKey(EventType.SYS)) { - Map> mapConsumers = mapIndex.get(EventType.SYS); - mapConsumers.forEach((x, y) -> y.accept(obj)); + Map mapConsumers = mapIndex.get(EventType.SYS); + mapConsumers.forEach((x,y) -> y.accept(obj)); } - } else if (obj instanceof S7AlarmEvent) { + }else if (obj instanceof S7AlarmEvent) { if (mapIndex.containsKey(EventType.ALM)) { - Map> mapConsumers = mapIndex.get(EventType.ALM); - mapConsumers.forEach((x, y) -> y.accept(obj)); + Map mapConsumers = mapIndex.get(EventType.ALM); + mapConsumers.forEach((x,y) -> y.accept(obj)); } - } else if (obj instanceof S7CyclicEvent) { + }else if (obj instanceof S7CyclicEvent) { if (mapIndex.containsKey(EventType.CYC)) { - Map> mapConsumers = mapIndex.get(EventType.CYC); - if (cycDelayedObject != null) { - mapConsumers.forEach((x, y) -> y.accept(cycDelayedObject)); - cycDelayedObject = null; - } - mapConsumers.forEach((x, y) -> y.accept(obj)); + + Map mapConsumers = mapIndex.get(EventType.CYC); + if (cycDelayedObject != null) { + mapConsumers.forEach((x,y) -> y.accept(cycDelayedObject)); + cycDelayedObject = null; + } + mapConsumers.forEach((x,y) -> { + S7PlcSubscriptionHandle sh = (S7PlcSubscriptionHandle) x.getSubscriptionHandles().get(0); + Short id = Short.parseShort(sh.getEventId()); + if (((S7CyclicEvent) obj).getMap().get("JOBID") == id) + y.accept(obj); + }); + } else { cycDelayedObject = obj; - } - } + } + } } - } catch (Exception e) { - LOGGER.error("oh no", e); - Thread.currentThread().interrupt(); + } catch (Exception ex) { + Logger.getLogger(S7ProtocolEventLogic.class.getName()).log(Level.SEVERE, null, ex); } } - LOGGER.trace("EventDispatcher Bye!"); + logger.info("EventDispacher Bye!"); } - public void doShutdown() { + public void doShutdown(){ shutdown = true; } - + } - - + + } diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java index a5a1de7bca0..7f997da7844 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java @@ -18,52 +18,84 @@ */ package org.apache.plc4x.java.s7.readwrite.protocol; +import org.apache.plc4x.java.api.model.PlcTag; +import org.apache.plc4x.java.s7.readwrite.utils.S7PlcSubscriptionHandle; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; -import org.apache.commons.lang3.concurrent.BasicThreadFactory; -import org.apache.commons.lang3.tuple.MutablePair; +import io.netty.channel.embedded.EmbeddedChannel; import org.apache.plc4x.java.api.exceptions.PlcProtocolException; import org.apache.plc4x.java.api.exceptions.PlcRuntimeException; -import org.apache.plc4x.java.api.messages.*; -import org.apache.plc4x.java.api.model.PlcSubscriptionHandle; -import org.apache.plc4x.java.api.model.PlcSubscriptionTag; -import org.apache.plc4x.java.api.model.PlcTag; +import org.apache.plc4x.java.api.messages.PlcReadRequest; +import org.apache.plc4x.java.api.messages.PlcReadResponse; +import org.apache.plc4x.java.api.messages.PlcResponse; +import org.apache.plc4x.java.api.messages.PlcWriteRequest; +import org.apache.plc4x.java.api.messages.PlcWriteResponse; import org.apache.plc4x.java.api.types.PlcResponseCode; +import org.apache.plc4x.java.spi.generation.*; +import org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionTag; +import org.apache.plc4x.java.spi.values.PlcNull; import org.apache.plc4x.java.api.value.PlcValue; -import org.apache.plc4x.java.s7.events.S7CyclicEvent; +import org.apache.plc4x.java.spi.values.PlcValueHandler; import org.apache.plc4x.java.s7.readwrite.*; -import org.apache.plc4x.java.s7.readwrite.connection.S7HMuxImpl; -import org.apache.plc4x.java.s7.readwrite.context.S7DriverContext; -import org.apache.plc4x.java.s7.readwrite.tag.*; -import org.apache.plc4x.java.s7.readwrite.types.S7ControllerType; -import org.apache.plc4x.java.s7.readwrite.types.S7SubscriptionType; -import org.apache.plc4x.java.s7.readwrite.utils.S7PlcSubscriptionHandle; -import org.apache.plc4x.java.s7.utils.S7ParamErrorCode; +import org.apache.plc4x.java.s7.readwrite.tag.S7StringTag; +import org.apache.plc4x.java.s7.readwrite.types.*; +import org.apache.plc4x.java.s7.readwrite.tag.S7Tag; import org.apache.plc4x.java.spi.ConversationContext; import org.apache.plc4x.java.spi.Plc4xProtocolBase; import org.apache.plc4x.java.spi.context.DriverContext; -import org.apache.plc4x.java.spi.generation.*; -import org.apache.plc4x.java.spi.messages.*; +import org.apache.plc4x.java.spi.messages.DefaultPlcReadRequest; +import org.apache.plc4x.java.spi.messages.DefaultPlcReadResponse; +import org.apache.plc4x.java.spi.messages.DefaultPlcWriteRequest; +import org.apache.plc4x.java.spi.messages.DefaultPlcWriteResponse; import org.apache.plc4x.java.spi.messages.utils.ResponseItem; -import org.apache.plc4x.java.spi.model.DefaultPlcSubscriptionTag; import org.apache.plc4x.java.spi.transaction.RequestTransactionManager; -import org.apache.plc4x.java.spi.values.PlcList; -import org.apache.plc4x.java.spi.values.PlcNull; -import org.apache.plc4x.java.spi.values.PlcSINT; -import org.apache.plc4x.java.spi.values.PlcValueHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.time.Duration; +import java.time.LocalDateTime; +import java.time.Month; import java.util.*; -import java.util.concurrent.*; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiConsumer; import java.util.function.Consumer; +import java.util.logging.Level; +import java.util.stream.Collector; +import java.util.stream.Collectors; import java.util.stream.IntStream; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; +import org.apache.commons.lang3.tuple.MutablePair; + +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.model.PlcSubscriptionHandle; +import org.apache.plc4x.java.api.model.PlcSubscriptionTag; +import org.apache.plc4x.java.s7.events.S7CyclicEvent; +import org.apache.plc4x.java.s7.readwrite.context.S7DriverContext; +import org.apache.plc4x.java.s7.readwrite.tag.S7AckTag; +import org.apache.plc4x.java.s7.readwrite.tag.S7ClkTag; +import org.apache.plc4x.java.s7.readwrite.tag.S7SubscriptionTag; +import org.apache.plc4x.java.s7.readwrite.tag.S7SzlTag; +import org.apache.plc4x.java.s7.utils.S7ParamErrorCode; +import org.apache.plc4x.java.spi.messages.DefaultPlcSubscriptionRequest; +import org.apache.plc4x.java.spi.messages.DefaultPlcSubscriptionResponse; +import org.apache.plc4x.java.spi.messages.DefaultPlcUnsubscriptionRequest; +import org.apache.plc4x.java.spi.values.PlcLDATE_AND_TIME; +import org.apache.plc4x.java.spi.values.PlcList; +import org.apache.plc4x.java.spi.values.PlcSINT; /** * The S7 Protocol states that there can not be more then {min(maxAmqCaller, maxAmqCallee} "ongoing" requests. @@ -71,21 +103,21 @@ * Thus, each request goes to a Work Queue and this Queue ensures, that only 3 are open at the same time. */ public class S7ProtocolLogic extends Plc4xProtocolBase { - - private final Logger logger = LoggerFactory.getLogger(S7ProtocolLogic.class); - + + private static final Logger logger = LoggerFactory.getLogger(S7ProtocolLogic.class); + public static final Duration REQUEST_TIMEOUT = Duration.ofMillis(10000); private final AtomicInteger tpduGenerator = new AtomicInteger(10); - + /* * Task group for managing connection redundancy. */ - private final ExecutorService clientExecutorService = Executors.newFixedThreadPool(4, new BasicThreadFactory.Builder() - .namingPattern("plc4x-app-thread-%d") - .daemon(true) - .priority(Thread.MAX_PRIORITY) - .build()); - + private ExecutorService clientExecutorService = Executors.newFixedThreadPool(4, new BasicThreadFactory.Builder() + .namingPattern("plc4x-app-thread-%d") + .daemon(true) + .priority(Thread.MAX_PRIORITY) + .build()); + /* * 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. @@ -94,25 +126,34 @@ public class S7ProtocolLogic extends Plc4xProtocolBase { * (Examples of this are PCS7 and Braumat). * Alarm filtering, ack, etc. must be performed by the client application. */ - private final BlockingQueue eventQueue = new ArrayBlockingQueue<>(1024); + private final BlockingQueue eventQueue = new ArrayBlockingQueue<>(1024); private final S7ProtocolEventLogic EventLogic = new S7ProtocolEventLogic(eventQueue); private final S7PlcSubscriptionHandle modeHandle = new S7PlcSubscriptionHandle(EventType.MODE, EventLogic); private final S7PlcSubscriptionHandle sysHandle = new S7PlcSubscriptionHandle(EventType.SYS, EventLogic); private final S7PlcSubscriptionHandle usrHandle = new S7PlcSubscriptionHandle(EventType.USR, EventLogic); private final S7PlcSubscriptionHandle almHandle = new S7PlcSubscriptionHandle(EventType.ALM, EventLogic); - private final S7PlcSubscriptionHandle cycHandle = new S7PlcSubscriptionHandle(EventType.CYC, EventLogic); + //private final S7PlcSubscriptionHandle cycHandle = new S7PlcSubscriptionHandle(EventType.CYC, EventLogic); /* - * For the reconnection functionality by a "TimeOut" of the connection, - * you must keep track of open transactions. In general, an S7 device - * supports a couple of simultaneous requests. - * The rhythm of execution must be determined by the TransactionManager. - * So far it is the way to indicate to the user that he must redo - * his request. - */ - private final HashMap> activeRequests = new HashMap<>(); - - + * For the reconnection functionality by a "TimeOut" of the connection, + * you must keep track of open transactions. In general, an S7 device + * supports a couple of simultaneous requests. + * The rhythm of execution must be determined by the TransactionManager. + * So far it is the way to indicate to the user that he must redo + * his request. + */ + private HashMap> active_requests = new HashMap<>(); + + /* + * This array stores the cyclic subscription requests between the driver + * and the PLC. The purpose is to document the tags associated with the + * request. Each subscription uses a 'JobID' that is managed by the PLC and + * obtained from the response to the request. In the following, + * the values sent PUSH from the PLC to the driver refer to this JobID. + */ + private final Map cycrequests = new HashMap<>(); + + private S7DriverContext s7DriverContext; private RequestTransactionManager tm; @@ -139,9 +180,14 @@ public void onConnect(ConversationContext context) { context.fireConnected(); return; } - - //Set feature for all handlers in the pipeline from the driver configuration. - setChannelFeatures(); + + // If the call is for a reconnection, we must clean up + // the queued messages so that they release the transaction handler. + cleanFutures(); + + //Set feature for all handlers in the pipeline from + //the driver configuration. + setChannelFeatures(); // Only the TCP transport supports login. logger.info("S7 Driver running in ACTIVE mode."); @@ -149,11 +195,16 @@ public void onConnect(ConversationContext context) { // Open the session on ISO Transport Protocol first. TPKTPacket packet = new TPKTPacket(createCOTPConnectionRequest( s7DriverContext.getCalledTsapId(), s7DriverContext.getCallingTsapId(), s7DriverContext.getCotpTpduSize())); + + context.getChannel().pipeline().names().forEach( s-> { + logger.debug("Nombre tuberias: " + s); + }); + context.sendRequest(packet) .onTimeout(e -> { - logger.warn("Timeout during Connection establishing, closing channel..."); - context.getChannel().close(); + logger.info("Timeout during Connection establishing, closing channel..."); + //context.getChannel().close(); }) .expectResponse(TPKTPacket.class, REQUEST_TIMEOUT) .check(p -> p.getPayload() instanceof COTPPacketConnectionResponse) @@ -191,7 +242,7 @@ public void onConnect(ConversationContext context) { // in order to detect the type of PLC. if (s7DriverContext.getControllerType() != S7ControllerType.ANY) { // Send an event that connection setup is complete. - context.fireConnected(); + context.fireConnected(); return; } @@ -219,16 +270,16 @@ public void onConnect(ConversationContext context) { }); } - - /* - * It performs the sequential and safe shutdown of the driver. - * Completion of pending requests, executors and associated tasks. - */ + + /* + * It performs the sequential and safe shutdown of the driver. + * Completion of pending requests, executors and associated tasks. + */ @Override public void onDisconnect(ConversationContext context) { //1. Clear all pending requests and their associated transaction - cleanFutures(); - //2. Here we shut down the local task executor. + cleanFutures(); + //2. Here we shutdown the local task executor. clientExecutorService.shutdown(); //3. Performs the shutdown of the transaction executor. tm.shutdown(); @@ -236,50 +287,60 @@ public void onDisconnect(ConversationContext context) { EventLogic.stop(); //5. Executes the closing of the main channel. context.getChannel().close(); - //6. Here is the stop of any task or state machine that is added. + //6. Here is the stop of any task or state machine that is added. } - + @Override public CompletableFuture read(PlcReadRequest readRequest) { if (!isConnected()) { - CompletableFuture future = new CompletableFuture<>(); - future.completeExceptionally(new PlcRuntimeException("Disconnected")); + CompletableFuture future = new CompletableFuture(); + future.completeExceptionally(new PlcRuntimeException("Disconnected")); return future; - } + } DefaultPlcReadRequest request = (DefaultPlcReadRequest) readRequest; List requestItems = new ArrayList<>(request.getNumberOfTags()); - + if (request.getTags().get(0) instanceof S7SzlTag) { S7SzlTag szltag = (S7SzlTag) request.getTags().get(0); - - final S7MessageUserData s7SzlMessageRequest = new S7MessageUserData(1, new S7ParameterUserData(List.of( + + final S7MessageUserData s7SzlMessageRequest = new S7MessageUserData(1, new S7ParameterUserData(Arrays.asList( new S7ParameterUserDataItemCPUFunctions((short) 0x11, (byte) 0x4, (byte) 0x4, (short) 0x01, (short) 0x00, null, null, null) - )), new S7PayloadUserData(List.of( - new S7PayloadUserDataItemCpuFunctionReadSzlRequest(DataTransportErrorCode.OK, - DataTransportSize.OCTET_STRING, - 0x04, - new SzlId(SzlModuleTypeClass.enumForValue((byte) ((szltag.getSzlId() & 0xf000) >> 12)), - (byte) ((szltag.getSzlId() & 0x0f00) >> 8), - SzlSublist.enumForValue((short) (szltag.getSzlId() & 0x00ff))), - szltag.getIndex()) - ))); - - return toPlcReadResponse(readRequest, readInternal(s7SzlMessageRequest)); - + )), new S7PayloadUserData(Arrays.asList( + new S7PayloadUserDataItemCpuFunctionReadSzlRequest(DataTransportErrorCode.OK, + DataTransportSize.OCTET_STRING, + 0x04, + new SzlId(SzlModuleTypeClass.enumForValue((byte) ((szltag.getSzlId() & 0xf000) >> 12)), + (byte) ((szltag.getSzlId() & 0x0f00) >> 8), + SzlSublist.enumForValue((short) (szltag.getSzlId() & 0x00ff))), + szltag.getIndex()) + ))); + + return toPlcReadResponse(readRequest, readInternal(s7SzlMessageRequest)); + } else if (request.getTags().get(0) instanceof S7AckTag) { - + List parameterItems = new ArrayList<>(request.getNumberOfTags()); List payloadItems = new ArrayList<>(request.getNumberOfTags()); encodeAlarmAckRequest(request, parameterItems, payloadItems); - final S7MessageUserData s7MessageRequest = new S7MessageUserData(-1, + final S7MessageUserData s7MessageRequest = new S7MessageUserData(-1, new S7ParameterUserData(parameterItems), - new S7PayloadUserData(payloadItems)); - return toPlcReadResponse(readRequest, readInternal(s7MessageRequest)); - - } - - + new S7PayloadUserData(payloadItems)); + return toPlcReadResponse(readRequest, readInternal(s7MessageRequest )); + + } else if (request.getTags().get(0) instanceof S7ClkTag) { + + List parameterItems = new ArrayList<>(request.getNumberOfTags()); + List payloadItems = new ArrayList<>(request.getNumberOfTags()); + encodePlcClkRequest(request, parameterItems, payloadItems); + final S7MessageUserData s7MessageRequest = new S7MessageUserData(-1, + new S7ParameterUserData(parameterItems), + new S7PayloadUserData(payloadItems)); + return toPlcReadResponse(readRequest, readInternal(s7MessageRequest )); + + } + + for (PlcTag tag : request.getTags()) { requestItems.add(new S7VarRequestParameterItemAddress(encodeS7Address(tag))); } @@ -298,25 +359,27 @@ public CompletableFuture read(PlcReadRequest readRequest) { * Maps the S7ReadResponse of a PlcReadRequest to a PlcReadResponse */ private CompletableFuture toPlcReadResponse(PlcReadRequest readRequest, CompletableFuture response) { - CompletableFuture clientFuture = new CompletableFuture<>(); - activeRequests.get(response).setRight(clientFuture); - + CompletableFuture client_future = new CompletableFuture<>(); + active_requests.get(response).setRight(client_future); + try { - clientExecutorService.execute(() -> { - try { - PlcReadResponse plcItems = (PlcReadResponse) decodeReadResponse(response.get(), readRequest); - clientFuture.complete(plcItems); - } catch (Exception e) { - logger.info("uh", e); + clientExecutorService.execute(()->{ + try + { + PlcReadResponse plcitems = (PlcReadResponse) decodeReadResponse(response.get(), readRequest); + client_future.complete(plcitems); + } catch (Exception ex) { + logger.info(ex.toString()); } }); - } catch (Exception e) { - logger.info("uh", e); - } + } catch (Exception ex) { + logger.info(ex.toString()); + } + + return client_future; - return clientFuture; -// TODO: whoever out commented this describe why it is out commented and describe what the above does different + // return response // .thenApply(p -> { // try { @@ -338,16 +401,20 @@ private CompletableFuture readInternal(S7Message request) { CompletableFuture future = new CompletableFuture<>(); int tpduId = tpduGenerator.getAndIncrement(); // If we've reached the max value for a 16 bit transaction identifier, reset back to 1 - tpduGenerator.compareAndExchange(0xFFFF, 1); + if (tpduGenerator.get() == 0xFFFF) { + tpduGenerator.set(1); + } S7Message message = (request instanceof S7MessageUserData) ? - new S7MessageUserData(tpduId, request.getParameter(), request.getPayload()) : - new S7MessageRequest(tpduId, request.getParameter(), request.getPayload()); + new S7MessageUserData(tpduId, request.getParameter(), request.getPayload()) : + new S7MessageRequest(tpduId, request.getParameter(), request.getPayload()); - TPKTPacket tpktPacket = new TPKTPacket(new COTPPacketData(null, message, true, (byte) tpduId)); + TPKTPacket tpktPacket = new TPKTPacket(new COTPPacketData(null, message, true, (byte) tpduId)); // Start a new request-transaction (Is ended in the response-handler) + RequestTransactionManager.RequestTransaction transaction = tm.startRequest(); + transaction.submit(() -> context.sendRequest(tpktPacket) .onTimeout(new TransactionErrorCallback<>(future, transaction)) .onError(new TransactionErrorCallback<>(future, transaction)) @@ -358,36 +425,48 @@ private CompletableFuture readInternal(S7Message request) { .unwrap(COTPPacket::getPayload) .check(p -> p.getTpduReference() == tpduId) .handle(p -> { - activeRequests.remove(future); + active_requests.remove(future); future.complete(p); // Finish the request-transaction. - transaction.endRequest(); + transaction.endRequest(); })); - activeRequests.put(future, new MutablePair<>(transaction, null)); - + active_requests.put(future, new MutablePair<>(transaction, null)); + return future; } - - + + //TODO: Clean code @Override public CompletableFuture write(PlcWriteRequest writeRequest) { + CompletableFuture future = new CompletableFuture<>(); - DefaultPlcWriteRequest request = (DefaultPlcWriteRequest) writeRequest; + DefaultPlcWriteRequest request = (DefaultPlcWriteRequest) writeRequest; + + List clktags = (List) request.getTagNames().stream() + .filter(t -> request.getTag(t) instanceof S7ClkTag) + .collect(Collectors.toList()); + + if (null != clktags ){ + if (!clktags.isEmpty()) { + return writeclk(writeRequest); + } + } + List parameterItems = new ArrayList<>(request.getNumberOfTags()); List payloadItems = new ArrayList<>(request.getNumberOfTags()); Iterator iter = request.getTagNames().iterator(); - + String tagName = null; - while (iter.hasNext()) { + while(iter.hasNext()) { tagName = iter.next(); final S7Tag tag = (S7Tag) request.getTag(tagName); final PlcValue plcValue = request.getPlcValue(tagName); parameterItems.add(new S7VarRequestParameterItemAddress(encodeS7Address(tag))); - payloadItems.add(serializePlcValue(tag, plcValue, iter.hasNext())); + payloadItems.add(serializePlcValue(tag, plcValue, iter.hasNext())); } - - + + // for (String tagName : request.getTagNames()) { // final S7Tag tag = (S7Tag) request.getTag(tagName); // final PlcValue plcValue = request.getPlcValue(tagName); @@ -395,11 +474,14 @@ public CompletableFuture write(PlcWriteRequest writeRequest) { // payloadItems.add(serializePlcValue(tag, plcValue)); // // } - - + + + final int tpduId = tpduGenerator.getAndIncrement(); // If we've reached the max value for a 16 bit transaction identifier, reset back to 1 - tpduGenerator.compareAndExchange(0xFFFF, 1); + if (tpduGenerator.get() == 0xFFFF) { + tpduGenerator.set(1); + } TPKTPacket tpktPacket = new TPKTPacket( new COTPPacketData( @@ -412,7 +494,7 @@ public CompletableFuture write(PlcWriteRequest writeRequest) { (byte) tpduId ) ); - + // Start a new request-transaction (Is ended in the response-handler) RequestTransactionManager.RequestTransaction transaction = tm.startRequest(); transaction.submit(() -> context.sendRequest(tpktPacket) @@ -435,42 +517,98 @@ public CompletableFuture write(PlcWriteRequest writeRequest) { return future; } + //TODO: Clean code + public CompletableFuture writeclk(PlcWriteRequest writeRequest) { + CompletableFuture future = new CompletableFuture<>(); + DefaultPlcWriteRequest request = (DefaultPlcWriteRequest) writeRequest; + + List parameterItems = new ArrayList<>(request.getNumberOfTags()); + List payloadItems = new ArrayList<>(request.getNumberOfTags()); + + Iterator iter = request.getTagNames().iterator(); + + encodePlcClkSetRequest((DefaultPlcWriteRequest) writeRequest, + parameterItems, payloadItems ); + + List clktags = (List) request.getTagNames().stream() + .filter(t -> request.getTag(t) instanceof S7ClkTag) + .collect(Collectors.toList()); + + final int tpduId = tpduGenerator.getAndIncrement(); + // If we've reached the max value for a 16 bit transaction identifier, reset back to 1 + if (tpduGenerator.get() == 0xFFFF) { + tpduGenerator.set(1); + } + + TPKTPacket tpktPacket = new TPKTPacket(new COTPPacketData(null, + new S7MessageUserData(tpduId, + new S7ParameterUserData(parameterItems), + new S7PayloadUserData(payloadItems)), + true, (byte) tpduId)); + + // Start a new request-transaction (Is ended in the response-handler) + RequestTransactionManager.RequestTransaction transaction = tm.startRequest(); + transaction.submit(() -> context.sendRequest(tpktPacket) + .onTimeout(new TransactionErrorCallback<>(future, transaction)) + .onError(new TransactionErrorCallback<>(future, transaction)) + .expectResponse(TPKTPacket.class, REQUEST_TIMEOUT) + .check(p -> p.getPayload() instanceof COTPPacketData) + .unwrap(p -> ((COTPPacketData) p.getPayload())) + .unwrap(COTPPacket::getPayload) + .check(p -> p.getTpduReference() == tpduId) + .handle(p -> { + try { + future.complete(((PlcWriteResponse) decodeWriteResponse(p, writeRequest))); + } catch (PlcProtocolException e) { + logger.warn("Error sending 'write' message: '{}'", e.getMessage(), e); + } + // Finish the request-transaction. + transaction.endRequest(); + })); + return future; + } + + @Override public CompletableFuture subscribe(PlcSubscriptionRequest subscriptionRequest) { if (!isConnected()) { - CompletableFuture future = new CompletableFuture<>(); - future.completeExceptionally(new PlcRuntimeException("Disconnected")); + CompletableFuture future = new CompletableFuture(); + future.completeExceptionally(new PlcRuntimeException("Disconnected")); return future; - } - if (!isSubscriptionSupported()) { - CompletableFuture future = new CompletableFuture<>(); - future.completeExceptionally(new PlcRuntimeException("Not Supported")); + } + if (!isFeatureSupported()) { + CompletableFuture future = new CompletableFuture(); + future.completeExceptionally(new PlcRuntimeException("Not Supported")); return future; - } - - CompletableFuture future = new CompletableFuture<>(); - HashMap valuesResponse = new HashMap<>(); + } + + CompletableFuture future = new CompletableFuture<>(); + HashMap valuesResponse = new HashMap<>(); HashMap> futures = new HashMap<>(); - + //Initialize multiple requests. - CompletableFuture response = new CompletableFuture<>(); - subscriptionRequest.getTagNames().forEach(fieldname -> futures.put(fieldname, new CompletableFuture<>())); - + CompletableFuture response = new CompletableFuture<>(); + subscriptionRequest.getTagNames().forEach(fieldname -> futures.put(fieldname, new CompletableFuture<>())); + + // + futures.put("DATA_", new CompletableFuture<>()); DefaultPlcSubscriptionRequest request = (DefaultPlcSubscriptionRequest) subscriptionRequest; List parameterItems = new ArrayList<>(request.getNumberOfTags()); List payloadItems = new ArrayList<>(request.getNumberOfTags()); - + //The main task that runs the subscriptions. - CompletableFuture mainTask; - mainTask = CompletableFuture. - allOf(futures.values().toArray(new CompletableFuture[0])); - - Thread t1 = new Thread(() -> { - - for (String tagName : request.getTagNames()) { - final DefaultPlcSubscriptionTag sf = (DefaultPlcSubscriptionTag) request.getTag(tagName); + CompletableFuture maintask; +// maintask = CompletableFuture. +// allOf(futures.values().toArray(new CompletableFuture[0])); + + Thread t1 = new Thread(()->{ + + //for (String tagName : request.getTagNames()) { + //System.out.println("Aqui repite: " + tagName); + //final DefaultPlcSubscriptionTag sf = (DefaultPlcSubscriptionTag) request.getTag(tagName); + final DefaultPlcSubscriptionTag sf = (DefaultPlcSubscriptionTag) request.getTags().get(0); final S7SubscriptionTag tag = (S7SubscriptionTag) sf.getTag(); switch (tag.getTagType()) { @@ -487,77 +625,86 @@ public CompletableFuture subscribe(PlcSubscriptionReque encodeAlarmQueryRequest(request, parameterItems, payloadItems); break; case CYCLIC_SUBSCRIPTION: - encodeCycledS7ANYSubscriptionRequest(request.getTag(tagName), parameterItems, payloadItems); + encodeCycledS7ANYSubscriptionRequest(request, parameterItems, payloadItems); break; case CYCLIC_DB_SUBSCRIPTION: - encodeCycledDBREADSubscriptionRequest(request.getTag(tagName), parameterItems, payloadItems); + encodeCycledDBREADSubscriptionRequest(request, parameterItems, payloadItems); break; case CYCLIC_UNSUBSCRIPTION: //encodeCycledUnSubscriptionRequest(request, parameterItems, payloadItems); break; default: - } - //final PlcValue plcValue = request.getPlcValue(tagName); - //parameterItems.add(new S7VarRequestParameterItemAddress(encodeS7Address(tag))); - //payloadItems.add(serializePlcValue(tag, plcValue)); - final int tpduId = tpduGenerator.getAndIncrement(); - // If we've reached the max value for a 16 bit transaction identifier, reset back to 1 - tpduGenerator.compareAndExchange(0xFFFF, 1); - - TPKTPacket tpktPacket = new TPKTPacket(new COTPPacketData(null, - new S7MessageUserData(tpduId, - new S7ParameterUserData(parameterItems), - new S7PayloadUserData(payloadItems)), - true, (byte) tpduId)); - - // Start a new request-transaction (Is ended in the response-handler) - RequestTransactionManager.RequestTransaction transaction = tm.startRequest(); - transaction.submit(() -> context.sendRequest(tpktPacket) - .onTimeout(new TransactionErrorCallback<>(future, transaction)) - .onError(new TransactionErrorCallback<>(future, transaction)) - .expectResponse(TPKTPacket.class, REQUEST_TIMEOUT) - .check(p -> p.getPayload() instanceof COTPPacketData) - .unwrap(p -> ((COTPPacketData) p.getPayload())) - .unwrap(COTPPacket::getPayload) - .check(p -> p.getTpduReference() == tpduId) - .handle(p -> { - try { - //future.complete(decodeEventSubscriptionRequest(tagName, p, subscriptionRequest)); - futures.get(tagName).complete(p); - } catch (Exception e) { - logger.warn("Error sending 'write' message: '{}'", e.getMessage(), e); - } - // Finish the request-transaction. - transaction.endRequest(); - })); - - try { - valuesResponse.put(tagName, decodeEventSubscriptionRequest(tagName, subscriptionRequest, futures.get(tagName).get())); - } catch (Exception ex) { - logger.warn(ex.toString()); - } + } + //} //Next + + //final PlcValue plcValue = request.getPlcValue(tagName); + //parameterItems.add(new S7VarRequestParameterItemAddress(encodeS7Address(tag))); + //payloadItems.add(serializePlcValue(tag, plcValue)); + final int tpduId = tpduGenerator.getAndIncrement(); + // If we've reached the max value for a 16 bit transaction identifier, reset back to 1 + if (tpduGenerator.get() == 0xFFFF) { + tpduGenerator.set(1); + } - } //Next + TPKTPacket tpktPacket = new TPKTPacket(new COTPPacketData(null, + new S7MessageUserData(tpduId, + new S7ParameterUserData(parameterItems), + new S7PayloadUserData(payloadItems)), + true, (byte) tpduId)); + + // Start a new request-transaction (Is ended in the response-handler) + RequestTransactionManager.RequestTransaction transaction = tm.startRequest(); + transaction.submit(() -> context.sendRequest(tpktPacket) + .onTimeout(new TransactionErrorCallback<>(future, transaction)) + .onError(new TransactionErrorCallback<>(future, transaction)) + .expectResponse(TPKTPacket.class, REQUEST_TIMEOUT) + .check(p -> p.getPayload() instanceof COTPPacketData) + .unwrap(p -> ((COTPPacketData) p.getPayload())) + .unwrap(COTPPacket::getPayload) + .check(p -> p.getTpduReference() == tpduId) + .handle(p -> { + try { + //future.complete(decodeEventSubscriptionRequest(tagName, p, subscriptionRequest)); + futures.get("DATA_").complete(p); + } catch (Exception e) { + logger.warn("Error sending 'write' message: '{}'", e.getMessage(), e); + } + // Finish the request-transaction. + transaction.endRequest(); + })); try { - mainTask.get(); + S7Message responseMessage = futures.get("DATA_").get(); + S7ParameterUserData parameter = (S7ParameterUserData) responseMessage.getParameter(); + S7ParameterUserDataItemCPUFunctions msgparameter = (S7ParameterUserDataItemCPUFunctions) parameter.getItems().get(0); + + valuesResponse.put(Integer.toString(msgparameter.getSequenceNumber()), + decodeEventSubscriptionRequest(Integer.toString(msgparameter.getSequenceNumber()), subscriptionRequest, futures.get("DATA_").get())); + + } catch (Exception ex) { + logger.warn(ex.toString()); + } + + + try { + ///maintask.get(); HashMap> values = new HashMap<>(); - valuesResponse.forEach((s, p) -> { + valuesResponse.forEach((s,p)->{ if (p != null) - values.putAll(((DefaultPlcSubscriptionResponse) p).getValues()); - }); + values.putAll(((DefaultPlcSubscriptionResponse)p).getValues()); + }); - response.complete(new DefaultPlcSubscriptionResponse(subscriptionRequest, values)); + response.complete(new DefaultPlcSubscriptionResponse(subscriptionRequest, values)); - } catch (Exception e) { - logger.warn("uh", e); - } + } catch (Exception ex) { + logger.warn(ex.getMessage()); + } }); - + t1.start(); - + return response; } @@ -565,18 +712,59 @@ public CompletableFuture subscribe(PlcSubscriptionReque @Override public CompletableFuture unsubscribe(PlcUnsubscriptionRequest unsubscriptionRequest) { if (!isConnected()) { - CompletableFuture future = new CompletableFuture<>(); - future.completeExceptionally(new PlcRuntimeException("Disconnected")); + CompletableFuture future = new CompletableFuture(); + future.completeExceptionally(new PlcRuntimeException("Disconnected")); return future; - } - if (!isSubscriptionSupported()) { - CompletableFuture future = new CompletableFuture<>(); - future.completeExceptionally(new PlcRuntimeException("Not Supported")); + } + if (!isFeatureSupported()) { + CompletableFuture future = new CompletableFuture(); + future.completeExceptionally(new PlcRuntimeException("Not Supported")); return future; + } + CompletableFuture future = new CompletableFuture<>(); + DefaultPlcUnsubscriptionRequest request = (DefaultPlcUnsubscriptionRequest) unsubscriptionRequest; + + List parameterItems = new ArrayList<>(); + List payloadItems = new ArrayList<>(); + + encodeCycledUnSubscriptionRequest(request, parameterItems, payloadItems); + + final int tpduId = tpduGenerator.getAndIncrement(); + // If we've reached the max value for a 16 bit transaction identifier, reset back to 1 + if (tpduGenerator.get() == 0xFFFF) { + tpduGenerator.set(1); } - /*CompletableFuture future =*/ return new CompletableFuture<>(); - // TODO: It seems the unsubscription hasn't been implemented yet. - //DefaultPlcUnsubscriptionRequest request = (DefaultPlcUnsubscriptionRequest) unsubscriptionRequest; + + TPKTPacket tpktPacket = new TPKTPacket( + new COTPPacketData(null, + new S7MessageUserData(tpduId, + new S7ParameterUserData(parameterItems), + new S7PayloadUserData(payloadItems)), + true, + (byte) tpduId) + ); + + // Start a new request-transaction (Is ended in the response-handler) + RequestTransactionManager.RequestTransaction transaction = tm.startRequest(); + transaction.submit(() -> context.sendRequest(tpktPacket) + .onTimeout(new TransactionErrorCallback<>(future, transaction)) + .onError(new TransactionErrorCallback<>(future, transaction)) + .expectResponse(TPKTPacket.class, REQUEST_TIMEOUT) + .check(p -> p.getPayload() instanceof COTPPacketData) + .unwrap(p -> ((COTPPacketData) p.getPayload())) + .unwrap(COTPPacket::getPayload) + .check(p -> p.getTpduReference() == tpduId) + .handle(p -> { + try { + future.complete(null); + } catch (Exception e) { + logger.warn("Error sending 'write' message: '{}'", e.getMessage(), e); + } + // Finish the request-transaction. + transaction.endRequest(); + })); + + return future; } private void encodeEventSubscriptionRequest(DefaultPlcSubscriptionRequest request, @@ -587,8 +775,8 @@ private void encodeEventSubscriptionRequest(DefaultPlcSubscriptionRequest reques if (request.getTag(tagName) instanceof DefaultPlcSubscriptionTag) { PlcTag event = ((DefaultPlcSubscriptionTag) request.getTag(tagName)).getTag(); if (event instanceof S7SubscriptionTag) { - if (((S7SubscriptionTag) event).getTagType() == S7SubscriptionType.EVENT_SUBSCRIPTION) - subsevent = (byte) (subsevent | ((S7SubscriptionTag) event).getEventType().getValue()); + if (((S7SubscriptionTag) event).getTagType() == S7SubscriptionType.EVENT_SUBSCRIPTION) + subsevent = (byte) (subsevent | ((S7SubscriptionTag) event).getEventType().getValue()); } } } @@ -608,6 +796,7 @@ private void encodeEventSubscriptionRequest(DefaultPlcSubscriptionRequest reques S7PayloadUserDataItemCpuFunctionMsgSubscriptionRequest payload; + if (subsevent > 0) { payload = new S7PayloadUserDataItemCpuFunctionMsgSubscriptionRequest( DataTransportErrorCode.OK, @@ -625,14 +814,14 @@ private void encodeEventSubscriptionRequest(DefaultPlcSubscriptionRequest reques } else { alarmtype = AlarmStateType.ALARM_S_INITIATE; } - - short auxSubsEvent = (short) (subsevent & 0xFF); - + + short auxsubsevent = (short) (subsevent & 0xFF); + payload = new S7PayloadUserDataItemCpuFunctionMsgSubscriptionRequest( DataTransportErrorCode.OK, DataTransportSize.OCTET_STRING, (short) 0x0c, - auxSubsEvent, + auxsubsevent, "HmiRtm ", alarmtype, (short) 0x00); @@ -644,21 +833,20 @@ private void encodeEventSubscriptionRequest(DefaultPlcSubscriptionRequest reques } private PlcSubscriptionResponse decodeEventSubscriptionRequest(String strTagName, - PlcSubscriptionRequest plcSubscriptionRequest, - S7Message responseMessage) + PlcSubscriptionRequest plcSubscriptionRequest, + S7Message responseMessage) throws PlcProtocolException { Map> values = new HashMap<>(); short errorClass = 0; short errorCode = 0; - // TODO: It seems this hasn't been implemented yet. - /*if (responseMessage instanceof S7MessageUserData) { + if (responseMessage instanceof S7MessageUserData) { S7MessageUserData messageUserData = (S7MessageUserData) responseMessage; S7PayloadUserData payload = (S7PayloadUserData) messageUserData.getPayload(); // errorClass = payload.getItems()[0]. // errorCode = messageUserData.getParameter(). - } else*/ if (responseMessage instanceof S7MessageResponse) { + } else if (responseMessage instanceof S7MessageResponse) { S7MessageResponse messageResponse = (S7MessageResponse) responseMessage; errorClass = messageResponse.getErrorClass(); errorCode = messageResponse.getErrorCode(); @@ -688,12 +876,12 @@ private PlcSubscriptionResponse decodeEventSubscriptionRequest(String strTagName return new DefaultPlcSubscriptionResponse(plcSubscriptionRequest, values); } } - + S7ParameterUserData parameter = (S7ParameterUserData) responseMessage.getParameter(); List parameters = parameter.getItems(); - S7ParameterUserDataItemCPUFunctions itemparameter = (S7ParameterUserDataItemCPUFunctions) parameters.get(0); - errorCode = itemparameter.getErrorCode().shortValue(); - + S7ParameterUserDataItemCPUFunctions itemparameter = (S7ParameterUserDataItemCPUFunctions) parameters.get(0); + errorCode = itemparameter.getErrorCode().shortValue(); + // In all other cases all went well. S7PayloadUserData payload = (S7PayloadUserData) responseMessage.getPayload(); @@ -727,63 +915,63 @@ private PlcSubscriptionResponse decodeEventSubscriptionRequest(String strTagName (item.getTransportSize() == DataTransportSize.OCTET_STRING)) { responseOk = true; } - } else if (payloadItems.get(0) instanceof S7PayloadUserDataItemCpuFunctionAlarmAckResponse) { + } else if (payloadItems.get(0) instanceof S7PayloadUserDataItemCpuFunctionAlarmAckResponse) { S7PayloadUserDataItemCpuFunctionAlarmAckResponse items = - (S7PayloadUserDataItemCpuFunctionAlarmAckResponse) - payloadItems.get(0); + (S7PayloadUserDataItemCpuFunctionAlarmAckResponse) + payloadItems.get(0) ; //String tagName = (String) plcSubscriptionRequest.getTagNames().toArray()[0]; //TODO: Chequear si tagName es el correcto - logger.info("strTagName: {}", strTagName); - values.put(strTagName, new ResponseItem<>(PlcResponseCode.OK, null)); - for (short s : items.getMessageObjects()) { + logger.info("strTagName: " + strTagName); + values.put(strTagName, new ResponseItem(PlcResponseCode.OK, null)); + for (short s:items.getMessageObjects()){ if (s == 0x0000) { - values.put(Integer.toHexString(s), new ResponseItem<>(PlcResponseCode.OK, null)); + values.put(Integer.toHexString(s), new ResponseItem(PlcResponseCode.OK, null)); } else if (s == 0x000a) { - values.put(Integer.toHexString(s), new ResponseItem<>(PlcResponseCode.NOT_FOUND, null)); + values.put(Integer.toHexString(s), new ResponseItem(PlcResponseCode.NOT_FOUND, null)); } } - return new DefaultPlcSubscriptionResponse(plcSubscriptionRequest, values); - - } else if (payloadItems.get(0) instanceof S7PayloadUserDataItemCpuFunctionAlarmAckErrorResponse) { - - /*S7PayloadUserDataItemCpuFunctionAlarmAckResponse items = - (S7PayloadUserDataItemCpuFunctionAlarmAckResponse) - payloadItems.get(0);*/ - //String fieldName = (String) S7PayloadUserDataItemCyclicServicesPush .getFieldNames().toArray()[0]; - logger.warn("Request field: {}: {} {}", strTagName, S7ParamErrorCode.valueOf(errorCode), S7ParamErrorCode.valueOf(errorCode).getEvent()); - values.put(strTagName, new ResponseItem<>(PlcResponseCode.NOT_FOUND, null)); - return new DefaultPlcSubscriptionResponse(plcSubscriptionRequest, values); - - } else if (payloadItems.get(0) instanceof S7PayloadUserDataItemCpuFunctionAlarmQueryResponse) { + return new DefaultPlcSubscriptionResponse(plcSubscriptionRequest,values); + + } else if (payloadItems.get(0) instanceof S7PayloadUserDataItemCpuFunctionAlarmAckErrorResponse) { + + S7PayloadUserDataItemCpuFunctionAlarmAckResponse items = + (S7PayloadUserDataItemCpuFunctionAlarmAckResponse) + payloadItems.get(0); + //String fieldName = (String) S7PayloadUserDataItemCyclicServicesPush .getFieldNames().toArray()[0]; + logger.warn("Request field: " + strTagName + ": " + S7ParamErrorCode.valueOf(errorCode)+ " " + S7ParamErrorCode.valueOf(errorCode).getEvent()); + values.put(strTagName, new ResponseItem(PlcResponseCode.NOT_FOUND, null)); + return new DefaultPlcSubscriptionResponse(plcSubscriptionRequest,values); + + } else if (payloadItems.get(0) instanceof S7PayloadUserDataItemCpuFunctionAlarmQueryResponse) { S7PayloadUserDataItemCpuFunctionAlarmQueryResponse items = - (S7PayloadUserDataItemCpuFunctionAlarmQueryResponse) payloadItems.get(0); + (S7PayloadUserDataItemCpuFunctionAlarmQueryResponse) payloadItems.get(0); ByteBuf buffer = Unpooled.directBuffer(items.getItems().length * 2); - ByteBuf rxBuffer = Unpooled.directBuffer(items.getItems().length * 2); + ByteBuf rxbuffer = Unpooled.directBuffer(items.getItems().length * 2); buffer.writeBytes(items.getItems()); - - - //int numberOfItems = 1; - - if (itemparameter.getLastDataUnit() == 1) { - - short loop = 0xff; - CompletableFuture loopfuture; - S7MessageUserData msg; - S7ParameterUserDataItemCPUFunctions loopparameter; - S7PayloadUserDataItemCpuFunctionAlarmQueryResponse looppayload = null; - + + + int numberOfItems = 1; + + if (itemparameter.getLastDataUnit() == 1){ + + short loop = 0xff; + CompletableFuture loopfuture = null; + S7MessageUserData msg = null; + S7ParameterUserDataItemCPUFunctions loopparameter = null; + S7PayloadUserDataItemCpuFunctionAlarmQueryResponse looppayload = null; + do { loopfuture = reassembledAlarmEvents(itemparameter.getSequenceNumber()); - + try { - + msg = loopfuture.get(); if (msg != null) { - loopparameter = (S7ParameterUserDataItemCPUFunctions) ((S7ParameterUserData) msg.getParameter()).getItems().get(0); + loopparameter = (S7ParameterUserDataItemCPUFunctions) ((S7ParameterUserData) msg.getParameter()).getItems().get(0); looppayload = (S7PayloadUserDataItemCpuFunctionAlarmQueryResponse) ((S7PayloadUserData) msg.getPayload()).getItems().get(0); buffer.writeBytes(looppayload.getItems()); @@ -791,92 +979,104 @@ private PlcSubscriptionResponse decodeEventSubscriptionRequest(String strTagName loop = loopparameter.getLastDataUnit(); } else loop = 0x00; - + } catch (Exception ex) { logger.warn(ex.toString()); } } while (loop > 0x00); - rxBuffer.writeByte(looppayload.getReturnCode().getValue()); - rxBuffer.writeByte(looppayload.getTransportSize().getValue()); - rxBuffer.writeShort(looppayload.getDataLength()); - rxBuffer.writeBytes(buffer); + rxbuffer.writeByte(looppayload .getReturnCode().getValue()); + rxbuffer.writeByte(looppayload .getTransportSize().getValue()); + rxbuffer.writeShort(looppayload.getDataLength()); + rxbuffer.writeBytes(buffer); } else { - rxBuffer.writeByte(payloadItems.get(0).getReturnCode().getValue()); - rxBuffer.writeByte(payloadItems.get(0).getTransportSize().getValue()); - rxBuffer.writeShort(payloadItems.get(0).getDataLength()); - rxBuffer.writeBytes(buffer); + rxbuffer.writeByte(payloadItems.get(0).getReturnCode().getValue()); + rxbuffer.writeByte(payloadItems.get(0).getTransportSize().getValue()); + rxbuffer.writeShort(payloadItems.get(0).getDataLength()); + rxbuffer.writeBytes(buffer); } - - ReadBuffer readBuffer = new ReadBufferByteBased(ByteBufUtil.getBytes(rxBuffer)); + + ReadBuffer readBuffer = new ReadBufferByteBased(ByteBufUtil.getBytes(rxbuffer)); try { - + short cpuSubfunction = 0x00; - + if (s7DriverContext.getControllerType() == S7ControllerType.S7_300) { - cpuSubfunction = 0x13; - } else cpuSubfunction = 0xf0; + cpuSubfunction = 0x13; + } else cpuSubfunction = 0xf0 ; - S7PayloadUserDataItem payloadItem = - S7PayloadUserDataItem.staticParse(readBuffer, + S7PayloadUserDataItem payloaditem = + S7PayloadUserDataItem.staticParse(readBuffer, (byte) 0x04, - (byte) 0x00, + (byte) 0x00, cpuSubfunction); - eventQueue.add(payloadItem); - } catch (Exception ex) { + eventQueue.add(payloaditem); + } catch (Exception ex) { logger.info(ex.toString()); - } - - PlcResponseCode resCode = (items.getReturnCode() == DataTransportErrorCode.OK) ? PlcResponseCode.OK : PlcResponseCode.INTERNAL_ERROR; - values.put(strTagName, new ResponseItem<>(resCode, null)); - return new DefaultPlcSubscriptionResponse(plcSubscriptionRequest, values); - - } else if (payloadItems.get(0) instanceof S7PayloadUserDataItemCyclicServicesSubscribeResponse) { + } + + PlcResponseCode rescode = (items.getReturnCode() == DataTransportErrorCode.OK) ? PlcResponseCode.OK : PlcResponseCode.INTERNAL_ERROR; + values.put(strTagName, new ResponseItem(rescode, null)); + return new DefaultPlcSubscriptionResponse(plcSubscriptionRequest,values); + + } else if (payloadItems.get(0) instanceof S7PayloadUserDataItemCyclicServicesSubscribeResponse) { //S7ParameterUserData parameter = (S7ParameterUserData) responseMessage.getParameter(); //logger.info("Aqui debe responder a Cyclic transfer"); - S7ParameterUserDataItemCPUFunctions msgParameter = (S7ParameterUserDataItemCPUFunctions) - parameter.getItems().get(0); - + S7ParameterUserDataItemCPUFunctions msgparameter = (S7ParameterUserDataItemCPUFunctions) + parameter.getItems().get(0); + + cycrequests.put(msgparameter.getSequenceNumber(), plcSubscriptionRequest); + S7CyclicEvent cycevent = new S7CyclicEvent(plcSubscriptionRequest, - msgParameter.getSequenceNumber(), - (S7PayloadUserDataItemCyclicServicesSubscribeResponse) payloadItems.get(0)); - - eventQueue.add(cycevent); - values.put(strTagName, new ResponseItem<>(PlcResponseCode.OK, cycHandle)); - return new DefaultPlcSubscriptionResponse(plcSubscriptionRequest, values); - - } else if (payloadItems.get(0) instanceof S7PayloadUserDataItemCyclicServicesChangeDrivenSubscribeResponse) { + msgparameter.getSequenceNumber(), + (S7PayloadUserDataItemCyclicServicesSubscribeResponse) payloadItems.get(0)); + + eventQueue.add(cycevent); + + S7PlcSubscriptionHandle cycHandle = new S7PlcSubscriptionHandle(strTagName, EventType.CYC, EventLogic); + + ResponseItem response = new ResponseItem(PlcResponseCode.OK, cycHandle); + plcSubscriptionRequest.getTagNames().forEach(s -> { + values.put(s, response); + }); + + return new DefaultPlcSubscriptionResponse(plcSubscriptionRequest,values); + + } else if (payloadItems.get(0) instanceof S7PayloadUserDataItemCyclicServicesChangeDrivenSubscribeResponse) { //logger.info("Aqui debe responder a Cyclic transfer Change Driven"); - S7ParameterUserDataItemCPUFunctions msgParameter = (S7ParameterUserDataItemCPUFunctions) - parameter.getItems().get(0); - - S7CyclicEvent cycEvent = new S7CyclicEvent(plcSubscriptionRequest, - msgParameter.getSequenceNumber(), - (S7PayloadUserDataItemCyclicServicesChangeDrivenSubscribeResponse) payloadItems.get(0)); - - eventQueue.add(cycEvent); - values.put(strTagName, new ResponseItem<>(PlcResponseCode.OK, cycHandle)); - return new DefaultPlcSubscriptionResponse(plcSubscriptionRequest, values); + S7ParameterUserDataItemCPUFunctions msgparameter = (S7ParameterUserDataItemCPUFunctions) + parameter.getItems().get(0); + + cycrequests.put(msgparameter.getSequenceNumber(), plcSubscriptionRequest); - } else if (payloadItems.get(0) instanceof S7PayloadUserDataItemCyclicServicesErrorResponse) { - // TODO: It seems this isn't fully implemented. + S7CyclicEvent cycevent = new S7CyclicEvent(plcSubscriptionRequest, + msgparameter.getSequenceNumber(), + (S7PayloadUserDataItemCyclicServicesChangeDrivenSubscribeResponse) payloadItems.get(0)); + + eventQueue.add(cycevent); + + S7PlcSubscriptionHandle cycHandle = new S7PlcSubscriptionHandle(strTagName, EventType.CYC, EventLogic); + values.put(strTagName, new ResponseItem(PlcResponseCode.OK, cycHandle)); + return new DefaultPlcSubscriptionResponse(plcSubscriptionRequest,values); + + } else if (payloadItems.get(0) instanceof S7PayloadUserDataItemCyclicServicesErrorResponse) { //S7ParameterUserData parameter = (S7ParameterUserData) responseMessage.getParameter(); //S7ParameterUserDataItem[] parameters = parameter.getItems(); //S7ParameterUserDataItemCPUFunctions itemparameter = (S7ParameterUserDataItemCPUFunctions) parameters[0]; //errorCode = itemparameter.getErrorCode().shortValue(); - logger.warn("Request field: " + strTagName + ": " + S7ParamErrorCode.valueOf(errorCode) + " " + S7ParamErrorCode.valueOf(errorCode).getEvent()); - if (errorCode == 0x8104) { - values.put(strTagName, new ResponseItem<>(PlcResponseCode.UNSUPPORTED, null)); - } else - values.put(strTagName, new ResponseItem<>(PlcResponseCode.INTERNAL_ERROR, null)); - return new DefaultPlcSubscriptionResponse(plcSubscriptionRequest, values); + logger.warn("Request field: " + strTagName + ": " + S7ParamErrorCode.valueOf(errorCode)+ " " + S7ParamErrorCode.valueOf(errorCode).getEvent()); + if (errorCode == 0x8104){ + values.put(strTagName, new ResponseItem(PlcResponseCode.UNSUPPORTED, null)); + } else + values.put(strTagName, new ResponseItem(PlcResponseCode.INTERNAL_ERROR, null)); + return new DefaultPlcSubscriptionResponse(plcSubscriptionRequest,values); } else if (payloadItems.get(0) instanceof S7PayloadUserDataItemCyclicServicesUnsubscribeResponse) { - values.put(strTagName, new ResponseItem<>(PlcResponseCode.OK, null)); - return new DefaultPlcSubscriptionResponse(plcSubscriptionRequest, values); - } + values.put(strTagName, new ResponseItem(PlcResponseCode.OK, null)); + return new DefaultPlcSubscriptionResponse(plcSubscriptionRequest,values); + } if (responseOk) { for (String tagName : plcSubscriptionRequest.getTagNames()) { @@ -910,25 +1110,25 @@ private void encodeEventUnSubscriptionRequest(DefaultPlcSubscriptionRequest requ } - private void encodeAlarmAckRequest(DefaultPlcReadRequest request, - List parameterItems, - List payloadItems) { - + private void encodeAlarmAckRequest( DefaultPlcReadRequest request, + List parameterItems, + List payloadItems) { + S7ParameterUserDataItemCPUFunctions parameter = new S7ParameterUserDataItemCPUFunctions( - (short) 0x11, //Method - (byte) 0x04, //FunctionType - (byte) 0x04, //FunctionGroup - (short) 0x0b, //SubFunction - (short) 0x00, //SequenceNumber - null, //DataUnitReferenceNumber - null, //LastDataUnit - null //errorCode - ); + (short) 0x11, //Method + (byte) 0x04, //FunctionType + (byte) 0x04, //FunctionGroup + (short) 0x0b, //SubFunction + (short) 0x00, //SequenceNumber + null, //DataUnitReferenceNumber + null, //LastDataUnit + null //errorCode + ); parameterItems.clear(); parameterItems.add(parameter); - + ArrayList messageObjects = null; - BitSet bs; + BitSet bs = new BitSet(); for (String fieldName : request.getTagNames()) { if (request.getTag(fieldName) instanceof S7AckTag) { PlcTag field = request.getTag(fieldName); @@ -936,247 +1136,350 @@ private void encodeAlarmAckRequest(DefaultPlcReadRequest request, ArrayList arrAlarmIds = ((S7AckTag) field).getAlarmIds(); ArrayList arrAlarmSigs = ((S7AckTag) field).getAlarmSigs(); //messageObjects = new AlarmMessageObjectAckType[arrAlarmIds.size()]; - messageObjects = new ArrayList<>(); + messageObjects = new ArrayList(); int j = 0; for (int i = 0; i < arrAlarmIds.size(); i++) { - bs = BitSet.valueOf(new byte[]{arrAlarmSigs.get(i).byteValue()}); - - AlarmMessageObjectAckType messageObject = new AlarmMessageObjectAckType( - SyntaxIdType.ALARM_ACKSET, - (short) 0, - arrAlarmIds.get(i), - new State(bs.get(7), bs.get(6), bs.get(5), bs.get(4), bs.get(3), bs.get(2), bs.get(1), bs.get(0)), - new State(bs.get(7), bs.get(6), bs.get(5), bs.get(4), bs.get(3), bs.get(2), bs.get(1), bs.get(0)) - ); - //messageObjects[i] = messageObject; - messageObjects.add(messageObject); + bs = BitSet.valueOf(new byte[]{arrAlarmSigs.get(i).byteValue()}); + + AlarmMessageObjectAckType messageObject = new AlarmMessageObjectAckType( + SyntaxIdType.ALARM_ACKSET, + (short) 0, + arrAlarmIds.get(i), + new State(bs.get(7),bs.get(6),bs.get(5),bs.get(4),bs.get(3),bs.get(2),bs.get(1),bs.get(0)), + new State(bs.get(7),bs.get(6),bs.get(5),bs.get(4),bs.get(3),bs.get(2),bs.get(1),bs.get(0)) + ); + //messageObjects[i] = messageObject; + messageObjects.add(messageObject); } } } } - + S7PayloadUserDataItemCpuFunctionAlarmAckRequest payload = new S7PayloadUserDataItemCpuFunctionAlarmAckRequest( - DataTransportErrorCode.OK, - DataTransportSize.OCTET_STRING, - 0x0c, - messageObjects); + DataTransportErrorCode.OK, + DataTransportSize.OCTET_STRING, + 0x0c, + messageObjects); // payloadItems.clear(); - payloadItems.add(payload); - - } + payloadItems.add(payload); + + } private void encodeAlarmQueryRequest(DefaultPlcSubscriptionRequest request, - List parameterItems, - List payloadItems) { - + List parameterItems, + List payloadItems) { + S7ParameterUserDataItemCPUFunctions parameter = new S7ParameterUserDataItemCPUFunctions( - (short) 0x11, //Method - (byte) 0x04, //FunctionType - (byte) 0x04, //FunctionGroup - (short) 0x13, //SubFunction - (short) 0x00, //SequenceNumber - null, //DataUnitReferenceNumber - null, //LastDataUnit - null //errorCode - ); - + (short) 0x11, //Method + (byte) 0x04, //FunctionType + (byte) 0x04, //FunctionGroup + (short) 0x13, //SubFunction + (short) 0x00, //SequenceNumber + null, //DataUnitReferenceNumber + null, //LastDataUnit + null //errorCode + ); + parameterItems.clear(); parameterItems.add(parameter); - + //TODO: Chequear el tipo dfe larma. S7PayloadUserDataItemCpuFunctionAlarmQueryRequest payload = new S7PayloadUserDataItemCpuFunctionAlarmQueryRequest( - DataTransportErrorCode.OK, - DataTransportSize.OCTET_STRING, - 0x0c, - SyntaxIdType.ALARM_QUERYREQSET, - QueryType.ALARM_8P, - AlarmType.ALARM_8); - + DataTransportErrorCode.OK, + DataTransportSize.OCTET_STRING, + 0x0c, + SyntaxIdType.ALARM_QUERYREQSET, + QueryType.ALARM_8P, + AlarmType.ALARM_8); + payloadItems.clear(); - payloadItems.add(payload); + payloadItems.add(payload); } private void encodeCycledSubscriptionRequest(DefaultPlcSubscriptionRequest request, - List parameterItems, - List payloadItem) { + List parameterItems, + List payloadItem) { } - private void encodeCycledS7ANYSubscriptionRequest(PlcSubscriptionTag plctag, - List parameterItems, - List payloadItems) { + private void encodeCycledS7ANYSubscriptionRequest(DefaultPlcSubscriptionRequest request, + List parameterItems, + List payloadItems){ S7ParameterUserDataItemCPUFunctions parameter = new S7ParameterUserDataItemCPUFunctions( - (short) 0x11, //Method - (byte) 0x04, //FunctionType - (byte) 0x02, //FunctionGroup - (short) 0x01, //SubFunction - (short) 0x00, //SequenceNumber - null, //DataUnitReferenceNumber - null, //LastDataUnit - null //errorCode - ); - + (short) 0x11, //Method + (byte) 0x04, //FunctionType + (byte) 0x02, //FunctionGroup + (short) 0x01, //SubFunction + (short) 0x00, //SequenceNumber + null, //DataUnitReferenceNumber + null, //LastDataUnit + null //errorCode + ); + parameterItems.clear(); parameterItems.add(parameter); - + //TODO: Chequear la asignacionde tipo - PlcTag tag = ((DefaultPlcSubscriptionTag) plctag).getTag(); - S7SubscriptionTag s7tag = (S7SubscriptionTag) tag; + //PlcTag tag = ((DefaultPlcSubscriptionTag) plctag).getTag(); + //S7SubscriptionTag s7tag = (S7SubscriptionTag) tag; // - List items = new ArrayList<>(); + List items = new ArrayList(); + + request.getTags().forEach(tag -> { + +// PlcTag plctag = ((DefaultPlcSubscriptionTag) tag).getTag(); + S7SubscriptionTag s7tag = (S7SubscriptionTag ) ((DefaultPlcSubscriptionTag) ((PlcSubscriptionTag) tag)).getTag(); +// + for (S7Tag userfield:s7tag.getS7Tags()) { + items.add(new CycServiceItemAnyType( + (short) 0x0a, + (short) 0x10, //S7ANY + userfield.getDataType(), + userfield.getNumberOfElements(), + userfield.getBlockNumber(), + userfield.getMemoryArea(), + (int) (((userfield.getByteOffset() << 3) | (userfield.getBitOffset() & 0x0007))) + )); + } + }); + + S7SubscriptionTag s7tag_base = (S7SubscriptionTag) ((DefaultPlcSubscriptionTag) ((PlcSubscriptionTag) request.getTags().get(0))).getTag(); + // - int i = 0; - for (S7Tag userfield : s7tag.getS7Tags()) { - items.add(new CycServiceItemAnyType( - (short) 0x0a, - (short) 0x10, //S7ANY - userfield.getDataType(), - userfield.getNumberOfElements(), - userfield.getBlockNumber(), - userfield.getMemoryArea(), - (((userfield.getByteOffset() << 3) | (userfield.getBitOffset() & 0x0007))) - )); - i++; - } +// int i=0; +// for (S7Tag userfield:s7tag.getS7Tags()) { +// items.add(new CycServiceItemAnyType( +// (short) 0x0a, +// (short) 0x10, //S7ANY +// userfield.getDataType(), +// userfield.getNumberOfElements(), +// userfield.getBlockNumber(), +// userfield.getMemoryArea(), +// (long) (((userfield.getByteOffset() << 3) | (userfield.getBitOffset() & 0x0007))) +// )); +// i++; +// } // // //Length in bytes // //4+12*items.legth int lengthInBytes = 4 + items.size() * 12; // S7PayloadUserDataItemCyclicServicesSubscribeRequest payload = - new S7PayloadUserDataItemCyclicServicesSubscribeRequest( - DataTransportErrorCode.OK, - DataTransportSize.OCTET_STRING, - lengthInBytes, - items.size(), - s7tag.getTimeBase(), - s7tag.getMultiplier(), - items - ); + new S7PayloadUserDataItemCyclicServicesSubscribeRequest( + DataTransportErrorCode.OK, + DataTransportSize.OCTET_STRING, + lengthInBytes, + items.size(), + s7tag_base.getTimeBase(), + s7tag_base.getMultiplier(), + items + ); payloadItems.clear(); payloadItems.add(payload); } + - - private void encodeCycledDBREADSubscriptionRequest(PlcSubscriptionTag plctag, - List parameterItems, - List payloadItems) { + private void encodeCycledDBREADSubscriptionRequest(DefaultPlcSubscriptionRequest request, + List parameterItems, + List payloadItems){ S7ParameterUserDataItemCPUFunctions parameter = new S7ParameterUserDataItemCPUFunctions( - (short) 0x11, //Method - (byte) 0x04, //FunctionType - (byte) 0x02, //FunctionGroup - (short) 0x01, //SubFunction - (short) 0x00, //SequenceNumber - null, //DataUnitReferenceNumber - null, //LastDataUnit - null //errorCode - ); - + (short) 0x11, //Method + (byte) 0x04, //FunctionType + (byte) 0x02, //FunctionGroup + (short) 0x01, //SubFunction + (short) 0x00, //SequenceNumber + null, //DataUnitReferenceNumber + null, //LastDataUnit + null //errorCode + ); + parameterItems.clear(); parameterItems.add(parameter); - + //TODO: Chequear la asignacionde tipo + PlcSubscriptionTag plctag = request.getTags().get(0); + PlcTag tag = ((DefaultPlcSubscriptionTag) plctag).getTag(); S7SubscriptionTag s7tag = (S7SubscriptionTag) tag; - double cycitemcount = Math.ceil(((double) s7tag.getS7Tags().length / (double) 50)); - + double cycitemcount = Math.ceil(((double)s7tag.getS7Tags().length / (double) 50)); + //CycServiceItemDbReadType[] cycitems = new CycServiceItemDbReadType[(int) cycitemcount]; List cycitems = new ArrayList(); - ArrayList subitems = new ArrayList(); - for (S7Tag userfield : s7tag.getS7Tags()) { + ArrayList subitems = new ArrayList(); + for (S7Tag userfield:s7tag.getS7Tags()){ subitems.add(new SubItem((short) userfield.getNumberOfElements(), - userfield.getBlockNumber(), - userfield.getByteOffset())); - } - + userfield.getBlockNumber(), + userfield.getByteOffset())); + } + int initpos = 0; - int endpos = (subitems.size() < 50) ? subitems.size() : 49; - int j = 0; - int lengthInBytes = 4; - do { - List arraysubitems = subitems.subList(initpos, endpos); - - cycitems.add(j, new CycServiceItemDbReadType( - (short) (arraysubitems.size() * 5 + 2), - (short) 0xb0, - (short) arraysubitems.size(), - arraysubitems)); - + int endpos = (subitems.size() < 50)?subitems.size():49; + int j=0; + int lengthInBytes = 4; + do{ + List arraysubitems = subitems.subList(initpos, endpos); + + cycitems.add(j,new CycServiceItemDbReadType( + (short) (arraysubitems.size()*5+2), + (short) 0xb0, + (short) arraysubitems.size(), + arraysubitems)); + lengthInBytes += 4 + arraysubitems.size() * 5; initpos = endpos++; - endpos = ((initpos + 49) < subitems.size()) ? (initpos + 49) : subitems.size(); + endpos = ((initpos+49) < subitems.size())?(initpos+49):subitems.size(); j++; } while (j < cycitems.size()); S7PayloadUserDataItemCyclicServicesSubscribeRequest payload = - new S7PayloadUserDataItemCyclicServicesSubscribeRequest( - DataTransportErrorCode.OK, - DataTransportSize.OCTET_STRING, - lengthInBytes, - cycitems.size(), - s7tag.getTimeBase(), - s7tag.getMultiplier(), - cycitems - ); - + new S7PayloadUserDataItemCyclicServicesSubscribeRequest( + DataTransportErrorCode.OK, + DataTransportSize.OCTET_STRING, + lengthInBytes, + cycitems.size(), + s7tag.getTimeBase(), + s7tag.getMultiplier(), + cycitems + ); + payloadItems.clear(); payloadItems.add(payload); } + + + private void encodeCycledUnSubscriptionRequest(DefaultPlcUnsubscriptionRequest request, + List parameterItems, + List payloadItems) { + + S7ParameterUserDataItemCPUFunctions parameter = new S7ParameterUserDataItemCPUFunctions( + (short) 0x11, //Method + (byte) 0x04, //FunctionType + (byte) 0x02, //FunctionGroup + (short) 0x04, //SubFunction + (short) 0x00, //SequenceNumber + null, //DataUnitReferenceNumber + null, //LastDataUnit + null //errorCode + ); + + parameterItems.clear(); + parameterItems.add(parameter); + + + List handles = request.getSubscriptionHandles(); + //PlcField field = ((DefaultPlcSubscriptionField) plcfield).getPlcField(); + //S7SubscriptionField s7field = (S7SubscriptionField) field; + + payloadItems.clear(); + //TODO:Check CPU type + handles.forEach(h -> { + S7PayloadUserDataItemCyclicServicesUnsubscribeRequest payload = + new S7PayloadUserDataItemCyclicServicesUnsubscribeRequest ( + DataTransportErrorCode.OK, + DataTransportSize.OCTET_STRING, + 0x02, + (short) 0x01, + Short.parseShort(((S7PlcSubscriptionHandle) h).getEventId())); + + payloadItems.add(payload); + }); + +// s7tag.getAckAlarms().forEach(jobid -> { +// S7PayloadUserDataItemCyclicServicesUnsubscribeRequest payload = +// new S7PayloadUserDataItemCyclicServicesUnsubscribeRequest ( +// DataTransportErrorCode.OK, +// DataTransportSize.OCTET_STRING, +// 0x02, +// (short) 0x05, +// jobid.byteValue()); +// +// payloadItems.add(payload); +// }); + } - private void encodeCycledUnSubscriptionRequest(DefaultPlcSubscriptionRequest request, - List parameterItems, - List payloadItems) { - + private void encodePlcClkRequest(DefaultPlcReadRequest request, + List parameterItems, + List payloadItems) { + final S7ClkTag tag = (S7ClkTag) request.getTags().get(0); + int subfunction = tag.getAddressString().equals("CLK")?1:3; + S7ParameterUserDataItemCPUFunctions parameter = new S7ParameterUserDataItemCPUFunctions( - (short) 0x11, //Method - (byte) 0x04, //FunctionType - (byte) 0x02, //FunctionGroup - (short) 0x04, //SubFunction - (short) 0x00, //SequenceNumber - null, //DataUnitReferenceNumber - null, //LastDataUnit - null //errorCode - ); - + (short) 0x11, //Method + (byte) 0x04, //FunctionType + (byte) 0x07, //FunctionGroup + (short) subfunction, //SubFunction + (short) 0x00, //SequenceNumber + null, //DataUnitReferenceNumber + null, //LastDataUnit + null //errorCode + ); + parameterItems.clear(); parameterItems.add(parameter); + + S7PayloadUserDataItemClkRequest payload; + payload = new S7PayloadUserDataItemClkRequest( + DataTransportErrorCode.NOT_FOUND, + DataTransportSize.NULL, + 0x00); + + + payloadItems.clear(); + payloadItems.add(payload); + } + + + private void encodePlcClkSetRequest(DefaultPlcWriteRequest request, + List parameterItems, + List payloadItems) { - PlcSubscriptionTag tag = request.getTags().get(0); - S7SubscriptionTag s7tag = (S7SubscriptionTag) tag; - //PlcField field = ((DefaultPlcSubscriptionField) plcfield).getPlcField(); - //S7SubscriptionField s7field = (S7SubscriptionField) field; + S7ParameterUserDataItemCPUFunctions parameter = new S7ParameterUserDataItemCPUFunctions( + (short) 0x11, //Method + (byte) 0x04, //FunctionType + (byte) 0x07, //FunctionGroup + (short) 0x04, //SubFunction + (short) 0x00, //SequenceNumber + null, //DataUnitReferenceNumber + null, //LastDataUnit + null //errorCode + ); - //TODO:Check CPU type - S7PayloadUserDataItemCyclicServicesUnsubscribeRequest payload = - new S7PayloadUserDataItemCyclicServicesUnsubscribeRequest( + parameterItems.clear(); + parameterItems.add(parameter); + + S7ClkTag tag = (S7ClkTag) request.getTags().get(0); + + S7PayloadUserDataItemClkSetRequest payload; + payload = new S7PayloadUserDataItemClkSetRequest ( DataTransportErrorCode.OK, DataTransportSize.OCTET_STRING, - 0x02, - (short) 0x05, - s7tag.getAckAlarms().get(0).byteValue() - ); + (int) 0x0A, + tag.getDateAndTime()); + payloadItems.clear(); payloadItems.add(payload); - - } - + } + + + /** * This method is only called when there is no Response Handler. */ @Override protected void decode(ConversationContext context, TPKTPacket msg) throws Exception { + S7Message s7msg = msg.getPayload().getPayload(); S7Parameter parameter = s7msg.getParameter(); if (parameter instanceof S7ParameterModeTransition) { @@ -1209,39 +1512,39 @@ protected void decode(ConversationContext context, TPKTPacket msg) t eventQueue.addAll(items); } else if ((myparameter.getCpuFunctionType() == 0x00) && (myparameter.getCpuSubfunction() == 0x13)) { - } else if ((myparameter.getCpuFunctionGroup() == 0x02) && (myparameter.getCpuFunctionType() == 0x00) && (myparameter.getCpuSubfunction() == 0x01)) { - - S7ParameterUserDataItemCPUFunctions parameteritem = - (S7ParameterUserDataItemCPUFunctions) - ((S7ParameterUserData) parameter).getItems().get(0); - - S7PayloadUserData payload = (S7PayloadUserData) s7msg.getPayload(); - - S7PayloadUserDataItemCyclicServicesPush payloaditem = - (S7PayloadUserDataItemCyclicServicesPush) - payload.getItems().get(0); - - S7CyclicEvent cycevent = new S7CyclicEvent(null, - parameteritem.getSequenceNumber(), - payloaditem); - eventQueue.add(cycevent); - - } else if ((myparameter.getCpuFunctionGroup() == 0x02) && (myparameter.getCpuFunctionType() == 0x00) && (myparameter.getCpuSubfunction() == 0x05)) { - S7ParameterUserDataItemCPUFunctions parameterItem = - (S7ParameterUserDataItemCPUFunctions) - ((S7ParameterUserData) parameter).getItems().get(0); - - S7PayloadUserData payload = (S7PayloadUserData) s7msg.getPayload(); - - S7PayloadUserDataItemCyclicServicesChangeDrivenPush payloadItem = - (S7PayloadUserDataItemCyclicServicesChangeDrivenPush) - payload.getItems().get(0); - - S7CyclicEvent cycEvent = new S7CyclicEvent(null, - parameterItem.getSequenceNumber(), - payloadItem); - eventQueue.add(cycEvent); - + } else if ((myparameter.getCpuFunctionGroup() == 0x02) && (myparameter.getCpuFunctionType() == 0x00) && (myparameter.getCpuSubfunction() == 0x01)){ + + S7ParameterUserDataItemCPUFunctions parameteritem = + (S7ParameterUserDataItemCPUFunctions) + ((S7ParameterUserData) parameter).getItems().get(0); + + S7PayloadUserData payload = (S7PayloadUserData) s7msg.getPayload(); + + S7PayloadUserDataItemCyclicServicesPush payloaditem = + (S7PayloadUserDataItemCyclicServicesPush) + payload.getItems().get(0); + + S7CyclicEvent cycevent = new S7CyclicEvent(cycrequests.get(parameteritem.getSequenceNumber()), + parameteritem.getSequenceNumber(), + payloaditem); + eventQueue.add(cycevent); + + } else if ((myparameter.getCpuFunctionGroup() == 0x02) && (myparameter.getCpuFunctionType() == 0x00) && (myparameter.getCpuSubfunction() == 0x05)) { + S7ParameterUserDataItemCPUFunctions parameteritem = + (S7ParameterUserDataItemCPUFunctions) + ((S7ParameterUserData) parameter).getItems().get(0); + + S7PayloadUserData payload = (S7PayloadUserData) s7msg.getPayload(); + + S7PayloadUserDataItemCyclicServicesChangeDrivenPush payloaditem = + (S7PayloadUserDataItemCyclicServicesChangeDrivenPush) + payload.getItems().get(0); + + S7CyclicEvent cycevent = new S7CyclicEvent(null, + parameteritem.getSequenceNumber(), + payloaditem); + eventQueue.add(cycevent); + } else if ((myparameter.getCpuFunctionType() == 0x08) && (myparameter.getCpuSubfunction() == 0x01)) { } else if ((myparameter.getCpuFunctionType() == 0x08) && (myparameter.getCpuSubfunction() == 0x04)) { @@ -1265,8 +1568,7 @@ private void extractControllerTypeAndFireConnected(ConversationContext payloadItems = payload.getItems(); + } + + List payloadItems = payload.getItems(); PlcResponseCode responseCode = PlcResponseCode.INTERNAL_ERROR; - PlcValue plcValue = null; + PlcValue plcValue = null; int index = 0; for (String tagName : plcReadRequest.getTagNames()) { + + if (plcReadRequest.getTag(tagName) instanceof S7SzlTag ) { - if (plcReadRequest.getTag(tagName) instanceof S7SzlTag) { - S7PayloadUserDataItemCpuFunctionReadSzlResponse payloadItem = (S7PayloadUserDataItemCpuFunctionReadSzlResponse) payloadItems.get(index); + S7SzlTag tag = (S7SzlTag) plcReadRequest.getTag(tagName); + S7PayloadUserDataItemCpuFunctionReadSzlResponse payloadItem = (S7PayloadUserDataItemCpuFunctionReadSzlResponse) payloadItems.get(index); responseCode = decodeResponseCode(payloadItem.getReturnCode()); - + if (responseCode == PlcResponseCode.OK) { try { - List plcvalues = new LinkedList<>(); + LinkedList plcvalues = null; byte[] data = payloadItem.getItems(); - for (byte b : data) plcvalues.add(new PlcSINT(b)); + plcvalues = new LinkedList(); + for (byte b:data ) plcvalues.add(new PlcSINT(b)); if (parameteritem.getLastDataUnit() == 1) { - CompletableFuture nextFuture; - S7ParameterUserData next_parameter; - S7PayloadUserData next_payload; - S7PayloadUserDataItemCpuFunctionReadSzlResponse next_payloadItem; - + CompletableFuture next_future = null; + S7ParameterUserData next_parameter = null; + S7PayloadUserData next_payload = null; + S7PayloadUserDataItemCpuFunctionReadSzlResponse next_payloadItem = null; + while (parameteritem.getLastDataUnit() == 1) { //TODO: Just wait for one answer!. Pending for other packages for rearm. - nextFuture = reassembledMessage(parameteritem.getSequenceNumber()); - S7MessageUserData msg = nextFuture.get(); + next_future = reassembledMessage(parameteritem.getSequenceNumber(), plcvalues); + + S7MessageUserData msg = null; + + msg = next_future.get(); if (msg != null) { next_parameter = (S7ParameterUserData) msg.getParameter(); parameteritem = (S7ParameterUserDataItemCPUFunctions) next_parameter.getItems().get(0); next_payload = (S7PayloadUserData) msg.getPayload(); next_payloadItem = (S7PayloadUserDataItemCpuFunctionReadSzlResponse) next_payload.getItems().get(0); - for (byte b : next_payloadItem.getItems()) plcvalues.add(new PlcSINT(b)); + for (byte b:next_payloadItem.getItems()) plcvalues.add(new PlcSINT(b)); } - - plcValue = new PlcList(plcvalues); + + plcValue = new PlcList(plcvalues); } - + } else { - plcValue = new PlcList(plcvalues); + plcValue = new PlcList(plcvalues); } - } catch (Exception e) { + } catch(Exception e) { throw new PlcProtocolException("Error decoding PlcValue", e); } } - - } - if (plcReadRequest.getTag(tagName) instanceof S7AckTag) { + + } if (plcReadRequest.getTag(tagName) instanceof S7AckTag ) { S7AckTag field = (S7AckTag) plcReadRequest.getTag(tagName); - S7PayloadUserDataItemCpuFunctionAlarmAckResponse payloadItem = - (S7PayloadUserDataItemCpuFunctionAlarmAckResponse) payloadItems.get(index); - responseCode = decodeResponseCode(payloadItem.getReturnCode()); + S7PayloadUserDataItemCpuFunctionAlarmAckResponse payloadItem = + (S7PayloadUserDataItemCpuFunctionAlarmAckResponse) payloadItems.get(index); + responseCode = decodeResponseCode(payloadItem.getReturnCode()); List data = payloadItem.getMessageObjects(); - LinkedList plcValues = new LinkedList<>(); - for (short b : data) plcValues.add(new PlcSINT((byte) b)); - plcValue = new PlcList(plcValues); - } + LinkedList plcvalues = new LinkedList(); + for (short b:data ) plcvalues.add(new PlcSINT((byte) b)); + plcValue = new PlcList(plcvalues); + + } if (plcReadRequest.getTag(tagName) instanceof S7ClkTag ) { + S7ClkTag field = (S7ClkTag) plcReadRequest.getTag(tagName); + DateAndTime dt = null; + if (payloadItems.get(index) instanceof S7PayloadUserDataItemClkResponse) { + final S7PayloadUserDataItemClkResponse payloadItem = + (S7PayloadUserDataItemClkResponse) payloadItems.get(index); + responseCode = decodeResponseCode(payloadItem.getReturnCode()); + dt = payloadItem.getTimeStamp(); + } else if (payloadItems.get(index) instanceof S7PayloadUserDataItemClkFResponse) { + final S7PayloadUserDataItemClkFResponse payloadItem = + (S7PayloadUserDataItemClkFResponse) payloadItems.get(index); + responseCode = decodeResponseCode(payloadItem.getReturnCode()); + dt = payloadItem.getTimeStamp(); + } + LinkedList plcvalues = new LinkedList(); + plcvalues.add(PlcLDATE_AND_TIME.of(LocalDateTime.of( + dt.getYear() + 2000, + dt.getMonth(), + dt.getDay(), + dt.getHour(), + dt.getMinutes(), + dt.getSeconds(), + dt.getMsec() * 1000000 ))); + plcValue = new PlcList(plcvalues); + } + ResponseItem result = new ResponseItem<>(responseCode, plcValue); values.put(tagName, result); index++; } - return new DefaultPlcReadResponse(plcReadRequest, values); - - } - + return new DefaultPlcReadResponse(plcReadRequest, values); + + } + // In all other cases all went well. S7PayloadReadVarResponse payload = (S7PayloadReadVarResponse) responseMessage.getPayload(); @@ -1503,6 +1836,7 @@ private PlcResponse decodeWriteResponse(S7Message responseMessage, PlcWriteReque Map responses = new HashMap<>(); short errorClass; short errorCode; + if (responseMessage instanceof S7MessageResponseData) { S7MessageResponseData messageResponseData = (S7MessageResponseData) responseMessage; errorClass = messageResponseData.getErrorClass(); @@ -1511,6 +1845,10 @@ private PlcResponse decodeWriteResponse(S7Message responseMessage, PlcWriteReque S7MessageResponse messageResponse = (S7MessageResponse) responseMessage; errorClass = messageResponse.getErrorClass(); errorCode = messageResponse.getErrorCode(); + } else if (responseMessage instanceof S7MessageUserData) { + String tagName = (String) plcWriteRequest.getTagNames().toArray()[0]; + responses.put(tagName, PlcResponseCode.OK); + return new DefaultPlcWriteResponse(plcWriteRequest, responses); } else { throw new PlcProtocolException("Unsupported message type " + responseMessage.getClass().getName()); } @@ -1700,134 +2038,151 @@ protected S7Address encodeS7Address(PlcTag tag) { s7Tag.getMemoryArea(), s7Tag.getByteOffset(), s7Tag.getBitOffset()); } - - private void cleanFutures() { + /* + * In the case of a reconnection, there may be requests waiting, + * for which the operation must be terminated by exception and canceled + * in the transaction manager. If this does not happen, + * the driver operation can be frozen. + */ + private void cleanFutures(){ //TODO: Debe ser ejecutado si la conexion esta levanta. - activeRequests.forEach((f, p) -> { + active_requests.forEach((f,p)->{ CompletableFuture cf = (CompletableFuture) f; try { if (!cf.isDone()) { logger.info("CF"); cf.cancel(true); logger.info("ClientCF"); - ((CompletableFuture) p.getRight()).completeExceptionally(new PlcRuntimeException("Disconnected")); + ((CompletableFuture) p.getRight()).completeExceptionally(new PlcRuntimeException("Disconnected")); logger.info("TM"); p.getLeft().endRequest(); - } - } catch (Exception ex) { + }; + } catch (Exception ex){ logger.info(ex.toString()); } }); - activeRequests.clear(); - - } - - private boolean isConnected() { + active_requests.clear(); + } + + private boolean isConnected(){ return context.getChannel().attr(S7HMuxImpl.IS_CONNECTED).get(); //return true; } - - private boolean isPrimaryChannel() { - return context.getChannel().attr(S7HMuxImpl.IS_PRIMARY).get() == null || context.getChannel().attr(S7HMuxImpl.IS_PRIMARY).get(); - } - - private void setChannelFeatures() { - context.getChannel().attr(S7HMuxImpl.READ_TIME_OUT).set(s7DriverContext.getReadTimeout()); + + private boolean isPrimaryChannel(){ + boolean b = (context.getChannel().attr(S7HMuxImpl.IS_PRIMARY).get() == null)?true:context.getChannel().attr(S7HMuxImpl.IS_PRIMARY).get(); + return b; + //return true; + } + + private void setChannelFeatures(){ + context.getChannel().attr(S7HMuxImpl.READ_TIME_OUT).set(s7DriverContext.getReadTimeout()); context.getChannel().attr(S7HMuxImpl.IS_PING_ACTIVE).set(s7DriverContext.getPing()); context.getChannel().attr(S7HMuxImpl.PING_TIME).set(s7DriverContext.getPingTime()); - context.getChannel().attr(S7HMuxImpl.RETRY_TIME).set(s7DriverContext.getRetryTime()); - } - - - private boolean isSubscriptionSupported() { - return (s7DriverContext.getControllerType() == S7ControllerType.S7_300) || - (s7DriverContext.getControllerType() == S7ControllerType.S7_400); - } - - private CompletableFuture reassembledMessage(short sequenceNumber) { - + context.getChannel().attr(S7HMuxImpl.RETRY_TIME).set(s7DriverContext.getRetryTime()); + } + + + private boolean isFeatureSupported(){ + boolean b = ((s7DriverContext.getControllerType() == S7ControllerType.S7_300) || + (s7DriverContext.getControllerType() == S7ControllerType.S7_400)) + ? true:false; + return b; + } + + private CompletableFuture reassembledMessage(short sequenceNumber, LinkedList plcValues){ + CompletableFuture future = new CompletableFuture<>(); - + //TODO: PDU id is the same, we need check. int tpduId = tpduGenerator.getAndIncrement(); // If we've reached the max value for a 16 bit transaction identifier, reset back to 1 - tpduGenerator.compareAndExchange(0xFFFF, 1); + if(tpduGenerator.get() == 0xFFFF) { + tpduGenerator.set(1); + } TPKTPacket request = createSzlReassembledRequest(tpduId, sequenceNumber); - + context.sendRequest(request) - .onTimeout(e -> { - logger.warn("Timeout during Connection establishing, closing channel..."); - //context.getChannel().close(); - }) - .expectResponse(TPKTPacket.class, Duration.ofMillis(1000)) - .check(p -> p.getPayload() instanceof COTPPacketData) - .unwrap(p -> ((COTPPacketData) p.getPayload())) - .check(p -> p.getPayload() instanceof S7MessageUserData) - .unwrap(p -> ((S7MessageUserData) p.getPayload())) - .check(p -> p.getPayload() instanceof S7PayloadUserData) - .handle(future::complete); + .onTimeout(e -> { + logger.warn("Timeout during Connection establishing, closing channel..."); + //context.getChannel().close(); + }) + .expectResponse(TPKTPacket.class, Duration.ofMillis(1000)) + .check(p -> p.getPayload() instanceof COTPPacketData) + .unwrap(p -> ((COTPPacketData) p.getPayload())) + .check(p -> p.getPayload() instanceof S7MessageUserData) + .unwrap(p -> ((S7MessageUserData) p.getPayload())) + .check(p -> p.getPayload() instanceof S7PayloadUserData) + .handle(messageUserData -> { + future.complete(messageUserData); + }); return future; } - + /* - * - */ + * + */ private TPKTPacket createSzlReassembledRequest(int tpduId, short sequenceNumber) { S7MessageUserData identifyRemoteMessage = new S7MessageUserData(tpduId, new S7ParameterUserData(Arrays.asList( - new S7ParameterUserDataItemCPUFunctions((short) 0x12, (byte) 0x4, (byte) 0x4, (short) 0x01, sequenceNumber, (short) 0x00, (short) 0x00, 0) + new S7ParameterUserDataItemCPUFunctions((short) 0x12, (byte) 0x4, (byte) 0x4, (short) 0x01, sequenceNumber, (short) 0x00, (short) 0x00, 0) )), new S7PayloadUserData(Arrays.asList( - new S7PayloadUserDataItemCpuFunctionReadSzlNoDataRequest( - DataTransportErrorCode.NOT_FOUND, - DataTransportSize.NULL, - 0x00) + new S7PayloadUserDataItemCpuFunctionReadSzlNoDataRequest( + DataTransportErrorCode.NOT_FOUND, + DataTransportSize.NULL, + 0x00) ))); COTPPacketData cotpPacketData = new COTPPacketData(null, identifyRemoteMessage, true, (byte) 2); return new TPKTPacket(cotpPacketData); - } - - private CompletableFuture reassembledAlarmEvents(short sequenceNumber) { + } + + private CompletableFuture reassembledAlarmEvents(short sequenceNumber) { CompletableFuture future = new CompletableFuture<>(); - + //TODO: PDU id is the same, we need check. int tpduId = tpduGenerator.getAndIncrement(); // If we've reached the max value for a 16 bit transaction identifier, reset back to 1 - tpduGenerator.compareAndExchange(0xFFFF, 1); - + if(tpduGenerator.get() == 0xFFFF) { + tpduGenerator.set(1); + } + TPKTPacket request = createAlarmQueryReassembledRequest(tpduId, sequenceNumber); context.sendRequest(request) - .onTimeout(e -> { - logger.warn("Timeout during Connection establishing, closing channel..."); - //context.getChannel().close(); - }) - .expectResponse(TPKTPacket.class, Duration.ofMillis(1000)) - .check(p -> p.getPayload() instanceof COTPPacketData) - .unwrap(p -> ((COTPPacketData) p.getPayload())) - .check(p -> p.getPayload() instanceof S7MessageUserData) - .unwrap(p -> ((S7MessageUserData) p.getPayload())) - .check(p -> p.getPayload() instanceof S7PayloadUserData) - .handle(future::complete); + .onTimeout(e -> { + logger.warn("Timeout during Connection establishing, closing channel..."); + //context.getChannel().close(); + }) + .expectResponse(TPKTPacket.class, Duration.ofMillis(1000)) + .check(p -> p.getPayload() instanceof COTPPacketData) + .unwrap(p -> ((COTPPacketData) p.getPayload())) + .check(p -> p.getPayload() instanceof S7MessageUserData) + .unwrap(p -> ((S7MessageUserData) p.getPayload())) + .check(p -> p.getPayload() instanceof S7PayloadUserData) + .handle(messageUserData -> { + future.complete(messageUserData); + }); - return future; + return future; } //TODO: S7PayloadUserDataItemCpuFunctionReadSzlNoDataRequest to S7PayloadUserDataItemCpuFunctionAlarmQueryNoDataRequest private TPKTPacket createAlarmQueryReassembledRequest(int tpduId, short sequenceNumber) { S7MessageUserData identifyRemoteMessage = new S7MessageUserData(tpduId, new S7ParameterUserData(Arrays.asList( - new S7ParameterUserDataItemCPUFunctions((short) 0x12, (byte) 0x4, (byte) 0x4, (short) 0x13, sequenceNumber, (short) 0x00, (short) 0x00, 0) + new S7ParameterUserDataItemCPUFunctions((short) 0x12, (byte) 0x4, (byte) 0x4, (short) 0x13, sequenceNumber, (short) 0x00, (short) 0x00, 0) )), new S7PayloadUserData(Arrays.asList( - new S7PayloadUserDataItemCpuFunctionReadSzlNoDataRequest( - DataTransportErrorCode.NOT_FOUND, - DataTransportSize.NULL, - 0x00) - ))); + new S7PayloadUserDataItemCpuFunctionReadSzlNoDataRequest ( + DataTransportErrorCode.NOT_FOUND, + DataTransportSize.NULL, + 0x00) + ))); COTPPacketData cotpPacketData = new COTPPacketData(null, identifyRemoteMessage, true, (byte) 2); return new TPKTPacket(cotpPacketData); - } - - + } + + + /** * A generic purpose error handler which terminates transaction and calls back given future with error message. */ @@ -1843,13 +2198,21 @@ static class TransactionErrorCallback implements Consume @Override public void accept(TimeoutException e) { - transaction.endRequest(); + try { + transaction.endRequest(); + } catch (Exception ex) { + logger.info(ex.getMessage()); + } future.completeExceptionally(e); } @Override public void accept(TPKTPacket tpktPacket, E e) { - transaction.endRequest(); + try { + transaction.endRequest(); + } catch (Exception ex) { + logger.info(ex.getMessage()); + } future.completeExceptionally(e); } } diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7AckTag.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7AckTag.java index f3569e2ed6a..ba077fa356e 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7AckTag.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7AckTag.java @@ -7,7 +7,7 @@ * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * - * https://www.apache.org/licenses/LICENSE-2.0 + * 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 @@ -18,61 +18,61 @@ */ package org.apache.plc4x.java.s7.readwrite.tag; -import org.apache.plc4x.java.api.model.PlcTag; - import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.plc4x.java.api.model.PlcTag; +import org.apache.plc4x.java.s7.readwrite.types.S7SubscriptionType; public class S7AckTag implements PlcTag { - - private static final Pattern EVENT_ALARM_ACK_PATTERN = + + private static final Pattern EVENT_ALARM_ACK_PATTERN = Pattern.compile("(^ACK:)(((?:,{0,1})(16#[0-9a-fA-F]{8})(;([0-9a-fA-F]{2})))+)"); - + private final ArrayList ackAlarmIds; - private final ArrayList ackAlarmSigs; - - public S7AckTag(ArrayList ackAlarmIds, ArrayList ackAlarmSigs) { + private final ArrayList ackAlarmSigs; + + public S7AckTag(ArrayList ackAlarmIds, ArrayList ackAlarmSigs){ this.ackAlarmIds = ackAlarmIds; this.ackAlarmSigs = ackAlarmSigs; - } - - + }; + + public ArrayList getAlarmIds() { return ackAlarmIds; } public ArrayList getAlarmSigs() { return ackAlarmSigs; - } - + } + public static boolean matches(String fieldString) { return EVENT_ALARM_ACK_PATTERN.matcher(fieldString).matches(); - } - + } + public static S7AckTag of(String fieldString) { //TODO: Actually only ALARM_S (SIG_1) Matcher matcher = EVENT_ALARM_ACK_PATTERN.matcher(fieldString); - if (matcher.matches()) { + if (matcher.matches()){ String[] arrIdAndSig; String EventIds = matcher.group(2); String[] arrStrEventId = EventIds.split(","); ArrayList arrAlarmIds = new ArrayList<>(); - ArrayList arrAlarmSigs = new ArrayList<>(); - for (String EventId : arrStrEventId) { + ArrayList arrAlarmSigs = new ArrayList<>(); + for (String EventId:arrStrEventId){ EventId = EventId.replaceAll("16#", ""); - arrIdAndSig = EventId.split(";"); + arrIdAndSig = EventId.split(";"); arrAlarmIds.add(Integer.parseInt(arrIdAndSig[0], 16)); - arrAlarmSigs.add(Integer.parseInt(arrIdAndSig[1], 16)); + arrAlarmSigs.add(Integer.parseInt(arrIdAndSig[1], 16)); } - return new S7AckTag(arrAlarmIds, arrAlarmSigs); - } else return null; - } + return new S7AckTag(arrAlarmIds, arrAlarmSigs); + } else return null; + }; @Override public String getAddressString() { throw new UnsupportedOperationException("Not supported yet."); } - - + + } diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7ClkTag.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7ClkTag.java new file mode 100644 index 00000000000..f54edf37260 --- /dev/null +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7ClkTag.java @@ -0,0 +1,99 @@ +/* + * 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 + * + * https://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.readwrite.tag; + +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; +import org.apache.plc4x.java.api.model.ArrayInfo; +import org.apache.plc4x.java.api.model.PlcTag; +import org.apache.plc4x.java.api.types.PlcValueType; +import org.apache.plc4x.java.s7.readwrite.DateAndTime; + +public class S7ClkTag implements PlcTag { + + private static final Pattern CLK_ADDRESS_PATTERN = + Pattern.compile("^CLK\\b"); + + private static final Pattern CLKF_ADDRESS_PATTERN = + Pattern.compile("^CLKF\\b"); + + private final String address; + private DateAndTime dat; + + public S7ClkTag(String address) { + this.address = address; + LocalDateTime ldt = LocalDateTime.now(); + this.dat = new DateAndTime( + ((short) (ldt.getYear() - 2000)), + (short) ldt.getMonthValue(), + (short) ldt.getDayOfMonth(), + (short) ldt.getHour(), + (short) ldt.getMinute(), + (short) ldt.getSecond(), + (short) TimeUnit.NANOSECONDS.toMillis(ldt.getNano()), + (byte) ldt.getDayOfWeek().plus(1).getValue() + ); + } + + @Override + public String getAddressString() { + return address; + } + + @Override + public PlcValueType getPlcValueType() { + return PlcValueType.DATE_AND_TIME; + } + + @Override + public List getArrayInfo() { + return Collections.emptyList(); + } + + public DateAndTime getDateAndTime() { + return this.dat; + } + + public void setDateAndTime(LocalDateTime ldt) { + this.dat = new DateAndTime( + ((short) (ldt.getYear() - 2000)), + (short) ldt.getMonthValue(), + (short) ldt.getDayOfMonth(), + (short) ldt.getHour(), + (short) ldt.getMinute(), + (short) ldt.getSecond(), + (short) TimeUnit.NANOSECONDS.toMillis(ldt.getNano()), + (byte) ldt.getDayOfWeek().plus(1).getValue() + ); + } + + public static boolean matches(String address) { + return CLK_ADDRESS_PATTERN.matcher(address).matches() || + CLKF_ADDRESS_PATTERN.matcher(address).matches(); + } + + public static S7ClkTag of(String address) { + return new S7ClkTag(address); + + } + +} diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7PlcTagHandler.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7PlcTagHandler.java index c42cdd48674..ca3c6ae7677 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7PlcTagHandler.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7PlcTagHandler.java @@ -31,9 +31,11 @@ public PlcTag parseTag(String tagAddress) { return S7Tag.of(tagAddress); } else if (S7SubscriptionTag.matches(tagAddress)){ return S7SubscriptionTag.of(tagAddress); - } else if (S7SzlTag.matches(tagAddress)){ + } else if (S7ClkTag.matches(tagAddress)){ + return S7ClkTag.of(tagAddress); + } else if (S7SzlTag.matches(tagAddress)){ return S7SzlTag.of(tagAddress); - } + } throw new PlcInvalidTagException(tagAddress); } diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7SubscriptionTag.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7SubscriptionTag.java index fef10087acc..c23e0c5013d 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7SubscriptionTag.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7SubscriptionTag.java @@ -58,13 +58,13 @@ public class S7SubscriptionTag implements PlcTag { //All fields index 9 private static final Pattern EVENT_SUBSCRIPTION_S7ANY_QUERY_PATTERN = - Pattern.compile("(^CYC(\\((?((B01SEC)|(B1SEC)|(B10SEC))):(?[1-99])\\)):)((,?(" + ADDRESS_PATTERN + ")|(" + DATA_BLOCK_ADDRESS_PATTERN + "))+)"); + Pattern.compile("(^CYC(\\((?((B01SEC)|(B1SEC)|(B10SEC))):(?[1-99])\\)):)(((?:,{0,1})((" + ADDRESS_PATTERN + ")|(" + DATA_BLOCK_ADDRESS_PATTERN + ")))+)"); private static final Pattern EVENT_SUBSCRIPTION_DB_QUERY_PATTERN = - Pattern.compile("(^CYC(\\((?((B01SEC)|(B1SEC)|(B10SEC))):(?[1-99])\\)):)((,?(%DB(?\\d{1,5}).DB(?B?)(?\\d{1,7})(\\[(?\\d+)]))?)+)"); + Pattern.compile("(^CYC(\\((?((B01SEC)|(B1SEC)|(B10SEC))):(?[1-99])\\)):)(((?:,{0,1})(%DB(?\\d{1,5}).DB(?[B]?)(?\\d{1,7})(\\[(?\\d+)]))?)+)"); private static final Pattern EVENT_CANCEL_JOB_QUERY_PATTERN = - Pattern.compile("(^CANCEL:)(,?(\\d{1,3}))+"); + Pattern.compile("(^CANCEL:)((((?:,{0,1})(\\d+{1,3})))+)"); private static final String MEMORY_AREA = "memoryArea"; private static final String TRANSFER_SIZE_CODE = "transferSizeCode"; diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/types/S7SubscriptionType.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/types/S7SubscriptionType.java index 6869b9f6064..2b3062af0bf 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/types/S7SubscriptionType.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/types/S7SubscriptionType.java @@ -25,5 +25,5 @@ public enum S7SubscriptionType { ALARM_QUERY, CYCLIC_SUBSCRIPTION, CYCLIC_DB_SUBSCRIPTION, - CYCLIC_UNSUBSCRIPTION + CYCLIC_UNSUBSCRIPTION; } diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/utils/S7PlcSubscriptionHandle.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/utils/S7PlcSubscriptionHandle.java index a209baf9ca4..d1fab5d82db 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/utils/S7PlcSubscriptionHandle.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/utils/S7PlcSubscriptionHandle.java @@ -24,15 +24,27 @@ public class S7PlcSubscriptionHandle extends DefaultPlcSubscriptionHandle { - private final EventType eventtype; + private EventType eventtype; + private final String id; public S7PlcSubscriptionHandle(EventType eventtype, PlcSubscriber plcSubscriber) { super(plcSubscriber); this.eventtype = eventtype; + this.id = null; } + public S7PlcSubscriptionHandle(String id, EventType eventtype, PlcSubscriber plcSubscriber) { + super(plcSubscriber); + this.eventtype = eventtype; + this.id = id; + } + public EventType getEventType() { return eventtype; } + public String getEventId() { + return id; + } + } diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/utils/StaticHelper.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/utils/StaticHelper.java index b4de5f24d14..aa294fde283 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/utils/StaticHelper.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/utils/StaticHelper.java @@ -37,7 +37,6 @@ import org.apache.plc4x.java.spi.generation.SerializationException; import org.apache.plc4x.java.spi.generation.WriteBuffer; -import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.time.Duration; @@ -641,7 +640,7 @@ private static StringBuilder ID_0xXY00(ByteBuf data) { } catch (Exception ex) { sb.append(ex); } - return sb.append(jsonszl); + return sb.append(jsonszl.toString()); } /* @@ -679,7 +678,7 @@ private static StringBuilder ID_0xXY11(ByteBuf data) { } catch (Exception ex) { sb.append(ex); } - return sb.append(jsonszl); + return sb.append(jsonszl.toString()); } /* @@ -714,7 +713,7 @@ private static StringBuilder ID_0xXY12(ByteBuf data) { } catch (Exception ex) { sb.append(ex); } - return sb.append(jsonszl); + return sb.append(jsonszl.toString()); } /* @@ -760,7 +759,7 @@ private static StringBuilder ID_0xXY13(ByteBuf data) { sb.append(ex); } - sb.append(jsonszl); + sb.append(jsonszl.toString()); return sb; } @@ -804,7 +803,7 @@ private static StringBuilder ID_0xXY14(ByteBuf data) { sb.append(ex); } - sb.append(jsonszl); + sb.append(jsonszl.toString()); return sb; } @@ -844,7 +843,7 @@ private static StringBuilder ID_0xXY15(ByteBuf data) { sb.append(ex); } - sb.append(jsonszl); + sb.append(jsonszl.toString()); return sb; } @@ -993,7 +992,7 @@ private static StringBuilder ID_0xXY1C(ByteBuf data) { sb.append(ex); } - sb.append(jsonszl); + sb.append(jsonszl.toString()); return sb; } @@ -1033,7 +1032,7 @@ private static StringBuilder ID_0xXY22(ByteBuf data) { sb.append(ex); } - sb.append(jsonszl); + sb.append(jsonszl.toString()); return sb; @@ -1073,7 +1072,7 @@ private static StringBuilder ID_0xXY25(ByteBuf data) { sb.append(ex); } - sb.append(jsonszl); + sb.append(jsonszl.toString()); return sb; } @@ -1113,7 +1112,7 @@ private static StringBuilder ID_0xXY32(ByteBuf data) { sb.append(ex); } - sb.append(jsonszl); + sb.append(jsonszl.toString()); return sb; } @@ -1162,7 +1161,7 @@ private static StringBuilder ID_0xXY71(ByteBuf data) { sb.append(ex); } - sb.append(jsonszl); + sb.append(jsonszl.toString()); return sb; } @@ -1203,7 +1202,7 @@ private static StringBuilder ID_0xXY74(ByteBuf data) { sb.append(ex); } - sb.append(jsonszl); + sb.append(jsonszl.toString()); return sb; } @@ -1247,7 +1246,7 @@ private static StringBuilder ID_0xXY75(ByteBuf data) { sb.append(ex); } - sb.append(jsonszl); + sb.append(jsonszl.toString()); return sb; } @@ -1296,7 +1295,7 @@ private static StringBuilder ID_0xXY90(ByteBuf data) { sb.append(ex); } - sb.append(jsonszl); + sb.append(jsonszl.toString()); return sb; } @@ -1343,7 +1342,7 @@ private static StringBuilder ID_0xXY91(ByteBuf data) { sb.append(ex); } - sb.append(jsonszl); + sb.append(jsonszl.toString()); return sb; } @@ -1398,7 +1397,7 @@ private static StringBuilder ID_0xXY92(ByteBuf data) { sb.append(ex); } - sb.append(jsonszl); + sb.append(jsonszl.toString()); return sb; } @@ -1441,7 +1440,7 @@ private static StringBuilder ID_0xXY94(ByteBuf data) { sb.append(ex); } - sb.append(jsonszl); + sb.append(jsonszl.toString()); return sb; } @@ -1496,7 +1495,7 @@ private static StringBuilder ID_0xXY95(ByteBuf data) { sb.append(ex); } - sb.append(jsonszl); + sb.append(jsonszl.toString()); return sb; } @@ -1550,7 +1549,7 @@ private static StringBuilder ID_0xXY96(ByteBuf data) { sb.append(ex); } - sb.append(jsonszl); + sb.append(jsonszl.toString()); return sb; } @@ -1595,7 +1594,7 @@ private static StringBuilder ID_0xXY9C(ByteBuf data) { sb.append(ex); } - sb.append(jsonszl); + sb.append(jsonszl.toString()); return sb; } @@ -1665,7 +1664,7 @@ private static StringBuilder ID_0xXYA0(ByteBuf data) { sb.append(ex); } - sb.append(jsonszl); + sb.append(jsonszl.toString()); return sb; } @@ -1708,7 +1707,7 @@ private static StringBuilder ID_0xXYB1(ByteBuf data) { sb.append(ex); } - sb.append(jsonszl); + sb.append(jsonszl.toString()); return sb; } @@ -1748,7 +1747,7 @@ private static StringBuilder ID_0xXYB2(ByteBuf data) { sb.append(ex); } - sb.append(jsonszl); + sb.append(jsonszl.toString()); return sb; } @@ -1787,7 +1786,7 @@ private static StringBuilder ID_0xXYB3(ByteBuf data) { sb.append(ex); } - sb.append(jsonszl); + sb.append(jsonszl.toString()); return sb; } @@ -1832,7 +1831,7 @@ private static StringBuilder ID_0xXYB4(ByteBuf data) { sb.append(ex); } - sb.append(jsonszl); + sb.append(jsonszl.toString()); return sb; } @@ -2065,13 +2064,13 @@ public static byte[] LocalDateTimeToS7DateTime(LocalDateTime data) { res[4] = ByteToBcd(data.getMinute()); res[5] = ByteToBcd(data.getSecond()); - long ms = data.getNano() / 1_000_000; + 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) | dayofweek); + res[7] = (byte) (((ms % 10) << 4) | ((byte) (dayofweek))); return res; } @@ -2139,7 +2138,8 @@ public static int RightShift3(final ReadBuffer buffer) throws ParseException { public static int RightShift3(final ReadBuffer buffer, DataTransportSize tsize) throws ParseException { int value = 0; - if (tsize == DataTransportSize.OCTET_STRING){ + if ((tsize == DataTransportSize.OCTET_STRING) || + (tsize == DataTransportSize.REAL)) { value = buffer.readUnsignedInt(16); } else { value = buffer.readUnsignedInt(16) >> 3; @@ -2177,7 +2177,7 @@ public static PlcResponseCode decodeResponseCode(DataTransportErrorCode dataTran private static byte[] wordToBytes(long data) { return new byte[]{ (byte) ((data >> 8) & 0xff), - (byte) ((data) & 0xff), + (byte) ((data >> 0) & 0xff), }; } @@ -2186,7 +2186,7 @@ private static byte[] dwordToBytes(long data) { (byte) ((data >> 24) & 0xff), (byte) ((data >> 16) & 0xff), (byte) ((data >> 8) & 0xff), - (byte) ((data) & 0xff), + (byte) ((data >> 0) & 0xff), }; } @@ -2240,6 +2240,7 @@ public static String SysEventProcessing(final S7SysEvent event, String eventtext if (bytebuf.capacity() < Byte.BYTES) break; strField = String.valueOf(bytebuf.getBoolean(0)); strOut = strOut.replaceAll(matcher.group(0), strField); + ; break; case "Y": if (bytebuf.capacity() < Byte.BYTES) break; @@ -2258,6 +2259,7 @@ public static String SysEventProcessing(final S7SysEvent event, String eventtext strField = String.format(format, value); } strOut = strOut.replaceAll(matcher.group(0), strField); + ; break; case "C": if (format.contains("%T#")) { @@ -2269,10 +2271,11 @@ public static String SysEventProcessing(final S7SysEvent event, String eventtext length = Integer.parseInt(fieldformat.group(1)); length = (length > bytebuf.capacity()) ? bytebuf.capacity() : length; strField = - bytebuf.readCharSequence(length, StandardCharsets.UTF_8).toString(); + bytebuf.readCharSequence(length, Charset.forName("utf-8")).toString(); } } strOut = strOut.replaceAll(matcher.group(0), strField); + ; break; case "W": if (bytebuf.capacity() < Short.BYTES) break; @@ -2291,6 +2294,7 @@ public static String SysEventProcessing(final S7SysEvent event, String eventtext strField = String.format(format, value); } strOut = strOut.replaceAll(matcher.group(0), strField); + ; break; case "I": if (bytebuf.capacity() < Integer.BYTES) break; @@ -2352,6 +2356,7 @@ public static String SysEventProcessing(final S7SysEvent event, String eventtext strField = String.format(format, value); strOut = strOut.replaceAll(matcher.group(0), strField); } + ; break; } } @@ -2419,7 +2424,7 @@ public static String AlarmProcessing(final S7AlarmEvent alarm, String alarmText, int length = 0; int sig = 0; long value = 0; - String strOut = alarmText; + String strOut = new String(alarmText); String strField = null; while (matcher.find()) { @@ -2436,6 +2441,7 @@ public static String AlarmProcessing(final S7AlarmEvent alarm, String alarmText, if (bytebuf.capacity() < Byte.BYTES) break; strField = String.valueOf(bytebuf.getBoolean(0)); strOut = strOut.replaceAll(matcher.group(0), strField); + ; break; case "Y": if (bytebuf.capacity() < Byte.BYTES) break; @@ -2454,6 +2460,7 @@ public static String AlarmProcessing(final S7AlarmEvent alarm, String alarmText, strField = String.format(format, value); } strOut = strOut.replaceAll(matcher.group(0), strField); + ; break; case "C": if (format.contains("%T#")) { @@ -2465,10 +2472,11 @@ public static String AlarmProcessing(final S7AlarmEvent alarm, String alarmText, length = Integer.parseInt(fieldformat.group(1)); length = (length > bytebuf.capacity()) ? bytebuf.capacity() : length; strField = - bytebuf.readCharSequence(length, StandardCharsets.UTF_8).toString(); + bytebuf.readCharSequence(length, Charset.forName("utf-8")).toString(); } } strOut = strOut.replaceAll(matcher.group(0), strField); + ; break; case "W": if (bytebuf.capacity() < Short.BYTES) break; @@ -2487,6 +2495,7 @@ public static String AlarmProcessing(final S7AlarmEvent alarm, String alarmText, strField = String.format(format, value); } strOut = strOut.replaceAll(matcher.group(0), strField); + ; break; case "I": if (bytebuf.capacity() < Integer.BYTES) break; @@ -2504,7 +2513,9 @@ public static String AlarmProcessing(final S7AlarmEvent alarm, String alarmText, value = bytebuf.getInt(0); strField = String.format(format, value); } + ; strOut = strOut.replaceAll(matcher.group(0), strField); + ; break; case "X": if (bytebuf.capacity() < Long.BYTES) break; @@ -2522,7 +2533,9 @@ public static String AlarmProcessing(final S7AlarmEvent alarm, String alarmText, value = bytebuf.getLong(0); strField = String.format(format, value); } + ; strOut = strOut.replaceAll(matcher.group(0), strField); + ; break; case "D": if (bytebuf.capacity() < Double.BYTES) break; @@ -2540,7 +2553,9 @@ public static String AlarmProcessing(final S7AlarmEvent alarm, String alarmText, value = bytebuf.getLong(0); strField = String.format(format, value); } + ; strOut = strOut.replaceAll(matcher.group(0), strField); + ; break; case "R": if (bytebuf.capacity() < Float.BYTES) break; @@ -2548,6 +2563,7 @@ public static String AlarmProcessing(final S7AlarmEvent alarm, String alarmText, strField = String.format(format, value); strOut = strOut.replaceAll(matcher.group(0), strField); } + ; break; } @@ -2746,46 +2762,23 @@ public static void serializeS7Char(WriteBuffer io, PlcValue value, String encodi * If your application does not handle S7string, you can handle * the String as char arrays from your application. */ - public static void serializeS7String(WriteBuffer io, PlcValue value, int stringLength, String encoding) throws SerializationException { + public static void serializeS7String(WriteBuffer io, PlcValue value, int stringLength, String encoding) { int k = 0xFF & ((stringLength > 250) ? 250 : stringLength); int m = 0xFF & value.getString().length(); m = (m > k) ? k : m; - byte[] chars; - if("UTF-8".equals(encoding)) { - chars = new byte[k]; - for (int i = 0; i < m; ++i) { - char c = value.getString().charAt(i); - chars[i] = (byte) c; - } - try { - io.writeByte((byte)(k & 0xFF)); - io.writeByte((byte)(m & 0xFF)); - io.writeByteArray(chars); - } catch (SerializationException ex) { - Logger.getLogger(StaticHelper.class.getName()).log(Level.SEVERE, null, ex); - } - } else if ("UTF-16".equals(encoding)) { - chars = new byte[k*2]; - try { - byte[] rawBytes = value.getString().getBytes("UTF-16"); - for (int i = 0; i < m * 2; ++i) { - // For some reason the first two bytes are "-2" and "-1". - chars[i] = rawBytes[i + 2]; - } - } catch (UnsupportedEncodingException e) { - throw new SerializationException("Unsupported string encoding '%s'" + encoding, e); - } - try { - io.writeUnsignedInt(16, (short)(k & 0xFFFF)); - io.writeUnsignedInt(16, (short)(m & 0xFFFF)); - io.writeByteArray(chars); - } catch (SerializationException ex) { - Logger.getLogger(StaticHelper.class.getName()).log(Level.SEVERE, null, ex); - } - } else { - throw new SerializationException("Unsupported string encoding '%s'" + encoding); + byte[] chars = new byte[m]; + for (int i = 0; i < m; ++i) { + char c = value.getString().charAt(i); + chars[i] = (byte) c; } + try { + io.writeByte((byte)(k & 0xFF)); + io.writeByte((byte)(m & 0xFF)); + io.writeByteArray(chars); + } catch (SerializationException ex) { + Logger.getLogger(StaticHelper.class.getName()).log(Level.SEVERE, null, ex); + } } } diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7DiagnosticEventId.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7DiagnosticEventId.java index af12f818b85..ae7fef3d10b 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7DiagnosticEventId.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/utils/S7DiagnosticEventId.java @@ -667,7 +667,8 @@ public short getCode() { } public static S7DiagnosticEventId valueOf(short code) { - int intcode = Short.toUnsignedInt(code); + + Integer intcode = Short.toUnsignedInt(code); int a = code & 0xA000; int b = code & 0xB000; if ((a != 0) || (b != 0)) intcode = 0x0000; diff --git a/plc4j/drivers/s7/src/test/java/org/apache/plc4x/java/s7/readwrite/ManualS7DriverTest.java b/plc4j/drivers/s7/src/test/java/org/apache/plc4x/java/s7/readwrite/ManualS7DriverTest.java index 71ff6197a15..5632798e977 100644 --- a/plc4j/drivers/s7/src/test/java/org/apache/plc4x/java/s7/readwrite/ManualS7DriverTest.java +++ b/plc4j/drivers/s7/src/test/java/org/apache/plc4x/java/s7/readwrite/ManualS7DriverTest.java @@ -23,7 +23,6 @@ import java.time.LocalDate; import java.time.LocalTime; -import java.time.format.DateTimeFormatter; public class ManualS7DriverTest extends ManualTest { @@ -67,7 +66,7 @@ public class ManualS7DriverTest extends ManualTest { */ public ManualS7DriverTest(String connectionString) { - super(connectionString, true); + super(connectionString); } public static void main(String[] args) throws Exception { @@ -89,7 +88,7 @@ public static void main(String[] args) throws Exception { test.addTestCase("%DB4:46:REAL", new PlcREAL(3.141593F)); // Not supported in S7 1200 //test.addTestCase("%DB4:50:LREAL", new PlcLREAL(2.71828182846D)); -// test.addTestCase("%DB4:58:TIME", "PT1.234S"); + test.addTestCase("%DB4:58:TIME", "PT1.234S"); test.addTestCase("%DB4:136:CHAR", new PlcCHAR("H")); test.addTestCase("%DB4:138:WCHAR", new PlcWCHAR("w")); test.addTestCase("%DB4:140:STRING(10)", new PlcSTRING("hurz")); @@ -98,8 +97,8 @@ public static void main(String[] args) throws Exception { // Not supported in S7 1200 //test.addTestCase("%DB4:62:LTIME", new PlcLTIME(Duration.parse("PT24015H23M12.034002044S")); test.addTestCase("%DB4:70:DATE", new PlcDATE(LocalDate.parse("1998-03-28"))); - test.addTestCase("%DB4:72:TIME_OF_DAY", new PlcTIME_OF_DAY(LocalTime.parse("15:36:30.123", DateTimeFormatter.ofPattern("HH:mm:ss.SSS")))); - //test.addTestCase("%DB4:76:TOD", new PlcTIME_OF_DAY(LocalTime.parse("16:17:18.123"))); + test.addTestCase("%DB4:72:TIME_OF_DAY", new PlcTIME_OF_DAY(LocalTime.parse("15:36:30.123"))); + test.addTestCase("%DB4:76:TOD", new PlcTIME_OF_DAY(LocalTime.parse("16:17:18.123"))); // Not supported in S7 1200 //test.addTestCase("%DB4:96:DATE_AND_TIME", new PlcDATE_AND_TIME(LocalDateTime.parse("1996-05-06T15:36:30"))); // Not supported in S7 1200 @@ -111,8 +110,4 @@ public static void main(String[] args) throws Exception { test.run(); } - static void testRead() { - - } - } diff --git a/plc4j/examples/plc4j-s7event/pom.xml b/plc4j/examples/plc4j-s7event/pom.xml index 23b85866b32..142437385af 100644 --- a/plc4j/examples/plc4j-s7event/pom.xml +++ b/plc4j/examples/plc4j-s7event/pom.xml @@ -40,6 +40,11 @@ org.apache.maven.plugins maven-dependency-plugin + + + org.slf4j:slf4j-simple + + @@ -81,5 +86,15 @@ commons-lang3 ${commons-lang3.version} + + org.slf4j + slf4j-simple + ${slf4j.version} + + + io.netty + netty-common + ${netty.version} + \ No newline at end of file diff --git a/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/CycSubscription.java b/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/CycSubscription.java deleted file mode 100644 index 36082fc6b33..00000000000 --- a/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/CycSubscription.java +++ /dev/null @@ -1,120 +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 - * - * https://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.examples.plc4j.s7event; - -import org.apache.commons.codec.binary.Hex; -import org.apache.plc4x.java.DefaultPlcDriverManager; -import org.apache.plc4x.java.api.PlcConnection; -import org.apache.plc4x.java.api.messages.PlcSubscriptionRequest; -import org.apache.plc4x.java.api.messages.PlcSubscriptionResponse; -import org.apache.plc4x.java.s7.events.S7CyclicEvent; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Map; - - -/** - * Example for capturing events generated from a Siemens S7-300, S7-400 or VIPA PLC. - * Support for mode events ("MODE"), system events ("SYS"), user events ("USR") - * and alarms ("ALM"). - * Each consumer shows the tags and associated values of the "map" containing - * the event parameters. - */ -public class CycSubscription { - - private static final Logger logger = LoggerFactory.getLogger(CycSubscription.class); - - /** - * @param args the command line arguments - */ - public static void main(String[] args) throws Exception { - - try (PlcConnection connection = new DefaultPlcDriverManager().getConnection("s7://10.10.1.33?remote-rack=0&remote-slot=3&controller-type=S7_400")) { - final PlcSubscriptionRequest.Builder subscription = connection.subscriptionRequestBuilder(); - - //subscription.addEventTagAddress("myCYC", "CYC(B01SEC:5):%DB9002.DBB0[1]"); - subscription.addEventTagAddress("myCYC", "CYC(B01SEC:5):%MB190:BYTE"); - - final PlcSubscriptionRequest sub = subscription.build(); - final PlcSubscriptionResponse subresponse = sub.execute().get(); - - //Si todo va bien con la subscripción puedo -// subresponse -// .getSubscriptionHandle("myMODE") -// .register(msg -> { -// System.out.println("******** S7ModeEvent ********"); -// Map map = ((S7ModeEvent) msg).getMap(); -// map.forEach((x, y) -> { -// System.out.println(x + " : " + y); -// }); -// System.out.println("****************************"); -// }); -// -// subresponse -// .getSubscriptionHandle("mySYS") -// .register(msg -> { -// System.out.println("******** S7SysEvent ********"); -// Map map = ((S7SysEvent) msg).getMap(); -// map.forEach((x, y) -> { -// if ("INFO1".equals(x)) { -// System.out.println(x + " : " + String.format("0x%04X", y)); -// } else if ("INFO2".equals(x)) { -// System.out.println(x + " : " + String.format("0x%08X", y)); -// } else System.out.println(x + " : " + y); -// }); -// System.out.println("****************************"); -// }); -// -// subresponse -// .getSubscriptionHandle("myUSR") -// .register(msg -> { -// System.out.println("******** S7UserEvent *******"); -// Map map = ((S7UserEvent) msg).getMap(); -// map.forEach((x, y) -> { -// System.out.println(x + " : " + y); -// }); -// System.out.println("****************************"); -// }); - - subresponse - .getSubscriptionHandle("myCYC") - .register(msg -> { - System.out.println("******** CYC Event *********"); - Map map = ((S7CyclicEvent) msg).getMap(); - map.forEach((x, y) -> { - if (x.startsWith("DATA_", 0)) { - System.out.println("Longitud de datos: " + ((byte[]) y).length); - System.out.println(x + ": " + Hex.encodeHexString((byte[]) y)); - } else - System.out.println(x + " : " + y); - }); - System.out.println("****************************"); - }); - - System.out.println("Waiting for events"); - - Thread.sleep(10000); - - System.out.println("Bye..."); - - } - } - -} diff --git a/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PLcSetAndGetRtClock.java b/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PLcSetAndGetRtClock.java new file mode 100644 index 00000000000..b2acc3c138f --- /dev/null +++ b/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PLcSetAndGetRtClock.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 + * + * https://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.examples.plc4j.s7event; + +public class PLcSetAndGetRtClock { + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + // TODO code application logic here + } + +} diff --git a/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcCycSubscriptionS7400H.java b/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcCycSubscriptionS7400H.java new file mode 100644 index 00000000000..aeb030534c3 --- /dev/null +++ b/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcCycSubscriptionS7400H.java @@ -0,0 +1,351 @@ +/* + * 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 + * + * https://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.examples.plc4j.s7event; + +import io.netty.util.concurrent.DefaultThreadFactory; +import org.apache.commons.codec.binary.Hex; +import org.apache.plc4x.java.DefaultPlcDriverManager; +import org.apache.plc4x.java.api.messages.PlcSubscriptionRequest; +import org.apache.plc4x.java.api.messages.PlcUnsubscriptionRequest; +import org.apache.plc4x.java.api.messages.PlcSubscriptionResponse; +import org.apache.plc4x.java.s7.events.S7CyclicEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicBoolean; +import org.apache.commons.lang3.time.StopWatch; +import org.apache.plc4x.java.api.exceptions.PlcConnectionException; +import org.apache.plc4x.java.api.listener.ConnectionStateListener; +import org.apache.plc4x.java.s7.readwrite.protocol.S7HPlcConnection; + + +/** + * Cyclic subscription allows the acquisition of data from + * the controller in push mode, the PLC is responsible for sending + * the data to the client application. The minimum time base is 100 msec. + * The data is sent as a stream of bytes so the client must + * maintain its consistency.This is the working mode of WinCC Scada. + * The connection is supervised. + * Plc: SIMATIC S7-400 + * Model: CPU 417 + * Part number: 6ES7 417-4XT05-0AB0 + * Firmware version: 5.1.0 + * CP1: 6GK7 443-1EX11-0XE0 + * CP2: 6GK7 443-1EX20-0XB0 +*/ +public class PlcCycSubscriptionS7400H implements ConnectionStateListener { + + private static final Logger logger = LoggerFactory.getLogger(PlcCycSubscriptionS7400H.class); + + private S7HPlcConnection connection = null; + private AtomicBoolean isConnected = new AtomicBoolean(false); + private AtomicBoolean ShutDown = new AtomicBoolean(false); + private final DefaultThreadFactory dtf = new DefaultThreadFactory("CYC", true); + /** + * @param args the command line arguments + */ + public static void main(String[] args) throws Exception { + + System.setProperty(org.slf4j.simple.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "Info"); + + PlcCycSubscriptionS7400H device = new PlcCycSubscriptionS7400H(); + device.run(args); + } + + public void run (String[] args) throws Exception { + + logger.info("*****************************************************"); + logger.info("* Example of connection and read to a Simatic S7-400H"); + logger.info("* Plc: SIMATIC S7-400"); + logger.info("* Model: CPU 417"); + logger.info("* Part number: 6ES7 417-4XT05-0AB0"); + logger.info("* Firmware version: 5.1.0"); + logger.info("* CP1: 6GK7 443-1EX11-0XE0"); + logger.info("* CP2: 6GK7 443-1EX20-0XB0"); + logger.info("*"); + logger.info("* Note: . "); + logger.info("* . "); + logger.info("*****************************************************"); + + + + logger.info("*****************************************************"); + logger.info("* 1. Once the connection is executed, it must "); + logger.info("* suscrict the data contained in the address."); + logger.info("* URL to:s7://10.10.1.80/10.10.1.81?remote-rack=0&"); + logger.info(" remote-slot=3&remote-rack2=0&remote-slot=4&"); + logger.info(" controller-type=S7_400&read-timeout=8&"); + logger.info(" ping=true&ping-time=2&retry-time=3"); + logger.info("* Press [ENTER]"); + logger.info("*****************************************************"); + System.in.read(); + + OpenConnection("s7://10.10.1.80/10.10.1.81?remote-rack=0&" + + "remote-slot=3&remote-rack2=0&remote-slot=4&" + + "controller-type=S7_400&read-timeout=8&" + + "ping=true&ping-time=2&retry-time=3"); //(01) + + logger.info("*****************************************************"); + logger.info("* 2. In this step subscriptions are launched."); + logger.info(" In the specific case of the S7-400,"); + logger.info("* you can have up to 32 simultaneous subscriptions."); + logger.info("* You must be able to read the value from the PLC."); + logger.info("* Press [ENTER]"); + logger.info("*****************************************************"); + System.in.read(); + + MakeSubscription(); //(02) + + logger.info("*****************************************************"); + logger.info("* 3. Subscriptions are removed."); + logger.info("* Depending on how you handle your tasks, "); + logger.info("* you should ensure that they are all completed."); + logger.info("* Press [ENTER]"); + logger.info("*****************************************************"); + System.in.read(); + + MakeUnsubscription(); //(03) + + logger.info("*****************************************************"); + logger.info("* 4. We close the connection and release resources."); + logger.info("* Press [ENTER]"); + logger.info("*****************************************************"); + System.in.read(); + + CloseConnection(); //(04) + + } + + /*************************************************************************** + * Under normal conditions, the driver expects you to have the PLC + * connected to the network to start operations. + * If a connection to the PLC cannot be established, an exception of type + * "PlcConnectionException" is generated, which must be handled by your + * application. In this example it waits for a connection to exist. + * When you disconnect the "connection", the S7 driver will take care of the + * connection and reconnection process if necessary. + * The internal wait time for the connection is one (01) second. + ***************************************************************************/ + private void OpenConnection(String url) { + int retrys = 0; + StopWatch watch = new StopWatch(); + watch.start(); + while (null == connection) { + try { + connection =(S7HPlcConnection) new DefaultPlcDriverManager(). + getConnection(url); + connection.addEventListener(this); + while (!connection.isConnected()); + watch.stop(); + + isConnected.set( connection.isConnected()); + + logger.info("Time elapse for connection: {} in ms, with " + + "rettrys: {}",watch.getTime(), retrys); + + } catch (PlcConnectionException ex) { + logger.info(ex.getMessage()); + retrys++; + } + } + } + + /*************************************************************************** + * When the connection is closed, pending tasks and transactions are + * completed. + * The rest of the work should be sent to the GC. + ***************************************************************************/ + private void CloseConnection() { + if (null == connection) return; + isConnected.set(false); + try { + connection.close(); + connection = null; //GC do you job!. + + } catch (PlcConnectionException ex) { + logger.info("CloseConnection: " + ex.getMessage()); + } + } + + /*************************************************************************** + * This method is called when there is a physical disconnection of the driver + * Check the monitoring parameters given in the URL during connection. + ***************************************************************************/ + public void MakeSubscription() throws Exception { + + Thread th01 = null; + + for (int i=1; i<=1; i++) { + + th01 = dtf.newThread(new SubscriptionRunnable(connection, i)); + + th01.start(); + + } + + } + + /*************************************************************************** + * Depending on your design, you must close all subscribers + * in an orderly manner. + ***************************************************************************/ + public void MakeUnsubscription() throws Exception { + logger.info("Finish all subscriptions."); + ShutDown.set(true); + } + + /*************************************************************************** + * This method is called when the driver makes an internal TCP connection. + * The first connection of the driver does not generate this event. + * In the case of high availability systems, this signal should be used + * to restart subscriptions to events, alarms, etc. + ***************************************************************************/ + @Override + public void connected() { + logger.info("*****************************************************"); + logger.info("*************** Plc is connected. *******************"); + logger.info("*****************************************************"); + isConnected.set(true); + } + + /*************************************************************************** + * This method is called when there is a physical disconnection of the driver + * Check the monitoring parameters given in the URL during connection. + ***************************************************************************/ + @Override + public void disconnected() { + logger.info("*****************************************************"); + logger.info("*************** Plc is disconnected. ****************"); + logger.info("*****************************************************"); + isConnected.set(false); + } + + /*************************************************************************** + * This object encapsulates the three steps required for cyclic subscription. + * Try to handle all possible exceptions that are generated. + ***************************************************************************/ + private class SubscriptionRunnable implements Runnable { + private final Logger logger = LoggerFactory.getLogger(SubscriptionRunnable.class); + + private final S7HPlcConnection myconnection; + private final int instance; + private PlcSubscriptionRequest.Builder subscription; + private PlcSubscriptionRequest sub; + private PlcSubscriptionResponse subresponse; + + public SubscriptionRunnable(S7HPlcConnection connection, int instance) { + this.myconnection = connection; + this.instance = instance; + } + + @Override + public void run() { + + MakeMySubscription(); + + MakeMyRegister(); + + while (!ShutDown.get()) { + try { + Thread.sleep(100); + } catch (Exception ex) { + logger.debug(ex.getMessage()); + } + } ; + + MakeMyUnsubscription(); + + logger.info("Bye!"); + } + + /*********************************************************************** + * Registration of the different memory areas. + * Only the first request sets the time period for the entire group. + * The time bases are for the multiplier: + * + * . B01SEC: Time base 0.1 Sec. (100 mSec.). + * . B1SEC: Time base 1.0 Sec. + * . B10SEC: Time base 10 Sec. + ***********************************************************************/ + private void MakeMySubscription() { + subscription = myconnection.subscriptionRequestBuilder(); + subscription.addEventTagAddress(instance + "_myCYC_01", "CYC(B1SEC:5):%MB190:BYTE"); + subscription.addEventTagAddress(instance + "_myCYC_02", "CYC(B1SEC:5):%MW190:INT"); + + sub = subscription.build(); + + try { + subresponse = sub.execute().get(); + } catch (InterruptedException ex) { + logger.info(ex.getMessage()); + } catch (ExecutionException ex) { + logger.info(ex.getMessage()); + } + } + + /*********************************************************************** + * This object encapsulates the three steps required for cyclic subscription. + * Try to handle all possible exceptions that are generated. + ***********************************************************************/ + private void MakeMyRegister() { + + subresponse + .getSubscriptionHandle(instance + "_myCYC_01") + .register(msg -> { + if (null == msg) return + ; + logger.info("******** {} CYC Event *********", instance); + Map map = ((S7CyclicEvent) msg).getMap(); + map.forEach((x, y) -> { + if (x.startsWith("DATA_", 0)) { + logger.info("Longitud de datos: " + ((byte[]) y).length); + logger.info(x + ": " + Hex.encodeHexString((byte[]) y)); + } else + logger.info(x + " : " + y); + }); + logger.info("****************************"); + });; + } + + /*********************************************************************** + * This object encapsulates the three steps required for cyclic subscription. + * Try to handle all possible exceptions that are generated. + ***********************************************************************/ + private void MakeMyUnsubscription(){ + final PlcUnsubscriptionRequest.Builder unsubscription = myconnection.unsubscriptionRequestBuilder(); + + unsubscription.addHandles(subresponse.getSubscriptionHandle(instance + "_myCYC_01")); + + final PlcUnsubscriptionRequest res = unsubscription.build(); + + try { + res.execute().get(); + } catch (InterruptedException ex) { + logger.info(ex.getMessage()); + } catch (ExecutionException ex) { + logger.info(ex.getMessage()); + } + } + + } + + +} diff --git a/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/EventSubscription.java b/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcEventSubscriptionS7400H.java similarity index 94% rename from plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/EventSubscription.java rename to plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcEventSubscriptionS7400H.java index 1510634d914..b817e3a1e5f 100644 --- a/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/EventSubscription.java +++ b/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcEventSubscriptionS7400H.java @@ -35,15 +35,18 @@ * Each consumer shows the tags and associated values of the "map" containing * the event parameters. */ -public class EventSubscription { +public class PlcEventSubscriptionS7400H { - private static final Logger logger = LoggerFactory.getLogger(EventSubscription.class); + private static final Logger logger = LoggerFactory.getLogger(PlcEventSubscriptionS7400H.class); /** * @param args the command line arguments */ public static void main(String[] args) throws Exception { - try (PlcConnection connection = new DefaultPlcDriverManager().getConnection("s7://10.10.1.33?remote-rack=0&remote-slot=3&controller-type=S7_400")) { + + System.setProperty(org.slf4j.simple.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "Debug"); + + try (PlcConnection connection = new DefaultPlcDriverManager().getConnection("s7://10.10.1.80?remote-rack=0&remote-slot=3&controller-type=S7_400")) { final PlcSubscriptionRequest.Builder subscription = connection.subscriptionRequestBuilder(); subscription.addEventTagAddress("myMODE", "MODE"); @@ -103,7 +106,7 @@ public static void main(String[] args) throws Exception { System.out.println("Waiting for events"); - Thread.sleep(5000); + Thread.sleep(20000); System.out.println("Bye..."); diff --git a/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcReadAndWriteVIPA.java b/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcReadAndWriteVIPA.java new file mode 100644 index 00000000000..6e5c22b1c0f --- /dev/null +++ b/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcReadAndWriteVIPA.java @@ -0,0 +1,42 @@ +/* + * 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 + * + * https://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.examples.plc4j.s7event; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * @author cgarcia + */ +public class PlcReadAndWriteVIPA { + + private static final Logger logger = LoggerFactory.getLogger(PlcReadAndWriteVIPA.class); + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + logger.info("*****************************************************"); + logger.info("* 1. I need a real VIPA CPU.."); + logger.info("* Press [ENTER]"); + logger.info("*****************************************************"); + } + +} diff --git a/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcReadDataS7400H.java b/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcReadDataS7400H.java new file mode 100644 index 00000000000..49cf838d0ef --- /dev/null +++ b/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcReadDataS7400H.java @@ -0,0 +1,267 @@ +/* + * 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 + * + * https://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.examples.plc4j.s7event; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicBoolean; +import org.apache.commons.lang3.time.StopWatch; +import org.apache.plc4x.java.DefaultPlcDriverManager; +import org.apache.plc4x.java.api.exceptions.PlcConnectionException; +import org.apache.plc4x.java.api.listener.ConnectionStateListener; +import org.apache.plc4x.java.api.messages.PlcReadRequest; +import org.apache.plc4x.java.api.messages.PlcReadResponse; +import org.apache.plc4x.java.api.types.PlcResponseCode; +import org.apache.plc4x.java.s7.readwrite.protocol.S7HPlcConnection; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/* +* +* Example of connection to a S7-400. +* The connection is supervised. +* Plc: SIMATIC S7-400 +* Model: CPU 417 +* Part number: 6ES7 417-4XT05-0AB0 +* Firmware version: 5.1.0 +* CP1: 6GK7 443-1EX11-0XE0 +* CP2: 6GK7 443-1EX20-0XB0 +*/ +public class PlcReadDataS7400H implements ConnectionStateListener { + + private static final Logger logger = LoggerFactory.getLogger(PlcReadDataS7400H.class); + + private S7HPlcConnection connection = null; + private AtomicBoolean isConnected = new AtomicBoolean(false); + + /** + * @param args the command line arguments + */ + public static void main(String[] args) throws Exception { + System.setProperty(org.slf4j.simple.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "Debug"); + + PlcReadDataS7400H device = new PlcReadDataS7400H(); + device.run(); + } + + + public void run() throws IOException { + logger.info("*****************************************************"); + logger.info("* Example of connection and read to a Simatic S7-400H"); + logger.info("* Plc: SIMATIC S7-400"); + logger.info("* Model: CPU 417"); + logger.info("* Part number: 6ES7 417-4XT05-0AB0"); + logger.info("* Firmware version: 5.1.0"); + logger.info("* CP1: 6GK7 443-1EX11-0XE0"); + logger.info("* CP2: 6GK7 443-1EX20-0XB0"); + logger.info("*"); + logger.info("* Note: . "); + logger.info("* . "); + logger.info("*****************************************************"); + + OpenConnection("s7://10.10.1.80/10.10.1.81?remote-rack=0&" + + "remote-slot=3&remote-rack2=0&remote-slot=4&" + + "controller-type=S7_400&read-timeout=8&" + + "ping=true&ping-time=2&retry-time=3"); //(01) + + logger.info("*****************************************************"); + logger.info("* 1. Once the connection is executed, it must read"); + logger.info("* the data contained in the address."); + logger.info("* URL to:s7://10.10.1.80/10.10.1.81?remote-rack=0&"); + logger.info(" remote-slot=3&remote-rack2=0&remote-slot=4&"); + logger.info(" controller-type=S7_400&read-timeout=8&"); + logger.info(" ping=true&ping-time=2&retry-time=3"); + logger.info("* Press [ENTER]"); + logger.info("*****************************************************"); + System.in.read(); + + Read(); //(01.1) + + logger.info("*****************************************************"); + logger.info("* 2. Turn off/on PLC! This will cause the connection"); + logger.info("* handlers to be lost. "); + logger.info("* This simulates connection loss due to lack of "); + logger.info("* traffic, which is handled by OS. "); + logger.info("* When reading is executed, the driver must activate"); + logger.info("* the reconnection process internally."); + logger.info("* In this operation the reading is lost, but "); + logger.info("* the reconnection process begins."); + logger.info("* Press [ENTER]"); + logger.info("*****************************************************"); + System.in.read(); + + Read(); //(02.1) + + logger.info("*****************************************************"); + logger.info("* 3. The connection must be reestablished."); + logger.info("* Remove primary connection."); + logger.info("* Press [ENTER]"); + logger.info("*****************************************************"); + System.in.read(); + + Read(); //(03.1) + + logger.info("*****************************************************"); + logger.info("* 4. Remove secondary connection."); + logger.info("* Press [ENTER]"); + logger.info("*****************************************************"); + System.in.read(); + + Read(); //(03.1) + + logger.info("*****************************************************"); + logger.info("* 5. Place primary connection."); + logger.info("* Press [ENTER]"); + logger.info("*****************************************************"); + System.in.read(); + + Read(); //(05.1) + + logger.info("*****************************************************"); + logger.info("* 6. Place secondary connection."); + logger.info("* Press [ENTER]"); + logger.info("*****************************************************"); + System.in.read(); + + Read(); //(06.1) + + logger.info("*****************************************************"); + logger.info("* 7. Once the connection is executed, it must read."); + logger.info("* Press [ENTER]"); + logger.info("*****************************************************"); + System.in.read(); + + Read(); //(07.1) + + + logger.info("*****************************************************"); + logger.info("* 8. And we close the connection."); + logger.info("* Press [ENTER]"); + logger.info("*****************************************************"); + + CloseConnection(); //(08.1) + + } + + + /*************************************************************************** + * Under normal conditions, the driver expects you to have the PLC + * connected to the network to start operations. + * If a connection to the PLC cannot be established, an exception of type + * "PlcConnectionException" is generated, which must be handled by your + * application. In this example it waits for a connection to exist. + * When you disconnect the "connection", the S7 driver will take care of the + * connection and reconnection process if necessary. + * The internal wait time for the connection is one (01) second. + ***************************************************************************/ + private void OpenConnection(String url) { + int retrys = 0; + StopWatch watch = new StopWatch(); + watch.start(); + while (null == connection) { + try { + connection =(S7HPlcConnection) new DefaultPlcDriverManager(). + getConnection(url); + connection.addEventListener(this); + while (!connection.isConnected()); + watch.stop(); + + isConnected.set( connection.isConnected()); + + logger.info("Time elapse for connection: {} in ms, with " + + "rettrys: {}",watch.getTime(), retrys); + + } catch (PlcConnectionException ex) { + logger.info(ex.getMessage()); + retrys++; + } + } + + } + + /*************************************************************************** + * When the connection is closed, pending tasks and transactions are + * completed. + * The rest of the work should be sent to the GC. + ***************************************************************************/ + private void CloseConnection() { + if (null == connection) return; + isConnected.set(false); + try { + connection.close(); + connection = null; //GC do you job!. + + } catch (PlcConnectionException ex) { + logger.info("CloseConnection: " + ex.getMessage()); + } + } + + /*************************************************************************** + * The reading process is standard. In case of an exception, + * the user must take the appropriate actions, but "do not close + * the connection": + ***************************************************************************/ + private void Read() { + if (!isConnected.get()) return; + try { + final PlcReadRequest.Builder readrequest = connection.readRequestBuilder(); //(01) + readrequest.addTagAddress("TEST", "%DB1000:4:INT"); //(02) + + final PlcReadRequest rr = readrequest.build(); //(03) + final PlcReadResponse response; //(04) + response = rr.execute().get(); //(05) + + if (response.getResponseCode("TEST") == PlcResponseCode.OK) { //(06) + logger.info("Value: " + response.getString("TEST")); + } else { + logger.info("Problem reading..."); + } + } catch (Exception ex) { //(07) + logger.info("Read: " + ex.getMessage()); + }; + } + + /*************************************************************************** + * This method is called when the driver makes an internal TCP connection. + * The first connection of the driver does not generate this event. + * In the case of high availability systems, this signal should be used + * to restart subscriptions to events, alarms, etc. + ***************************************************************************/ + @Override + public void connected() { + logger.info("*****************************************************"); + logger.info("*************** Plc is connected. *******************"); + logger.info("*****************************************************"); + isConnected.set(true); + } + + /*************************************************************************** + * This method is called when there is a physical disconnection of the driver + * Check the monitoring parameters given in the URL during connection. + ***************************************************************************/ + @Override + public void disconnected() { + logger.info("*****************************************************"); + logger.info("*************** Plc is disconnected. ****************"); + logger.info("*****************************************************"); + isConnected.set(false); + } + + +} diff --git a/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcReadS71200.java b/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcReadS71200.java new file mode 100644 index 00000000000..7a0ac295bfd --- /dev/null +++ b/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcReadS71200.java @@ -0,0 +1,265 @@ +/* + * 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 + * + * https://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.examples.plc4j.s7event; + +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import org.apache.commons.lang3.time.StopWatch; +import org.apache.plc4x.java.DefaultPlcDriverManager; +import org.apache.plc4x.java.api.exceptions.PlcConnectionException; +import org.apache.plc4x.java.api.listener.ConnectionStateListener; +import org.apache.plc4x.java.api.messages.PlcReadRequest; +import org.apache.plc4x.java.api.messages.PlcReadResponse; +import org.apache.plc4x.java.api.types.PlcResponseCode; +import org.apache.plc4x.java.s7.readwrite.protocol.S7HPlcConnection; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/* +* Example of connection to a Simatic S7-1200. +* The connection is supervised. +* Plc: SIMATIC S7-1200 +* Model: CPU 1214C DC/DC/DC +* Part number: 6ES7 214-1AE30-0XB0 +* Firmware version: 2.2 +*/ +public class PlcReadS71200 implements ConnectionStateListener { + + private static final Logger logger = LoggerFactory.getLogger(PlcReadS71200.class); + + private S7HPlcConnection connection = null; + private AtomicBoolean isConnected = new AtomicBoolean(false); + + + /** + * @param args the command line arguments + */ + public static void main(String[] args) throws Exception{ + System.setProperty(org.slf4j.simple.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "Debug"); + + PlcReadS71200 device = new PlcReadS71200(); + device.run(); + } + + public void run() throws IOException { + logger.info("*****************************************************"); + logger.info("* Example of connection and read to a Simatic S7-1200"); + logger.info("* Plc: SIMATIC S7-1200"); + logger.info("* Model: CPU 1214C DC/DC/DC"); + logger.info("* Part number: 6ES7 214-1AE30-0XB0"); + logger.info("* Firmware version: 2.2"); + logger.info("*"); + logger.info("* Note: . All DBs must be non-optimized."); + logger.info("* . PLC can be pinged."); + logger.info("*****************************************************"); + + OpenConnection("s7://10.10.1.46"); //(01) + + logger.info("*****************************************************"); + logger.info("* 1. Once the connection is executed, it must read"); + logger.info("* the data contained in the address."); + logger.info("* URL to: s7://10.10.1.46."); + logger.info("* Press [ENTER]"); + logger.info("*****************************************************"); + System.in.read(); + + Read(); //(01.1) + + logger.info("*****************************************************"); + logger.info("* 2. Turn off/on PLC! This will cause the connection"); + logger.info("* handlers to be lost. "); + logger.info("* This simulates connection loss due to lack of "); + logger.info("* traffic, which is handled by OS. "); + logger.info("* When reading is executed, the driver must activate"); + logger.info("* the reconnection process internally."); + logger.info("* In this operation the reading is lost, but "); + logger.info("* the reconnection process begins."); + logger.info("* Press [ENTER]"); + logger.info("*****************************************************"); + System.in.read(); + + Read(); //(02.1) + + while (!isConnected.get()); //(04) + + logger.info("*****************************************************"); + logger.info("* 3. The connection must be reestablished."); + logger.info("* You must be able to read the value from the PLC.."); + logger.info("* Press [ENTER]"); + logger.info("*****************************************************"); + System.in.read(); + + Read(); //(03.1) + + logger.info("*****************************************************"); + logger.info("* 4. Now we close the connection and open it using"); + logger.info("* other parameters."); + logger.info("* The new connection is given by"); + logger.info("* URL to: s7://10.10.1.46?read-timeout=6&ping=true&ping-time=2"); + logger.info("* Press [ENTER]"); + logger.info("*****************************************************"); + System.in.read(); + + CloseConnection(); //(04.1) + OpenConnection("s7://10.10.1.46?read-timeout=6&ping=true&ping-time=2"); //(04.2) + + + logger.info("*****************************************************"); + logger.info("* 5. Once the connection is executed, it must read."); + logger.info("* Press [ENTER]"); + logger.info("*****************************************************"); + System.in.read(); + + Read(); //(05.1) + + logger.info("*****************************************************"); + logger.info("* 6. Turn off/on PLC! This will cause the connection"); + logger.info("* handlers to be lost. "); + logger.info("* The driver will try to reconnect. "); + logger.info("* Press [ENTER]"); + logger.info("*****************************************************"); + System.in.read(); + + while (!isConnected.get()); + Read(); //(06.1) + + logger.info("*****************************************************"); + logger.info("* 7. Once the connection is executed, it must read."); + logger.info("* Press [ENTER]"); + logger.info("*****************************************************"); + System.in.read(); + + Read(); //(07.1) + + + logger.info("*****************************************************"); + logger.info("* 8. And we close the connection."); + logger.info("* Press [ENTER]"); + logger.info("*****************************************************"); + + CloseConnection(); //(08.1) + + } + + /*************************************************************************** + * Under normal conditions, the driver expects you to have the PLC + * connected to the network to start operations. + * If a connection to the PLC cannot be established, an exception of type + * "PlcConnectionException" is generated, which must be handled by your + * application. In this example it waits for a connection to exist. + * When you disconnect the connection, the S7 driver will take care of the + * connection and reconnection process if necessary. + * The internal wait time for the connection is one (01) second. + ***************************************************************************/ + private void OpenConnection(String url) { + int retrys = 0; + StopWatch watch = new StopWatch(); + watch.start(); + while (null == connection) { + try { + connection =(S7HPlcConnection) new DefaultPlcDriverManager(). + getConnection(url); + connection.addEventListener(this); + while (!connection.isConnected()); + watch.stop(); + + isConnected.set( connection.isConnected()); + + logger.info("Time elapse for connection: {} in ms, with " + + "rettrys: {}",watch.getTime(), retrys); + + } catch (PlcConnectionException ex) { + logger.info(ex.getMessage()); + retrys++; + } + } + + } + + /*************************************************************************** + * When the connection is closed, pending tasks and transactions are + * completed. + * The rest of the work should be sent to the GC. + ***************************************************************************/ + private void CloseConnection() { + if (null == connection) return; + isConnected.set(false); + try { + connection.close(); + connection = null; //GC do you job!. + + } catch (PlcConnectionException ex) { + logger.info("CloseConnection: " + ex.getMessage()); + } + } + + /*************************************************************************** + * The reading process is standard. In case of an exception, + * the user must take the appropriate actions, but "do not close + * the connection": + ***************************************************************************/ + private void Read() { + try { + final PlcReadRequest.Builder readrequest = connection.readRequestBuilder(); //(01) + readrequest.addTagAddress("TEST", "%DB100:10:INT"); //(02) + + final PlcReadRequest rr = readrequest.build(); //(03) + final PlcReadResponse response; //(04) + response = rr.execute().get(); //(05) + + if (response.getResponseCode("TEST") == PlcResponseCode.OK) { //(06) + logger.info("Value: " + response.getString("TEST")); + } else { + logger.info("Problem reading..."); + } + } catch (Exception ex) { //(07) + logger.info("Read: " + ex.getMessage()); + }; + + } + + /*************************************************************************** + * This method is called when the driver makes an internal TCP connection. + * The first connection of the driver does not generate this event. + * In the case of high availability systems, this signal should be used + * to restart subscriptions to events, alarms, etc. + ***************************************************************************/ + @Override + public void connected() { + logger.info("*****************************************************"); + logger.info("*************** Plc is connected. *******************"); + logger.info("*****************************************************"); + isConnected.set(true); + } + + /*************************************************************************** + * This method is called when there is a physical disconnection of the driver + * Check the monitoring parameters given in the URL during connection. + ***************************************************************************/ + @Override + public void disconnected() { + logger.info("*****************************************************"); + logger.info("*************** Plc is disconnected. ****************"); + logger.info("*****************************************************"); + isConnected.set(false); + } + +} diff --git a/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/SzlRequest.java b/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcSzlRequestS7400H.java similarity index 93% rename from plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/SzlRequest.java rename to plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcSzlRequestS7400H.java index 22de70ee98c..809ce1d2c64 100644 --- a/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/SzlRequest.java +++ b/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcSzlRequestS7400H.java @@ -38,15 +38,17 @@ * SZL_ID = 0x0011, allows to identify the device (PLC). */ -public class SzlRequest { +public class PlcSzlRequestS7400H { - private static final Logger logger = LoggerFactory.getLogger(SzlRequest.class); + private static final Logger logger = LoggerFactory.getLogger(PlcSzlRequestS7400H.class); /** * @param args the command line arguments */ public static void main(String[] args) throws Exception { + System.setProperty(org.slf4j.simple.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "Debug"); + System.out.println("******************************************************************************************"); System.out.println("Before using, take a look at:"); System.out.println("System Software for S7-300/400.\r\nSystem and Standard Functions - Volume 1/2"); @@ -55,7 +57,7 @@ public static void main(String[] args) throws Exception { System.out.println("URL: https://cache.industry.siemens.com/dl/files/604/44240604/att_67003/v1/s7sfc_en-EN.pdf"); System.out.println("******************************************************************************************"); - try (PlcConnection connection = new DefaultPlcDriverManager().getConnection("s7://10.10.1.33?remote-rack=0&remote-slot=3&controller-type=S7_400")) { //(01) + try (PlcConnection connection = new DefaultPlcDriverManager().getConnection("s7://10.10.1.80?remote-rack=0&remote-slot=3&controller-type=S7_400")) { //(01) final PlcReadRequest.Builder readrequest = connection.readRequestBuilder(); //(02) diff --git a/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcWriteDataS7400H.java b/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcWriteDataS7400H.java new file mode 100644 index 00000000000..ffc5a477d11 --- /dev/null +++ b/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcWriteDataS7400H.java @@ -0,0 +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 + * + * https://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.examples.plc4j.s7event; + + +public class PlcWriteDataS7400H { + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + // TODO code application logic here + } + +} diff --git a/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcWriteS71200.java b/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcWriteS71200.java new file mode 100644 index 00000000000..d88057fd102 --- /dev/null +++ b/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcWriteS71200.java @@ -0,0 +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 + * + * https://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.examples.plc4j.s7event; + + +public class PlcWriteS71200 { + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + // TODO code application logic here + } + +} diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/Plc4xNettyWrapper.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/Plc4xNettyWrapper.java index e1f708072d9..e6fdf575b56 100644 --- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/Plc4xNettyWrapper.java +++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/Plc4xNettyWrapper.java @@ -18,6 +18,7 @@ */ package org.apache.plc4x.java.spi; +import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; diff --git a/protocols/s7/src/main/resources/protocols/s7/s7.mspec b/protocols/s7/src/main/resources/protocols/s7/s7.mspec index 98cf4a69192..f3945c05eaf 100644 --- a/protocols/s7/src/main/resources/protocols/s7/s7.mspec +++ b/protocols/s7/src/main/resources/protocols/s7/s7.mspec @@ -17,9 +17,6 @@ * under the License. */ -// https://blog.viettelcybersecurity.com/security-wall-of-s7commplus-part-1/ -// https://blog.viettelcybersecurity.com/security-wall-of-s7commplus-3/ - //////////////////////////////////////////////////////////////// // IsoOnTcp/TPKT //////////////////////////////////////////////////////////////// @@ -288,10 +285,10 @@ ] ] -//TODO: Se debe modificar el calculo para incluir el tipo -// . si es tipo 4 usa el desplazamiento -// . si es tipo 3, la longitud es la indicada -// . verificar calculo con los otros tipos +//TODO: The calculation must be modified to include the type +// . if it is type 0x07(REAL) or 0x09 (OCTET_STRING), the length is indicated +// . another type uses scrolling +// . verify calculation with the other types [type AssociatedValueType [simple DataTransportErrorCode returnCode] [simple DataTransportSize transportSize] @@ -442,9 +439,10 @@ [simple uint 8 syntaxId] [typeSwitch syntaxId ['0x10' CycServiceItemAnyType - [simple TransportSize transportSize] + //[simple TransportSize transportSize] + [enum TransportSize transportSize code] [simple uint 16 length] - [simple uint 16 dbNumber] + [simple uint 16 dbNumber] [simple MemoryArea memoryArea] [simple uint 24 address] ] @@ -493,7 +491,7 @@ [discriminatedType S7PayloadUserDataItem(uint 4 cpuFunctionGroup, uint 4 cpuFunctionType, uint 8 cpuSubfunction) [simple DataTransportErrorCode returnCode] [simple DataTransportSize transportSize] - [simple uint 16 dataLength] + [simple uint 16 dataLength] //[implicit uint 16 dataLength 'lengthInBytes - 4'] [typeSwitch cpuFunctionGroup, cpuFunctionType, cpuSubfunction, dataLength @@ -579,7 +577,6 @@ [simple uint 16 szlIndex] ] - // TODO: carcia: explain why you out commented this? the byte array variant below looks hacky //['0x04', '0x08', '0x01' S7PayloadUserDataItemCpuFunctionReadSzlResponse // [simple SzlId szlId] // [simple uint 16 szlIndex] @@ -649,6 +646,34 @@ [array byte items count 'dataLength'] ] + //Time Functions + ['0x07', '0x04', '0x01' S7PayloadUserDataItemClkRequest + ] + + ['0x07', '0x08', '0x01' S7PayloadUserDataItemClkResponse(uint 16 dataLength) + [simple uint 8 Reserved] + [simple uint 8 Year1] + [simple DateAndTime TimeStamp] + ] + + ['0x07', '0x04', '0x03' S7PayloadUserDataItemClkFRequest + ] + + ['0x07', '0x08', '0x03' S7PayloadUserDataItemClkFResponse(uint 16 dataLength) + [simple uint 8 Reserved] + [simple uint 8 Year1] + [simple DateAndTime TimeStamp] + ] + + ['0x07', '0x04', '0x04' S7PayloadUserDataItemClkSetRequest + [reserved uint 8 '0x00'] + [reserved uint 8 '0x00'] + [simple DateAndTime TimeStamp] + ] + + ['0x07', '0x08', '0x04' S7PayloadUserDataItemClkSetResponse + ] + ] ] @@ -734,10 +759,12 @@ [simple string 16 value encoding='"UTF-16"'] ] ['"IEC61131_STRING"' STRING - [manual vstring value 'STATIC_CALL("parseS7String", readBuffer, stringLength, _type.encoding)' 'STATIC_CALL("serializeS7String", writeBuffer, _value, stringLength, _type.encoding)' '(stringLength * 8) + 16' encoding='"UTF-8"'] + // TODO: Fix this length + [manual vstring value 'STATIC_CALL("parseS7String", readBuffer, stringLength, _type.encoding)' 'STATIC_CALL("serializeS7String", writeBuffer, _value, stringLength, _type.encoding)' 'STR_LEN(_value) + 2' encoding='"UTF-8"'] ] ['"IEC61131_WSTRING"' STRING - [manual vstring value 'STATIC_CALL("parseS7String", readBuffer, stringLength, _type.encoding)' 'STATIC_CALL("serializeS7String", writeBuffer, _value, stringLength, _type.encoding)' '(stringLength * 16) + 32' encoding='"UTF-16"'] + // TODO: Fix this length + [manual vstring value 'STATIC_CALL("parseS7String", readBuffer, stringLength, _type.encoding)' 'STATIC_CALL("serializeS7String", writeBuffer, _value, stringLength, _type.encoding)' '(STR_LEN(_value) * 2) + 2' encoding='"UTF-16"'] ] // ----------------------------------------- @@ -852,10 +879,10 @@ ['0x0F' LREAL ['0x30' , 'X' , '8' , 'REAL' , 'null' , 'IEC61131_LREAL' , 'false' , 'false' , 'true' , 'true' , 'false' ]] // Characters and Strings - ['0x10' CHAR ['0x03' , 'B' , '1' , 'null' , 'OCTET_STRING' , 'IEC61131_CHAR' , 'true' , 'true' , 'true' , 'true' , 'true' ]] - ['0x11' WCHAR ['0x13' , 'X' , '2' , 'null' , 'OCTET_STRING' , 'IEC61131_WCHAR' , 'false' , 'false' , 'true' , 'true' , 'true' ]] - ['0x12' STRING ['0x03' , 'X' , '1' , 'null' , 'OCTET_STRING' , 'IEC61131_STRING' , 'true' , 'true' , 'true' , 'true' , 'true' ]] - ['0x13' WSTRING ['0x00' , 'X' , '2' , 'null' , 'OCTET_STRING' , 'IEC61131_WSTRING' , 'false' , 'false' , 'true' , 'true' , 'true' ]] + ['0x10' CHAR ['0x03' , 'B' , '1' , 'null' , 'BYTE_WORD_DWORD' , 'IEC61131_CHAR' , 'true' , 'true' , 'true' , 'true' , 'true' ]] + ['0x11' WCHAR ['0x13' , 'X' , '2' , 'null' , 'null' , 'IEC61131_WCHAR' , 'false' , 'false' , 'true' , 'true' , 'true' ]] + ['0x12' STRING ['0x03' , 'X' , '1' , 'null' , 'BYTE_WORD_DWORD' , 'IEC61131_STRING' , 'true' , 'true' , 'true' , 'true' , 'true' ]] + ['0x13' WSTRING ['0x00' , 'X' , '2' , 'null' , 'null' , 'IEC61131_WSTRING' , 'false' , 'false' , 'true' , 'true' , 'true' ]] // Dates and time values (Please note that we seem to have to rewrite queries for these types to reading bytes or we'll get "Data type not supported" errors) ['0x14' TIME ['0x0B' , 'X' , '4' , 'null' , 'null' , 'IEC61131_TIME' , 'true' , 'true' , 'true' , 'true' , 'true' ]] @@ -863,9 +890,9 @@ ['0x16' LTIME ['0x00' , 'X' , '8' , 'TIME' , 'null' , 'IEC61131_LTIME' , 'false' , 'false' , 'false' , 'true' , 'false' ]] ['0x17' DATE ['0x09' , 'X' , '2' , 'null' , 'BYTE_WORD_DWORD' , 'IEC61131_DATE' , 'true' , 'true' , 'true' , 'true' , 'true' ]] ['0x18' TIME_OF_DAY ['0x06' , 'X' , '4' , 'null' , 'BYTE_WORD_DWORD' , 'IEC61131_TIME_OF_DAY' , 'true' , 'true' , 'true' , 'true' , 'true' ]] - //['0x19' TOD ['0x06' , 'X' , '4' , 'null' , 'BYTE_WORD_DWORD' , 'IEC61131_TIME_OF_DAY' , 'true' , 'true' , 'true' , 'true' , 'true' ]] + ['0x19' TOD ['0x06' , 'X' , '4' , 'null' , 'BYTE_WORD_DWORD' , 'IEC61131_TIME_OF_DAY' , 'true' , 'true' , 'true' , 'true' , 'true' ]] ['0x1A' DATE_AND_TIME ['0x0F' , 'X' , '12' , 'null' , 'null' , 'IEC61131_DATE_AND_TIME', 'true' , 'true' , 'false' , 'true' , 'false' ]] - //['0x1B' DT ['0x0F' , 'X' , '12' , 'null' , 'null' , 'IEC61131_DATE_AND_TIME', 'true' , 'true' , 'false' , 'true' , 'false' ]] + ['0x1B' DT ['0x0F' , 'X' , '12' , 'null' , 'null' , 'IEC61131_DATE_AND_TIME', 'true' , 'true' , 'false' , 'true' , 'false' ]] ] [enum uint 8 MemoryArea(string 24 shortName) @@ -1000,7 +1027,7 @@ ['0x12' UPDATE] ] -[enum uint 8 TimeBase +[enum uint 8 'TimeBase' ['0x00' B01SEC] ['0x01' B1SEC] ['0X02' B10SEC]