You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2026/08/19 20:45:20 UTC
(plc4x) 01/07: feat(plc4j/eip): Detect Connection Manager and Message using "Get Attribute Single" (#2674)
This is an automated email from the ASF dual-hosted git repository.
chrisdutz pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git
commit 4b4aea691d8ec10730f6e44c1b5ca2549ce9dbb2
Author: Anderson Vasconcelos Pires <an...@gmail.com>
AuthorDate: Wed Aug 19 12:42:19 2026 -0300
feat(plc4j/eip): Detect Connection Manager and Message using "Get Attribute Single" (#2674)
* feat(plc4j/eip): Implement "Get Attribute Single" on EIP protocol for cases where "Get Attribute All" is not supported by the device.
---
.../{LogicalSegmentType.java => AttributeID.java} | 99 ++--
.../eip/readwrite/GetAttributeSingleRequest.java | 90 ++-
.../eip/readwrite/GetAttributeSingleResponse.java | 112 +++-
.../java/eip/readwrite/LogicalSegmentType.java | 2 +
.../plc4x/java/eip/base/EipTcpConnection.java | 83 ++-
.../eip/src/main/resources/protocols/eip/eip.mspec | 15 +-
.../resources/protocols/eip/DriverTestsuite.xml | 644 +--------------------
7 files changed, 348 insertions(+), 697 deletions(-)
diff --git a/plc4j/drivers/eip/src/main/generated/org/apache/plc4x/java/eip/readwrite/LogicalSegmentType.java b/plc4j/drivers/eip/src/main/generated/org/apache/plc4x/java/eip/readwrite/AttributeID.java
similarity index 50%
copy from plc4j/drivers/eip/src/main/generated/org/apache/plc4x/java/eip/readwrite/LogicalSegmentType.java
copy to plc4j/drivers/eip/src/main/generated/org/apache/plc4x/java/eip/readwrite/AttributeID.java
index 28776467a5..9982e11ecf 100644
--- a/plc4j/drivers/eip/src/main/generated/org/apache/plc4x/java/eip/readwrite/LogicalSegmentType.java
+++ b/plc4j/drivers/eip/src/main/generated/org/apache/plc4x/java/eip/readwrite/AttributeID.java
@@ -25,59 +25,67 @@ import org.apache.plc4x.java.spi.fields.data.reader.DataReaderFactory;
import org.apache.plc4x.java.spi.fields.data.writer.DataWriterFactory;
import org.apache.plc4x.java.spi.fields.fields.reader.FieldReaderFactory;
import org.apache.plc4x.java.spi.fields.fields.writer.FieldWriterFactory;
-import org.apache.plc4x.java.spi.fields.utils.EvaluationHelper;
import org.apache.plc4x.java.spi.fields.utils.ThreadLocalHelper;
/**
* Code generated by code-generation. DO NOT EDIT.
*/
-public abstract class LogicalSegmentType implements Message {
- public LogicalSegmentType() {
+public class AttributeID extends LogicalSegmentType implements Message {
+ protected final byte format;
+
+ protected final short attribute;
+
+ public AttributeID(Byte format, Short attribute) {
+ this.format = format;
+ this.attribute = attribute;
}
/**
* Discriminator field logicalSegmentType
*/
- public abstract byte getLogicalSegmentType();
+ @Override
+ public byte getLogicalSegmentType() {
+ return (byte) 0x04;
+ }
+
+ /**
+ * Property field format
+ */
+ public byte getFormat() {
+ return format;
+ }
- protected abstract void serializeLogicalSegmentTypeChild(WriteBuffer writeBuffer) throws
- BufferException;
+ /**
+ * Property field attribute
+ */
+ public short getAttribute() {
+ return attribute;
+ }
- public static LogicalSegmentType staticParse(ReadBuffer readBuffer) throws BufferException {
- readBuffer.pushContext(WithOption.WithName("LogicalSegmentType"));
+ public static LogicalSegmentTypeBuilder staticParseLogicalSegmentTypeBuilder(
+ ReadBuffer readBuffer) throws BufferException {
+ readBuffer.pushContext(WithOption.WithName("AttributeID"));
int startPos = readBuffer.getPositionInBits();
boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
- // Discriminator Field: logicalSegmentType
- byte logicalSegmentType = FieldReaderFactory.readDiscriminatorField(DataReaderFactory.readUnsignedByte(readBuffer, 3), WithOption.WithName("logicalSegmentType"));
-
- // Switch Field
- LogicalSegmentTypeBuilder builder = null;
- if (EvaluationHelper.equals(logicalSegmentType, (byte) (0x00))) {
- builder = ClassID.staticParseLogicalSegmentTypeBuilder(readBuffer);
- } else if (EvaluationHelper.equals(logicalSegmentType, (byte) (0x01))) {
- builder = InstanceID.staticParseLogicalSegmentTypeBuilder(readBuffer);
- } else if (EvaluationHelper.equals(logicalSegmentType, (byte) (0x02))) {
- builder = MemberID.staticParseLogicalSegmentTypeBuilder(readBuffer);
- }
- if (builder == null) {
- throw new BufferException("Unsupported case for discriminated type parameters parameters [logicalSegmentType]");
- }
+ // Simple Field: format
+ byte format = FieldReaderFactory.readSimpleField(DataReaderFactory.readUnsignedByte(readBuffer, 2), WithOption.WithName("format"));
+
+ // Simple Field: attribute
+ short attribute = FieldReaderFactory.readSimpleField(DataReaderFactory.readUnsignedShort(readBuffer, 8), WithOption.WithName("attribute"));
readBuffer.popContext();
- return builder.build();
+ return new LogicalSegmentTypeBuilderImpl(format, attribute);
}
- @Override
- public void serialize(WriteBuffer writeBuffer) throws BufferException {
- writeBuffer.pushContext(WithOption.WithName("LogicalSegmentType"));
+ protected void serializeLogicalSegmentTypeChild(WriteBuffer writeBuffer) throws BufferException {
+ writeBuffer.pushContext(WithOption.WithName("AttributeID"));
int startPos = writeBuffer.getPositionInBits();
boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
- byte logicalSegmentType = (byte) getLogicalSegmentType();
- // Discriminator Field: logicalSegmentType
- FieldWriterFactory.writeDiscriminatorField((byte) logicalSegmentType, DataWriterFactory.writeUnsignedByte(writeBuffer, 3), WithOption.WithName("logicalSegmentType"));
+ // Simple Field: format
+ FieldWriterFactory.writeSimpleField((byte) format, DataWriterFactory.writeUnsignedByte(writeBuffer, 2), WithOption.WithName("format"));
- // Switch Field
- serializeLogicalSegmentTypeChild(writeBuffer);
+ // Simple Field: attribute
+ FieldWriterFactory.writeSimpleField((short) attribute, DataWriterFactory.writeUnsignedShort(writeBuffer, 8), WithOption.WithName("attribute"));
writeBuffer.popContext();
}
@@ -89,19 +97,30 @@ public abstract class LogicalSegmentType implements Message {
@Override
public int getLengthInBits() {
- int lengthInBits = 0;
- LogicalSegmentType _value = this;
+ int lengthInBits = super.getLengthInBits();
+ AttributeID _value = this;
boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
- // Discriminator Field: logicalSegmentType
- lengthInBits += 3;
+ // Simple Field: format
+ lengthInBits += 2;
- // Switch Field
- // (the subtype will instead add the actual length of subtype elements)
+ // Simple Field: attribute
+ lengthInBits += 8;
return lengthInBits;
}
- public interface LogicalSegmentTypeBuilder {
- LogicalSegmentType build();
+ public static class LogicalSegmentTypeBuilderImpl implements LogicalSegmentType.LogicalSegmentTypeBuilder {
+ private final byte format;
+
+ private final short attribute;
+
+ public LogicalSegmentTypeBuilderImpl(byte format, short attribute) {
+ this.format = format;
+ this.attribute = attribute;
+ }
+
+ public LogicalSegmentType build() {
+ return new AttributeID(format, attribute);
+ }
}
}
diff --git a/plc4j/drivers/eip/src/main/generated/org/apache/plc4x/java/eip/readwrite/GetAttributeSingleRequest.java b/plc4j/drivers/eip/src/main/generated/org/apache/plc4x/java/eip/readwrite/GetAttributeSingleRequest.java
index a14814da0a..efea7404ff 100644
--- a/plc4j/drivers/eip/src/main/generated/org/apache/plc4x/java/eip/readwrite/GetAttributeSingleRequest.java
+++ b/plc4j/drivers/eip/src/main/generated/org/apache/plc4x/java/eip/readwrite/GetAttributeSingleRequest.java
@@ -21,13 +21,27 @@ import org.apache.plc4x.java.spi.buffers.api.ReadBuffer;
import org.apache.plc4x.java.spi.buffers.api.WithOption;
import org.apache.plc4x.java.spi.buffers.api.WriteBuffer;
import org.apache.plc4x.java.spi.buffers.api.exceptions.BufferException;
+import org.apache.plc4x.java.spi.fields.data.reader.DataReaderFactory;
+import org.apache.plc4x.java.spi.fields.data.writer.DataWriterFactory;
+import org.apache.plc4x.java.spi.fields.fields.reader.FieldReaderFactory;
+import org.apache.plc4x.java.spi.fields.fields.writer.FieldWriterFactory;
import org.apache.plc4x.java.spi.fields.utils.ThreadLocalHelper;
/**
* Code generated by code-generation. DO NOT EDIT.
*/
public class GetAttributeSingleRequest extends CipService implements Message {
- public GetAttributeSingleRequest() {
+ protected final PathSegment classSegment;
+
+ protected final PathSegment instanceSegment;
+
+ protected final PathSegment attributeSegment;
+
+ public GetAttributeSingleRequest(PathSegment classSegment, PathSegment instanceSegment,
+ PathSegment attributeSegment) {
+ this.classSegment = classSegment;
+ this.instanceSegment = instanceSegment;
+ this.attributeSegment = attributeSegment;
}
/**
@@ -54,19 +68,65 @@ public class GetAttributeSingleRequest extends CipService implements Message {
return false;
}
+ /**
+ * Property field classSegment
+ */
+ public PathSegment getClassSegment() {
+ return classSegment;
+ }
+
+ /**
+ * Property field instanceSegment
+ */
+ public PathSegment getInstanceSegment() {
+ return instanceSegment;
+ }
+
+ /**
+ * Property field attributeSegment
+ */
+ public PathSegment getAttributeSegment() {
+ return attributeSegment;
+ }
+
public static CipServiceBuilder staticParseCipServiceBuilder(ReadBuffer readBuffer,
boolean connected, int serviceLen) throws BufferException {
readBuffer.pushContext(WithOption.WithName("GetAttributeSingleRequest"));
int startPos = readBuffer.getPositionInBits();
boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
+ // Implicit Field: requestPathSize
+ short requestPathSize = FieldReaderFactory.readImplicitField(DataReaderFactory.readUnsignedShort(readBuffer, 8), WithOption.WithName("requestPathSize"));
+
+ // Simple Field: classSegment
+ PathSegment classSegment = FieldReaderFactory.readSimpleField(DataReaderFactory.readComplex(() -> (PathSegment) PathSegment.staticParse(readBuffer), readBuffer), WithOption.WithName("classSegment"));
+
+ // Simple Field: instanceSegment
+ PathSegment instanceSegment = FieldReaderFactory.readSimpleField(DataReaderFactory.readComplex(() -> (PathSegment) PathSegment.staticParse(readBuffer), readBuffer), WithOption.WithName("instanceSegment"));
+
+ // Simple Field: attributeSegment
+ PathSegment attributeSegment = FieldReaderFactory.readSimpleField(DataReaderFactory.readComplex(() -> (PathSegment) PathSegment.staticParse(readBuffer), readBuffer), WithOption.WithName("attributeSegment"));
+
readBuffer.popContext();
- return new CipServiceBuilderImpl();
+ return new CipServiceBuilderImpl(classSegment, instanceSegment, attributeSegment);
}
protected void serializeCipServiceChild(WriteBuffer writeBuffer) throws BufferException {
writeBuffer.pushContext(WithOption.WithName("GetAttributeSingleRequest"));
int startPos = writeBuffer.getPositionInBits();
boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
+ // Implicit Field: requestPathSize
+ short requestPathSize = (short) (((((classSegment.getLengthInBytes()) + (instanceSegment.getLengthInBytes())) + (attributeSegment.getLengthInBytes()))) / (2));
+ FieldWriterFactory.writeImplicitField((short) requestPathSize, DataWriterFactory.writeUnsignedShort(writeBuffer, 8), WithOption.WithName("requestPathSize"));
+
+ // Simple Field: classSegment
+ FieldWriterFactory.writeSimpleField((PathSegment) classSegment, DataWriterFactory.writeComplex(writeBuffer), WithOption.WithName("classSegment"));
+
+ // Simple Field: instanceSegment
+ FieldWriterFactory.writeSimpleField((PathSegment) instanceSegment, DataWriterFactory.writeComplex(writeBuffer), WithOption.WithName("instanceSegment"));
+
+ // Simple Field: attributeSegment
+ FieldWriterFactory.writeSimpleField((PathSegment) attributeSegment, DataWriterFactory.writeComplex(writeBuffer), WithOption.WithName("attributeSegment"));
+
writeBuffer.popContext();
}
@@ -80,15 +140,37 @@ public class GetAttributeSingleRequest extends CipService implements Message {
int lengthInBits = super.getLengthInBits();
GetAttributeSingleRequest _value = this;
boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
+ // Implicit Field: requestPathSize
+ lengthInBits += 8;
+
+ // Simple Field: classSegment
+ lengthInBits += classSegment.getLengthInBits();
+
+ // Simple Field: instanceSegment
+ lengthInBits += instanceSegment.getLengthInBits();
+
+ // Simple Field: attributeSegment
+ lengthInBits += attributeSegment.getLengthInBits();
+
return lengthInBits;
}
public static class CipServiceBuilderImpl implements CipService.CipServiceBuilder {
- public CipServiceBuilderImpl() {
+ private final PathSegment classSegment;
+
+ private final PathSegment instanceSegment;
+
+ private final PathSegment attributeSegment;
+
+ public CipServiceBuilderImpl(PathSegment classSegment, PathSegment instanceSegment,
+ PathSegment attributeSegment) {
+ this.classSegment = classSegment;
+ this.instanceSegment = instanceSegment;
+ this.attributeSegment = attributeSegment;
}
public CipService build() {
- return new GetAttributeSingleRequest();
+ return new GetAttributeSingleRequest(classSegment, instanceSegment, attributeSegment);
}
}
}
diff --git a/plc4j/drivers/eip/src/main/generated/org/apache/plc4x/java/eip/readwrite/GetAttributeSingleResponse.java b/plc4j/drivers/eip/src/main/generated/org/apache/plc4x/java/eip/readwrite/GetAttributeSingleResponse.java
index 2e06093730..e96143e065 100644
--- a/plc4j/drivers/eip/src/main/generated/org/apache/plc4x/java/eip/readwrite/GetAttributeSingleResponse.java
+++ b/plc4j/drivers/eip/src/main/generated/org/apache/plc4x/java/eip/readwrite/GetAttributeSingleResponse.java
@@ -16,18 +16,36 @@
// under the License.
package org.apache.plc4x.java.eip.readwrite;
+import java.util.List;
import org.apache.plc4x.java.spi.buffers.api.Message;
import org.apache.plc4x.java.spi.buffers.api.ReadBuffer;
import org.apache.plc4x.java.spi.buffers.api.WithOption;
import org.apache.plc4x.java.spi.buffers.api.WriteBuffer;
import org.apache.plc4x.java.spi.buffers.api.exceptions.BufferException;
+import org.apache.plc4x.java.spi.fields.data.reader.DataReaderFactory;
+import org.apache.plc4x.java.spi.fields.data.writer.DataWriterFactory;
+import org.apache.plc4x.java.spi.fields.fields.reader.FieldReaderFactory;
+import org.apache.plc4x.java.spi.fields.fields.writer.FieldWriterFactory;
import org.apache.plc4x.java.spi.fields.utils.ThreadLocalHelper;
/**
* Code generated by code-generation. DO NOT EDIT.
*/
public class GetAttributeSingleResponse extends CipService implements Message {
- public GetAttributeSingleResponse() {
+ protected final short status;
+
+ protected final short extStatusSize;
+
+ protected final List<Integer> extStatus;
+
+ protected final byte[] servicesData;
+
+ public GetAttributeSingleResponse(Short status, Short extStatusSize, List<Integer> extStatus,
+ byte[] servicesData) {
+ this.status = status;
+ this.extStatusSize = extStatusSize;
+ this.extStatus = extStatus;
+ this.servicesData = servicesData;
}
/**
@@ -54,19 +72,77 @@ public class GetAttributeSingleResponse extends CipService implements Message {
return false;
}
+ /**
+ * Property field status
+ */
+ public short getStatus() {
+ return status;
+ }
+
+ /**
+ * Property field extStatusSize
+ */
+ public short getExtStatusSize() {
+ return extStatusSize;
+ }
+
+ /**
+ * Property field extStatus
+ */
+ public List<Integer> getExtStatus() {
+ return extStatus;
+ }
+
+ /**
+ * Property field servicesData
+ */
+ public byte[] getServicesData() {
+ return servicesData;
+ }
+
public static CipServiceBuilder staticParseCipServiceBuilder(ReadBuffer readBuffer,
boolean connected, int serviceLen) throws BufferException {
readBuffer.pushContext(WithOption.WithName("GetAttributeSingleResponse"));
int startPos = readBuffer.getPositionInBits();
boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
+ // Reserved Field
+ FieldReaderFactory.readReservedField(DataReaderFactory.readUnsignedShort(readBuffer, 8), (short) 0x00, WithOption.WithName("GetAttributeSingleResponse.reserved0"));
+
+ // Simple Field: status
+ short status = FieldReaderFactory.readSimpleField(DataReaderFactory.readUnsignedShort(readBuffer, 8), WithOption.WithName("status"));
+
+ // Simple Field: extStatusSize
+ short extStatusSize = FieldReaderFactory.readSimpleField(DataReaderFactory.readUnsignedShort(readBuffer, 8), WithOption.WithName("extStatusSize"));
+
+ // Array Field: extStatus
+ List<Integer> extStatus = FieldReaderFactory.readCountArrayField(DataReaderFactory.readUnsignedInt(readBuffer, 16), extStatusSize, WithOption.WithName("extStatus"));
+
+ // Array Field: servicesData
+ byte[] servicesData = readBuffer.readBits(Math.toIntExact((((serviceLen) - (4)) - ((2) * (extStatusSize))) * 8), WithOption.WithName("servicesData"));
+
readBuffer.popContext();
- return new CipServiceBuilderImpl();
+ return new CipServiceBuilderImpl(status, extStatusSize, extStatus, servicesData);
}
protected void serializeCipServiceChild(WriteBuffer writeBuffer) throws BufferException {
writeBuffer.pushContext(WithOption.WithName("GetAttributeSingleResponse"));
int startPos = writeBuffer.getPositionInBits();
boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
+ // Reserved Field
+ FieldWriterFactory.writeReservedField((short) 0x00, DataWriterFactory.writeUnsignedShort(writeBuffer, 8));
+
+ // Simple Field: status
+ FieldWriterFactory.writeSimpleField((short) status, DataWriterFactory.writeUnsignedShort(writeBuffer, 8), WithOption.WithName("status"));
+
+ // Simple Field: extStatusSize
+ FieldWriterFactory.writeSimpleField((short) extStatusSize, DataWriterFactory.writeUnsignedShort(writeBuffer, 8), WithOption.WithName("extStatusSize"));
+
+ // Array Field: extStatus
+ FieldWriterFactory.writeSimpleTypeArrayField(extStatus, DataWriterFactory.writeUnsignedInt(writeBuffer, 16), WithOption.WithName("extStatus"));
+
+ // Array Field: servicesData
+ FieldWriterFactory.writeByteArrayField(servicesData, DataWriterFactory.writeByteArray(writeBuffer, (int) ((servicesData != null) ? servicesData.length : 0)), WithOption.WithName("servicesData"));
+
writeBuffer.popContext();
}
@@ -80,15 +156,43 @@ public class GetAttributeSingleResponse extends CipService implements Message {
int lengthInBits = super.getLengthInBits();
GetAttributeSingleResponse _value = this;
boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
+ // Reserved Field
+ lengthInBits += 8;
+
+ // Simple Field: status
+ lengthInBits += 8;
+
+ // Simple Field: extStatusSize
+ lengthInBits += 8;
+
+ // Array Field: extStatus
+ lengthInBits += 16 * extStatus.size();
+
+ // Array Field: servicesData
+ lengthInBits += 8 * ((servicesData != null) ? servicesData.length : 0);
+
return lengthInBits;
}
public static class CipServiceBuilderImpl implements CipService.CipServiceBuilder {
- public CipServiceBuilderImpl() {
+ private final short status;
+
+ private final short extStatusSize;
+
+ private final List<Integer> extStatus;
+
+ private final byte[] servicesData;
+
+ public CipServiceBuilderImpl(short status, short extStatusSize, List<Integer> extStatus,
+ byte[] servicesData) {
+ this.status = status;
+ this.extStatusSize = extStatusSize;
+ this.extStatus = extStatus;
+ this.servicesData = servicesData;
}
public CipService build() {
- return new GetAttributeSingleResponse();
+ return new GetAttributeSingleResponse(status, extStatusSize, extStatus, servicesData);
}
}
}
diff --git a/plc4j/drivers/eip/src/main/generated/org/apache/plc4x/java/eip/readwrite/LogicalSegmentType.java b/plc4j/drivers/eip/src/main/generated/org/apache/plc4x/java/eip/readwrite/LogicalSegmentType.java
index 28776467a5..a02ac13ea8 100644
--- a/plc4j/drivers/eip/src/main/generated/org/apache/plc4x/java/eip/readwrite/LogicalSegmentType.java
+++ b/plc4j/drivers/eip/src/main/generated/org/apache/plc4x/java/eip/readwrite/LogicalSegmentType.java
@@ -58,6 +58,8 @@ public abstract class LogicalSegmentType implements Message {
builder = InstanceID.staticParseLogicalSegmentTypeBuilder(readBuffer);
} else if (EvaluationHelper.equals(logicalSegmentType, (byte) (0x02))) {
builder = MemberID.staticParseLogicalSegmentTypeBuilder(readBuffer);
+ } else if (EvaluationHelper.equals(logicalSegmentType, (byte) (0x04))) {
+ builder = AttributeID.staticParseLogicalSegmentTypeBuilder(readBuffer);
}
if (builder == null) {
throw new BufferException("Unsupported case for discriminated type parameters parameters [logicalSegmentType]");
diff --git a/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/base/EipTcpConnection.java b/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/base/EipTcpConnection.java
index 629f6dfda6..ed3525af2e 100644
--- a/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/base/EipTcpConnection.java
+++ b/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/base/EipTcpConnection.java
@@ -220,7 +220,7 @@ public class EipTcpConnection extends PollingSubscriptionConnectionBase<EIPConfi
this.sessionHandle = sessionResponse.getSessionHandle();
LOGGER.debug("Got assigned with Session handle {}", sessionHandle);
- // 3) GetAttributeAll on the message router to probe capabilities.
+ // 3) Probe connection-manager and message-router capabilities.
// Skipped when the user has already committed to the unconnected
// path — the probe is only useful for choosing between the
// connection-manager and message-router code paths, and some
@@ -229,7 +229,7 @@ public class EipTcpConnection extends PollingSubscriptionConnectionBase<EIPConfi
if (getConfiguration().isForceUnconnectedOperation()) {
return CompletableFuture.completedFuture(null);
}
- return probeAttributes().thenCompose(v -> {
+ return probeClassObjectSupport().thenCompose(v -> {
if (useConnectionManager) {
return openConnectionManager();
}
@@ -238,8 +238,9 @@ public class EipTcpConnection extends PollingSubscriptionConnectionBase<EIPConfi
});
}
- private CompletableFuture<Void> probeAttributes() {
- PathSegment classSegment = new LogicalSegment(new ClassID((byte) 0, (short) 2));
+ // Using this method to continue having the GetAttributeAll that can be useful in the future
+ private CompletableFuture<Void> checkClassObjectAttributes(CIPClassID classId) {
+ PathSegment classSegment = new LogicalSegment(new ClassID((byte) 0, (short) classId.getValue()));
PathSegment instanceSegment = new LogicalSegment(new InstanceID((byte) 0, (short) 1));
UnConnectedDataItem exchange = new UnConnectedDataItem(
new GetAttributeAllRequest(classSegment, instanceSegment));
@@ -248,40 +249,68 @@ public class EipTcpConnection extends PollingSubscriptionConnectionBase<EIPConfi
DEFAULT_SENDER_CONTEXT, 0L, EMPTY_INTERFACE_HANDLE, 0, typeIds);
return sendRequest(eipWrapper).thenAccept(response -> {
- if (!(response instanceof CipRRData rr) || rr.getStatus() != CIPStatus.Success.getValue()) {
- return;
- }
- UnConnectedDataItem dataItem = (UnConnectedDataItem) rr.getTypeIds().get(1);
- if (!(dataItem.getService() instanceof GetAttributeAllResponse gar)) {
- return;
- }
- if (gar.getStatus() == CIPStatus.ServiceNotSupported.getValue()) {
- return;
- }
- if (gar.getAttributes() != null) {
- for (Integer classId : gar.getAttributes().getClassId()) {
- if (CIPClassID.enumForValue(classId) == CIPClassID.MessageRouter) {
- this.useMessageRouter = true;
- }
- if (CIPClassID.enumForValue(classId) == CIPClassID.ConnectionManager) {
- this.useConnectionManager = true;
- }
- }
+
+ if (extractCipService(response) instanceof GetAttributeAllResponse gar &&
+ gar.getStatus() == CIPStatus.Success.getValue() &&
+ gar.getAttributes() != null) {
+ LOGGER.debug("Identity getNumberActive {}", gar.getAttributes().getNumberActive());
}
+ });
+ }
+
+ private CipService extractCipService(EipPacket response) {
+ if (response instanceof CipRRData rr
+ && rr.getStatus() == CIPStatus.Success.getValue()
+ && rr.getTypeIds().size() > 1
+ && rr.getTypeIds().get(1) instanceof UnConnectedDataItem di) {
+ return di.getService();
+ }
+ return null;
+ }
+
+ private CompletableFuture<Void> probeClassObjectSupport() {
+
+ return checkClassObjectSupport(CIPClassID.ConnectionManager).thenCompose(hasSupport -> {
+ useConnectionManager = hasSupport;
+ return checkClassObjectSupport(CIPClassID.MessageRouter);
+ }).thenCompose(hasSupport -> {
+ useMessageRouter = hasSupport;
+ return checkClassObjectAttributes(CIPClassID.Identity);
}).exceptionally(e -> {
// Treat any probe failure (timeout, parse error, malformed response,
- // ServiceNotSupported) as "device has no message router / connection
- // manager" and fall through to the unconnected code path. This keeps
+ // ServiceNotSupported) as the state that was achieved. This keeps
// the handshake working against non-Logix devices and simulators.
- LOGGER.debug("GetAttributeAll probe failed, falling back to unconnected mode", e);
+ LOGGER.debug("probeClassObjectSupport probe failed, keeping the state achieved", e);
return null;
});
}
+ private CompletableFuture<Boolean> checkClassObjectSupport(CIPClassID classId) {
+
+ UnConnectedDataItem exchange = new UnConnectedDataItem(new GetAttributeSingleRequest(
+ new LogicalSegment(new ClassID((byte) 0, (short) classId.getValue())),
+ new LogicalSegment(new InstanceID((byte) 0, (short) 0)), // Class level discovery
+ new LogicalSegment(new AttributeID((byte) 0, (short) 1))) // Attribute ID 1: Revision
+ );
+ List<TypeId> typeIds = Arrays.asList(nullAddressItem, exchange);
+ CipRRData eipWrapper = new CipRRData(sessionHandle, CIPStatus.Success.getValue(),
+ DEFAULT_SENDER_CONTEXT, 0L, EMPTY_INTERFACE_HANDLE, 0, typeIds);
+
+ return sendRequest(eipWrapper).thenCompose(response -> {
+
+ if (extractCipService(response) instanceof GetAttributeSingleResponse gsr) {
+ boolean hasSupport = gsr.getStatus() == CIPStatus.Success.getValue();
+ LOGGER.debug("ClassId: {} status: {} hasSupport: {}", classId, gsr.getStatus(), hasSupport);
+ return CompletableFuture.completedFuture(hasSupport);
+ }
+ return CompletableFuture.completedFuture(false);
+ });
+ }
+
private CompletableFuture<Void> openConnectionManager() {
UnConnectedDataItem exchange = new UnConnectedDataItem(
new CipConnectionManagerRequest(
- new LogicalSegment(new ClassID((byte) 0, (short) 6)),
+ new LogicalSegment(new ClassID((byte) 0, (short) CIPClassID.ConnectionManager.getValue())),
new LogicalSegment(new InstanceID((byte) 0, (short) 1)),
(byte) 0, (byte) 10, (short) 14, 536870914L, 33944L,
this.connectionSerialNumber, 4919, 42L, (short) 3, 2101812L,
diff --git a/protocols/eip/src/main/resources/protocols/eip/eip.mspec b/protocols/eip/src/main/resources/protocols/eip/eip.mspec
index e7e2957e7c..e0c79089d1 100644
--- a/protocols/eip/src/main/resources/protocols/eip/eip.mspec
+++ b/protocols/eip/src/main/resources/protocols/eip/eip.mspec
@@ -157,10 +157,17 @@
[array byte servicesData count 'serviceLen - 6 - (2 * serviceNb)' ]
]
['0x0E','false' GetAttributeSingleRequest
- // TODO: Implement
+ [implicit uint 8 requestPathSize '(classSegment.lengthInBytes + instanceSegment.lengthInBytes + attributeSegment.lengthInBytes)/2']
+ [simple PathSegment classSegment ]
+ [simple PathSegment instanceSegment ]
+ [simple PathSegment attributeSegment ]
]
['0x0E','true' GetAttributeSingleResponse
- // TODO: Implement
+ [reserved uint 8 '0x00' ]
+ [simple uint 8 status ]
+ [simple uint 8 extStatusSize ]
+ [array uint 16 extStatus count 'extStatusSize' ]
+ [array byte servicesData count 'serviceLen - 4 - 2 * extStatusSize' ]
]
['0x10','false' SetAttributeSingleRequest
// TODO: Implement
@@ -358,6 +365,10 @@
[simple uint 2 format]
[simple uint 8 instance]
]
+ ['0x04' AttributeID
+ [simple uint 2 format]
+ [simple uint 8 attribute]
+ ]
]
]
diff --git a/protocols/eip/src/test/resources/protocols/eip/DriverTestsuite.xml b/protocols/eip/src/test/resources/protocols/eip/DriverTestsuite.xml
index 1b5d94cdba..20c5f68f71 100644
--- a/protocols/eip/src/test/resources/protocols/eip/DriverTestsuite.xml
+++ b/protocols/eip/src/test/resources/protocols/eip/DriverTestsuite.xml
@@ -428,379 +428,15 @@
</testcase>
<testcase>
- <name>Two element read request</name>
+ <name>Get Attribute Single Request</name>
<steps>
- <api-request name="Receive Read Request from application">
- <TestReadRequest>
- <tags isList="true">
- <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
- <name>hurz1</name>
- <address>%rate</address>
- </tag>
- <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
- <name>hurz2</name>
- <address>%count</address>
- </tag>
- </tags>
- </TestReadRequest>
- </api-request>
- <outgoing-plc-message name="Send CipReadRequest to PLC">
- <parser-arguments>
- <response>false</response>
- </parser-arguments>
- <EipPacket>
- <command dataType="uint" bitLength="16">111</command>
- <packetLength dataType="uint" bitLength="16">40</packetLength>
- <sessionHandle dataType="uint" bitLength="32">1074224669</sessionHandle>
- <status dataType="uint" bitLength="32">0</status>
- <senderContext dataType="byte" bitLength="64">0x504c433458202020</senderContext>
- <options dataType="uint" bitLength="32">0</options>
- <CipRRData>
- <interfaceHandle dataType="uint" bitLength="32">0</interfaceHandle>
- <timeout dataType="uint" bitLength="16">0</timeout>
- <typeIdCount dataType="uint" bitLength="16">2</typeIdCount>
- <typeIds isList="true">
- <TypeId>
- <id dataType="uint" bitLength="16">0</id>
- <NullAddressItem>
- <reserved dataType="uint" bitLength="16">0</reserved>
- </NullAddressItem>
- </TypeId>
- <TypeId>
- <id dataType="uint" bitLength="16">178</id>
- <UnConnectedDataItem>
- <packetSize dataType="uint" bitLength="16">24</packetSize>
- <service>
- <CipService>
- <response dataType="bit" bitLength="1">false</response>
- <service dataType="uint" bitLength="7">82</service>
- <CipUnconnectedRequest>
- <requestPathSize dataType="uint" bitLength="8">2</requestPathSize>
- <classSegment>
- <PathSegment>
- <pathSegment dataType="uint" bitLength="3">1</pathSegment>
- <LogicalSegment>
- <segmentType>
- <LogicalSegmentType>
- <logicalSegmentType dataType="uint" bitLength="3">0</logicalSegmentType>
- <ClassID>
- <format dataType="uint" bitLength="2">0</format>
- <segmentClass dataType="uint" bitLength="8">6</segmentClass>
- </ClassID>
- </LogicalSegmentType>
- </segmentType>
- </LogicalSegment>
- </PathSegment>
- </classSegment>
- <instanceSegment>
- <PathSegment>
- <pathSegment dataType="uint" bitLength="3">1</pathSegment>
- <LogicalSegment>
- <segmentType>
- <LogicalSegmentType>
- <logicalSegmentType dataType="uint" bitLength="3">1</logicalSegmentType>
- <InstanceID>
- <format dataType="uint" bitLength="2">0</format>
- <instance dataType="uint" bitLength="8">1</instance>
- </InstanceID>
- </LogicalSegmentType>
- </segmentType>
- </LogicalSegment>
- </PathSegment>
- </instanceSegment>
- <reserved dataType="uint" bitLength="16">40197</reserved>
- <messageSize dataType="uint" bitLength="16">10</messageSize>
- <unconnectedService>
- <CipService>
- <response dataType="bit" bitLength="1">false</response>
- <service dataType="uint" bitLength="7">76</service>
- <CipReadRequest>
- <requestPathSize dataType="uint" bitLength="8">3</requestPathSize>
- <tag dataType="byte" bitLength="48">0x910472617465</tag>
- <elementNb dataType="uint" bitLength="16">1</elementNb>
- </CipReadRequest>
- </CipService>
- </unconnectedService>
- <route dataType="uint" bitLength="16">1</route>
- <backPlane dataType="int" bitLength="8">1</backPlane>
- <slot dataType="int" bitLength="8">0</slot>
- </CipUnconnectedRequest>
- </CipService>
- </service>
- </UnConnectedDataItem>
- </TypeId>
- </typeIds>
- </CipRRData>
- </EipPacket>
- </outgoing-plc-message>
- <incoming-plc-message name="Get CipReadResponse from PLC">
- <parser-arguments>
- <response>true</response>
- </parser-arguments>
- <EipPacket>
- <command dataType="uint" bitLength="16">111</command>
- <packetLength dataType="uint" bitLength="16">36</packetLength>
- <sessionHandle dataType="uint" bitLength="32">1074224669</sessionHandle>
- <status dataType="uint" bitLength="32">0</status>
- <senderContext dataType="byte" bitLength="64">0x504c433458202020</senderContext>
- <options dataType="uint" bitLength="32">0</options>
- <CipRRData>
- <interfaceHandle dataType="uint" bitLength="32">0</interfaceHandle>
- <timeout dataType="uint" bitLength="16">0</timeout>
- <typeIdCount dataType="uint" bitLength="16">2</typeIdCount>
- <typeIds isList="true">
- <TypeId>
- <id dataType="uint" bitLength="16">0</id>
- <NullAddressItem>
- <reserved dataType="uint" bitLength="16">0</reserved>
- </NullAddressItem>
- </TypeId>
- <TypeId>
- <id dataType="uint" bitLength="16">178</id>
- <UnConnectedDataItem>
- <packetSize dataType="uint" bitLength="16">10</packetSize>
- <service>
- <CipService>
- <response dataType="bit" bitLength="1">true</response>
- <service dataType="uint" bitLength="7">76</service>
- <CipReadResponse>
- <reserved dataType="uint" bitLength="8">0</reserved>
- <status dataType="uint" bitLength="8">0</status>
- <extStatus dataType="uint" bitLength="8">0</extStatus>
- <data>
- <CIPData>
- <dataType>
- <CIPDataTypeCode dataType="uint" bitLength="16" stringRepresentation="DINT">196
- </CIPDataTypeCode>
- </dataType>
- <data dataType="byte" bitLength="32">0x00000216</data>
- </CIPData>
- </data>
- </CipReadResponse>
- </CipService>
- </service>
- </UnConnectedDataItem>
- </TypeId>
- </typeIds>
- </CipRRData>
- </EipPacket>
- </incoming-plc-message>
- <outgoing-plc-message name="Send CipReadRequest to PLC">
- <parser-arguments>
- <response>false</response>
- </parser-arguments>
- <EipPacket>
- <command dataType="uint" bitLength="16">111</command>
- <packetLength dataType="uint" bitLength="16">42</packetLength>
- <sessionHandle dataType="uint" bitLength="32">1074224669</sessionHandle>
- <status dataType="uint" bitLength="32">0</status>
- <senderContext dataType="byte" bitLength="64">0x504c433458202020</senderContext>
- <options dataType="uint" bitLength="32">0</options>
- <CipRRData>
- <interfaceHandle dataType="uint" bitLength="32">0</interfaceHandle>
- <timeout dataType="uint" bitLength="16">0</timeout>
- <typeIdCount dataType="uint" bitLength="16">2</typeIdCount>
- <typeIds isList="true">
- <TypeId>
- <id dataType="uint" bitLength="16">0</id>
- <NullAddressItem>
- <reserved dataType="uint" bitLength="16">0</reserved>
- </NullAddressItem>
- </TypeId>
- <TypeId>
- <id dataType="uint" bitLength="16">178</id>
- <UnConnectedDataItem>
- <packetSize dataType="uint" bitLength="16">26</packetSize>
- <service>
- <CipService>
- <response dataType="bit" bitLength="1">false</response>
- <service dataType="uint" bitLength="7">82</service>
- <CipUnconnectedRequest>
- <requestPathSize dataType="uint" bitLength="8">2</requestPathSize>
- <classSegment>
- <PathSegment>
- <pathSegment dataType="uint" bitLength="3">1</pathSegment>
- <LogicalSegment>
- <segmentType>
- <LogicalSegmentType>
- <logicalSegmentType dataType="uint" bitLength="3">0</logicalSegmentType>
- <ClassID>
- <format dataType="uint" bitLength="2">0</format>
- <segmentClass dataType="uint" bitLength="8">6</segmentClass>
- </ClassID>
- </LogicalSegmentType>
- </segmentType>
- </LogicalSegment>
- </PathSegment>
- </classSegment>
- <instanceSegment>
- <PathSegment>
- <pathSegment dataType="uint" bitLength="3">1</pathSegment>
- <LogicalSegment>
- <segmentType>
- <LogicalSegmentType>
- <logicalSegmentType dataType="uint" bitLength="3">1</logicalSegmentType>
- <InstanceID>
- <format dataType="uint" bitLength="2">0</format>
- <instance dataType="uint" bitLength="8">1</instance>
- </InstanceID>
- </LogicalSegmentType>
- </segmentType>
- </LogicalSegment>
- </PathSegment>
- </instanceSegment>
- <reserved dataType="uint" bitLength="16">40197</reserved>
- <messageSize dataType="uint" bitLength="16">12</messageSize>
- <unconnectedService>
- <CipService>
- <response dataType="bit" bitLength="1">false</response>
- <service dataType="uint" bitLength="7">76</service>
- <CipReadRequest>
- <requestPathSize dataType="uint" bitLength="8">4</requestPathSize>
- <tag dataType="byte" bitLength="64">0x9105636f756e7400</tag>
- <elementNb dataType="uint" bitLength="16">1</elementNb>
- </CipReadRequest>
- </CipService>
- </unconnectedService>
- <route dataType="uint" bitLength="16">1</route>
- <backPlane dataType="int" bitLength="8">1</backPlane>
- <slot dataType="int" bitLength="8">0</slot>
- </CipUnconnectedRequest>
- </CipService>
- </service>
- </UnConnectedDataItem>
- </TypeId>
- </typeIds>
- </CipRRData>
- </EipPacket>
- </outgoing-plc-message>
- <incoming-plc-message name="Get CipReadResponse from PLC">
- <parser-arguments>
- <response>true</response>
- </parser-arguments>
- <EipPacket>
- <command dataType="uint" bitLength="16">111</command>
- <packetLength dataType="uint" bitLength="16">36</packetLength>
- <sessionHandle dataType="uint" bitLength="32">1074224669</sessionHandle>
- <status dataType="uint" bitLength="32">0</status>
- <senderContext dataType="byte" bitLength="64">0x504c433458202020</senderContext>
- <options dataType="uint" bitLength="32">0</options>
- <CipRRData>
- <interfaceHandle dataType="uint" bitLength="32">0</interfaceHandle>
- <timeout dataType="uint" bitLength="16">0</timeout>
- <typeIdCount dataType="uint" bitLength="16">2</typeIdCount>
- <typeIds isList="true">
- <TypeId>
- <id dataType="uint" bitLength="16">0</id>
- <NullAddressItem>
- <reserved dataType="uint" bitLength="16">0</reserved>
- </NullAddressItem>
- </TypeId>
- <TypeId>
- <id dataType="uint" bitLength="16">178</id>
- <UnConnectedDataItem>
- <packetSize dataType="uint" bitLength="16">10</packetSize>
- <service>
- <CipService>
- <response dataType="bit" bitLength="1">true</response>
- <service dataType="uint" bitLength="7">76</service>
- <CipReadResponse>
- <reserved dataType="uint" bitLength="8">0</reserved>
- <status dataType="uint" bitLength="8">0</status>
- <extStatus dataType="uint" bitLength="8">0</extStatus>
- <data>
- <CIPData>
- <dataType>
- <CIPDataTypeCode dataType="uint" bitLength="16" stringRepresentation="DINT">196
- </CIPDataTypeCode>
- </dataType>
- <data dataType="byte" bitLength="32">0x2a000000</data>
- </CIPData>
- </data>
- </CipReadResponse>
- </CipService>
- </service>
- </UnConnectedDataItem>
- </TypeId>
- </typeIds>
- </CipRRData>
- </EipPacket>
- </incoming-plc-message>
- <api-response name="Report Read Response to application">
- <PlcReadResponse>
- <request>
- <PlcReadRequest>
- <PlcTagRequest>
- <tags isList="true">
- <hurz1>
- <PlcTagItem>
- <tag>
- <EipTag>
- <node dataType="string" bitLength="32" encoding="UTF8">rate</node>
- <type dataType="string" bitLength="32" encoding="UTF8">DINT</type>
- <elementNb dataType="uint" bitLength="16">1</elementNb>
- </EipTag>
- </tag>
- </PlcTagItem>
- </hurz1>
- <hurz2>
- <PlcTagItem>
- <tag>
- <EipTag>
- <node dataType="string" bitLength="40" encoding="UTF8">count</node>
- <type dataType="string" bitLength="32" encoding="UTF8">DINT</type>
- <elementNb dataType="uint" bitLength="16">1</elementNb>
- </EipTag>
- </tag>
- </PlcTagItem>
- </hurz2>
- </tags>
- </PlcTagRequest>
- </PlcReadRequest>
- </request>
- <values isList="true">
- <hurz1>
- <PlcResponseItem>
- <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
- <value>
- <PlcDINT dataType="int" bitLength="32">369229824</PlcDINT>
- </value>
- </PlcResponseItem>
- </hurz1>
- <hurz2>
- <PlcResponseItem>
- <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
- <value>
- <PlcDINT dataType="int" bitLength="32">42</PlcDINT>
- </value>
- </PlcResponseItem>
- </hurz2>
- </values>
- </PlcReadResponse>
- </api-response>
- </steps>
- </testcase>
-
- <testcase>
- <name>Array read request</name>
- <steps>
- <api-request name="Receive Read Request from application">
- <TestReadRequest>
- <tags isList="true">
- <tag className="org.apache.plc4x.test.driver.internal.api.TestTag">
- <name>hurz</name>
- <address>%rate:DINT:4</address>
- </tag>
- </tags>
- </TestReadRequest>
- </api-request>
- <outgoing-plc-message name="Send CipReadRequest to PLC">
+ <outgoing-plc-message name="Send GetAttributeSingleRequest">
<parser-arguments>
<response>false</response>
</parser-arguments>
<EipPacket>
<command dataType="uint" bitLength="16">111</command>
- <packetLength dataType="uint" bitLength="16">40</packetLength>
+ <packetLength dataType="uint" bitLength="16">22</packetLength>
<sessionHandle dataType="uint" bitLength="32">1074224669</sessionHandle>
<status dataType="uint" bitLength="32">0</status>
<senderContext dataType="byte" bitLength="64">0x504c433458202020</senderContext>
@@ -819,13 +455,13 @@
<TypeId>
<id dataType="uint" bitLength="16">178</id>
<UnConnectedDataItem>
- <packetSize dataType="uint" bitLength="16">24</packetSize>
+ <packetSize dataType="uint" bitLength="16">8</packetSize>
<service>
<CipService>
<response dataType="bit" bitLength="1">false</response>
- <service dataType="uint" bitLength="7">82</service>
- <CipUnconnectedRequest>
- <requestPathSize dataType="uint" bitLength="8">2</requestPathSize>
+ <service dataType="uint" bitLength="7">14</service>
+ <GetAttributeSingleRequest>
+ <requestPathSize dataType="uint" bitLength="8">3</requestPathSize>
<classSegment>
<PathSegment>
<pathSegment dataType="uint" bitLength="3">1</pathSegment>
@@ -835,7 +471,7 @@
<logicalSegmentType dataType="uint" bitLength="3">0</logicalSegmentType>
<ClassID>
<format dataType="uint" bitLength="2">0</format>
- <segmentClass dataType="uint" bitLength="8">6</segmentClass>
+ <segmentClass dataType="uint" bitLength="8">1</segmentClass>
</ClassID>
</LogicalSegmentType>
</segmentType>
@@ -858,224 +494,23 @@
</LogicalSegment>
</PathSegment>
</instanceSegment>
- <reserved dataType="uint" bitLength="16">40197</reserved>
- <messageSize dataType="uint" bitLength="16">10</messageSize>
- <unconnectedService>
- <CipService>
- <response dataType="bit" bitLength="1">false</response>
- <service dataType="uint" bitLength="7">76</service>
- <CipReadRequest>
- <requestPathSize dataType="uint" bitLength="8">3</requestPathSize>
- <tag dataType="byte" bitLength="48">0x910472617465</tag>
- <elementNb dataType="uint" bitLength="16">4</elementNb>
- </CipReadRequest>
- </CipService>
- </unconnectedService>
- <route dataType="uint" bitLength="16">1</route>
- <backPlane dataType="int" bitLength="8">1</backPlane>
- <slot dataType="int" bitLength="8">0</slot>
- </CipUnconnectedRequest>
- </CipService>
- </service>
- </UnConnectedDataItem>
- </TypeId>
- </typeIds>
- </CipRRData>
- </EipPacket>
- </outgoing-plc-message>
- <incoming-plc-message name="Get CipReadResponse from PLC">
- <parser-arguments>
- <response>true</response>
- </parser-arguments>
- <EipPacket>
- <command dataType="uint" bitLength="16">111</command>
- <packetLength dataType="uint" bitLength="16">48</packetLength>
- <sessionHandle dataType="uint" bitLength="32">1074224669</sessionHandle>
- <status dataType="uint" bitLength="32">0</status>
- <senderContext dataType="byte" bitLength="64">0x504c433458202020</senderContext>
- <options dataType="uint" bitLength="32">0</options>
- <CipRRData>
- <interfaceHandle dataType="uint" bitLength="32">0</interfaceHandle>
- <timeout dataType="uint" bitLength="16">0</timeout>
- <typeIdCount dataType="uint" bitLength="16">2</typeIdCount>
- <typeIds isList="true">
- <TypeId>
- <id dataType="uint" bitLength="16">0</id>
- <NullAddressItem>
- <reserved dataType="uint" bitLength="16">0</reserved>
- </NullAddressItem>
- </TypeId>
- <TypeId>
- <id dataType="uint" bitLength="16">178</id>
- <UnConnectedDataItem>
- <packetSize dataType="uint" bitLength="16">22</packetSize>
- <service>
- <CipService>
- <response dataType="bit" bitLength="1">true</response>
- <service dataType="uint" bitLength="7">76</service>
- <CipReadResponse>
- <reserved dataType="uint" bitLength="8">0</reserved>
- <status dataType="uint" bitLength="8">0</status>
- <extStatus dataType="uint" bitLength="8">0</extStatus>
- <data>
- <CIPData>
- <dataType>
- <CIPDataTypeCode dataType="uint" bitLength="16" stringRepresentation="DINT">196
- </CIPDataTypeCode>
- </dataType>
- <data dataType="byte" bitLength="128">0x01000000020000000300000004000000</data>
- </CIPData>
- </data>
- </CipReadResponse>
- </CipService>
- </service>
- </UnConnectedDataItem>
- </TypeId>
- </typeIds>
- </CipRRData>
- </EipPacket>
- </incoming-plc-message>
- <api-response name="Report Read Response to application">
- <PlcReadResponse>
- <request>
- <PlcReadRequest>
- <PlcTagRequest>
- <tags isList="true">
- <hurz>
- <PlcTagItem>
- <tag>
- <EipTag>
- <node dataType="string" bitLength="32" encoding="UTF8">rate</node>
- <type dataType="string" bitLength="32" encoding="UTF8">DINT</type>
- <elementNb dataType="uint" bitLength="16">4</elementNb>
- </EipTag>
- </tag>
- </PlcTagItem>
- </hurz>
- </tags>
- </PlcTagRequest>
- </PlcReadRequest>
- </request>
- <values isList="true">
- <hurz>
- <PlcResponseItem>
- <code dataType="string" bitLength="16" encoding="UTF-8">OK</code>
- <value>
- <PlcList>
- <PlcDINT dataType="int" bitLength="32">1</PlcDINT>
- <PlcDINT dataType="int" bitLength="32">2</PlcDINT>
- <PlcDINT dataType="int" bitLength="32">3</PlcDINT>
- <PlcDINT dataType="int" bitLength="32">4</PlcDINT>
- </PlcList>
- </value>
- </PlcResponseItem>
- </hurz>
- </values>
- </PlcReadResponse>
- </api-response>
- </steps>
- </testcase>
-
- <testcase>
- <name>Single element write request</name>
- <steps>
- <api-request name="Receive Write Request from application">
- <TestWriteRequest>
- <tags isList="true">
- <tag className="org.apache.plc4x.test.driver.internal.api.TestValueTag">
- <name>hurz</name>
- <address>%rate:DINT</address>
- <value>369229824</value>
- </tag>
- </tags>
- </TestWriteRequest>
- </api-request>
- <outgoing-plc-message name="Send CipWriteRequest to PLC">
- <parser-arguments>
- <response>false</response>
- </parser-arguments>
- <EipPacket>
- <command dataType="uint" bitLength="16">111</command>
- <packetLength dataType="uint" bitLength="16">44</packetLength>
- <sessionHandle dataType="uint" bitLength="32">1074224669</sessionHandle>
- <status dataType="uint" bitLength="32">0</status>
- <senderContext dataType="byte" bitLength="64">0x504c433458202020</senderContext>
- <options dataType="uint" bitLength="32">0</options>
- <CipRRData>
- <interfaceHandle dataType="uint" bitLength="32">0</interfaceHandle>
- <timeout dataType="uint" bitLength="16">0</timeout>
- <typeIdCount dataType="uint" bitLength="16">2</typeIdCount>
- <typeIds isList="true">
- <TypeId>
- <id dataType="uint" bitLength="16">0</id>
- <NullAddressItem>
- <reserved dataType="uint" bitLength="16">0</reserved>
- </NullAddressItem>
- </TypeId>
- <TypeId>
- <id dataType="uint" bitLength="16">178</id>
- <UnConnectedDataItem>
- <packetSize dataType="uint" bitLength="16">28</packetSize>
- <service>
- <CipService>
- <response dataType="bit" bitLength="1">false</response>
- <service dataType="uint" bitLength="7">82</service>
- <CipUnconnectedRequest>
- <requestPathSize dataType="uint" bitLength="8">2</requestPathSize>
- <classSegment>
- <PathSegment>
- <pathSegment dataType="uint" bitLength="3">1</pathSegment>
- <LogicalSegment>
- <segmentType>
- <LogicalSegmentType>
- <logicalSegmentType dataType="uint" bitLength="3">0</logicalSegmentType>
- <ClassID>
- <format dataType="uint" bitLength="2">0</format>
- <segmentClass dataType="uint" bitLength="8">6</segmentClass>
- </ClassID>
- </LogicalSegmentType>
- </segmentType>
- </LogicalSegment>
- </PathSegment>
- </classSegment>
- <instanceSegment>
+ <attributeSegment>
<PathSegment>
<pathSegment dataType="uint" bitLength="3">1</pathSegment>
<LogicalSegment>
<segmentType>
<LogicalSegmentType>
- <logicalSegmentType dataType="uint" bitLength="3">1</logicalSegmentType>
- <InstanceID>
+ <logicalSegmentType dataType="uint" bitLength="3">4</logicalSegmentType>
+ <AttributeID>
<format dataType="uint" bitLength="2">0</format>
- <instance dataType="uint" bitLength="8">1</instance>
- </InstanceID>
+ <attribute dataType="uint" bitLength="8">1</attribute>
+ </AttributeID>
</LogicalSegmentType>
</segmentType>
</LogicalSegment>
</PathSegment>
- </instanceSegment>
- <reserved dataType="uint" bitLength="16">40197</reserved>
- <messageSize dataType="uint" bitLength="16">14</messageSize>
- <unconnectedService>
- <CipService>
- <response dataType="bit" bitLength="1">false</response>
- <service dataType="uint" bitLength="7">77</service>
- <CipWriteRequest>
- <requestPathSize dataType="uint" bitLength="8">3</requestPathSize>
- <tag dataType="byte" bitLength="48">0x910472617465</tag>
- <dataType>
- <CIPDataTypeCode dataType="uint" bitLength="16" stringRepresentation="DINT">196
- </CIPDataTypeCode>
- </dataType>
- <elementNb dataType="uint" bitLength="16">1</elementNb>
- <data dataType="byte" bitLength="32">0x00000216</data>
- </CipWriteRequest>
- </CipService>
- </unconnectedService>
- <route dataType="uint" bitLength="16">1</route>
- <backPlane dataType="int" bitLength="8">1</backPlane>
- <slot dataType="int" bitLength="8">0</slot>
- </CipUnconnectedRequest>
+ </attributeSegment>
+ </GetAttributeSingleRequest>
</CipService>
</service>
</UnConnectedDataItem>
@@ -1084,13 +519,13 @@
</CipRRData>
</EipPacket>
</outgoing-plc-message>
- <incoming-plc-message name="Get CipWriteResponse from PLC">
+ <incoming-plc-message name="Receive GetAttributeSingleResponse">
<parser-arguments>
<response>true</response>
</parser-arguments>
<EipPacket>
<command dataType="uint" bitLength="16">111</command>
- <packetLength dataType="uint" bitLength="16">28</packetLength>
+ <packetLength dataType="uint" bitLength="16">22</packetLength>
<sessionHandle dataType="uint" bitLength="32">1074224669</sessionHandle>
<status dataType="uint" bitLength="32">0</status>
<senderContext dataType="byte" bitLength="64">0x504c433458202020</senderContext>
@@ -1109,16 +544,18 @@
<TypeId>
<id dataType="uint" bitLength="16">178</id>
<UnConnectedDataItem>
- <packetSize dataType="uint" bitLength="16">4</packetSize>
+ <packetSize dataType="uint" bitLength="16">6</packetSize>
<service>
<CipService>
<response dataType="bit" bitLength="1">true</response>
- <service dataType="uint" bitLength="7">77</service>
- <CipWriteResponse>
+ <service dataType="uint" bitLength="7">14</service>
+ <GetAttributeSingleResponse>
<reserved dataType="uint" bitLength="8">0</reserved>
<status dataType="uint" bitLength="8">0</status>
- <extStatus dataType="uint" bitLength="8">0</extStatus>
- </CipWriteResponse>
+ <extStatusSize dataType="uint" bitLength="16">0</extStatusSize>
+ <extStatus isList="true"/>
+ <servicesData dataType="byte" bitLength="16">0x0100</servicesData>
+ </GetAttributeSingleResponse>
</CipService>
</service>
</UnConnectedDataItem>
@@ -1127,39 +564,6 @@
</CipRRData>
</EipPacket>
</incoming-plc-message>
- <api-response name="Report Write Response to application">
- <PlcWriteResponse>
- <request>
- <PlcWriteRequest>
- <PlcTagRequest>
- <tags isList="true">
- <hurz>
- <PlcTagItem>
- <tag>
- <EipTag>
- <node dataType="string" bitLength="32" encoding="UTF8">rate</node>
- <type dataType="string" bitLength="32" encoding="UTF8">DINT</type>
- <elementNb dataType="uint" bitLength="16">1</elementNb>
- </EipTag>
- </tag>
- </PlcTagItem>
- </hurz>
- </tags>
- </PlcTagRequest>
- <values isList="true">
- <hurz>
- <PlcDINT dataType="int" bitLength="32">369229824</PlcDINT>
- </hurz>
- </values>
- </PlcWriteRequest>
- </request>
- <responseCodes isList="true">
- <hurz>
- <ResponseCode dataType="uint" bitLength="8" stringRepresentation="OK">1</ResponseCode>
- </hurz>
- </responseCodes>
- </PlcWriteResponse>
- </api-response>
</steps>
</testcase>