You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by hu...@apache.org on 2022/06/22 06:50:06 UTC
[plc4x] branch eip_update created (now 3a4f7d4667)
This is an automated email from the ASF dual-hosted git repository.
hutcheb pushed a change to branch eip_update
in repository https://gitbox.apache.org/repos/asf/plc4x.git
at 3a4f7d4667 Merged Logix Develop with EIP
This branch includes the following new commits:
new 3a4f7d4667 Merged Logix Develop with EIP
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
[plc4x] 01/01: Merged Logix Develop with EIP
Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
hutcheb pushed a commit to branch eip_update
in repository https://gitbox.apache.org/repos/asf/plc4x.git
commit 3a4f7d46674a9c3f2b1ed44f365ae21f81329cba
Author: Ben Hutcheson <be...@gmail.com>
AuthorDate: Wed Jun 22 16:49:21 2022 +1000
Merged Logix Develop with EIP
---
.../readwrite/configuration/EIPConfiguration.java | 10 +
.../plc4x/java/eip/readwrite/field/EipField.java | 2 +
.../eip/readwrite/protocol/EipProtocolLogic.java | 554 +++++++++++++--------
.../java/eip/readwrite/EIPDriverTestsuite.java | 2 +-
.../eip/readwrite/EIPParserSerializerTest.java | 2 +-
.../eip/src/test/resources/logback-test.xml | 2 +-
.../eip/src/main/resources/protocols/eip/eip.mspec | 273 ++++++++--
.../resources/protocols/eip/DriverTestsuite.xml | 12 +
.../protocols/eip/ParserSerializerTestsuite.xml | 456 ++++++++++-------
9 files changed, 903 insertions(+), 410 deletions(-)
diff --git a/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/readwrite/configuration/EIPConfiguration.java b/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/readwrite/configuration/EIPConfiguration.java
index f34f2d9229..e86433ff04 100644
--- a/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/readwrite/configuration/EIPConfiguration.java
+++ b/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/readwrite/configuration/EIPConfiguration.java
@@ -19,10 +19,13 @@
package org.apache.plc4x.java.eip.readwrite.configuration;
import org.apache.plc4x.java.eip.readwrite.EIPDriver;
+import org.apache.plc4x.java.eip.readwrite.IntegerEncoding;
import org.apache.plc4x.java.spi.configuration.Configuration;
import org.apache.plc4x.java.spi.configuration.annotations.ConfigurationParameter;
import org.apache.plc4x.java.transport.tcp.TcpTransportConfiguration;
+import java.nio.ByteOrder;
+
public class EIPConfiguration implements Configuration, TcpTransportConfiguration {
@ConfigurationParameter
@@ -31,6 +34,9 @@ public class EIPConfiguration implements Configuration, TcpTransportConfiguratio
@ConfigurationParameter
private int slot;
+ @ConfigurationParameter
+ private IntegerEncoding byteOrder = IntegerEncoding.BIG_ENDIAN;
+
public int getBackplane() {
return backplane;
}
@@ -47,6 +53,10 @@ public class EIPConfiguration implements Configuration, TcpTransportConfiguratio
this.slot = slot;
}
+ public IntegerEncoding getByteOrder() { return this.byteOrder; }
+
+ public void setByteOrder(IntegerEncoding byteOrder) { this.byteOrder = byteOrder; }
+
@Override
public int getDefaultPort(){return EIPDriver.PORT;}
diff --git a/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/readwrite/field/EipField.java b/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/readwrite/field/EipField.java
index ec9cd6644b..b3816a648d 100644
--- a/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/readwrite/field/EipField.java
+++ b/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/readwrite/field/EipField.java
@@ -97,6 +97,8 @@ public class EipField implements PlcField, Serializable {
}
if (!matcher.group(TYPE).isEmpty()) {
type = CIPDataTypeCode.valueOf(matcher.group(TYPE));
+ } else {
+ type = CIPDataTypeCode.DINT;
}
if (nb != 0) {
if (type != null) {
diff --git a/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/readwrite/protocol/EipProtocolLogic.java b/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/readwrite/protocol/EipProtocolLogic.java
index 6380a96f7d..0db2c5820b 100644
--- a/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/readwrite/protocol/EipProtocolLogic.java
+++ b/plc4j/drivers/eip/src/main/java/org/apache/plc4x/java/eip/readwrite/protocol/EipProtocolLogic.java
@@ -31,9 +31,7 @@ import org.apache.plc4x.java.eip.readwrite.field.EipField;
import org.apache.plc4x.java.spi.ConversationContext;
import org.apache.plc4x.java.spi.Plc4xProtocolBase;
import org.apache.plc4x.java.spi.configuration.HasConfiguration;
-import org.apache.plc4x.java.spi.generation.ParseException;
-import org.apache.plc4x.java.spi.generation.ReadBuffer;
-import org.apache.plc4x.java.spi.generation.ReadBufferByteBased;
+import org.apache.plc4x.java.spi.generation.*;
import org.apache.plc4x.java.spi.messages.*;
import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
import org.apache.plc4x.java.spi.transaction.RequestTransactionManager;
@@ -48,15 +46,22 @@ import java.time.Duration;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
public class EipProtocolLogic extends Plc4xProtocolBase<EipPacket> implements HasConfiguration<EIPConfiguration> {
private static final Logger logger = LoggerFactory.getLogger(EipProtocolLogic.class);
public static final Duration REQUEST_TIMEOUT = Duration.ofMillis(10000);
- private static final List<Short> emptySenderContext = Arrays.asList((short) 0x00, (short) 0x00, (short) 0x00,
- (short) 0x00, (short) 0x00, (short) 0x00, (short) 0x00, (short) 0x00);
- private List<Short> senderContext;
+ private static final byte[] DEFAULT_SENDER_CONTEXT = "PLC4X ".getBytes(StandardCharsets.US_ASCII);
+ private static final long EMPTY_SESSION_HANDLE = 0L;
+ private static final long EMPTY_INTERFACE_HANDLE = 0L;
+
+ private byte[] senderContext;
+
+ private long connectionId = 0L;
+ private int sequenceCount = 1;
private EIPConfiguration configuration;
private final AtomicInteger transactionCounterGenerator = new AtomicInteger(10);
@@ -72,16 +77,110 @@ public class EipProtocolLogic extends Plc4xProtocolBase<EipPacket> implements Ha
@Override
public void onConnect(ConversationContext<EipPacket> context) {
- logger.debug("Sending RegisterSession EIP Package");
+ logger.debug("Sending Register Session EIP Package");
EipConnectionRequest connectionRequest =
- new EipConnectionRequest(0L, 0L, emptySenderContext, 0L);
+ new EipConnectionRequest(
+ EMPTY_SESSION_HANDLE,
+ CIPStatus.Success.getValue(),
+ DEFAULT_SENDER_CONTEXT,
+ 0L,
+ this.configuration.getByteOrder());
context.sendRequest(connectionRequest)
.expectResponse(EipPacket.class, REQUEST_TIMEOUT).unwrap(p -> p)
.check(p -> p instanceof EipConnectionRequest)
.handle(p -> {
- if (p.getStatus() == 0L) {
+ if (p.getStatus() == CIPStatus.Success.getValue()) {
sessionHandle = p.getSessionHandle();
senderContext = p.getSenderContext();
+ logger.debug("Got assigned with Session {}", sessionHandle);
+ onConnectOpenConnectionManager(context, p);
+
+ } else {
+ logger.warn("Got status code [{}]", p.getStatus());
+ }
+ });
+ }
+
+ public void onConnectOpenConnectionManager(ConversationContext<EipPacket> context, EipPacket response) {
+ logger.debug("Sending Open Connection Manager EIP Package");
+
+ PathSegment classSegment = new LogicalSegment(new ClassID((byte) 0, (short) 6, this.configuration.getByteOrder()), this.configuration.getByteOrder());
+ PathSegment instanceSegment = new LogicalSegment(new InstanceID((byte) 0, (short) 1, this.configuration.getByteOrder()), this.configuration.getByteOrder());
+
+ UnConnectedDataItem exchange = new UnConnectedDataItem(
+ new CipConnectionManagerRequest(
+ classSegment,
+ instanceSegment,
+ (byte) 0,
+ (byte) 10,
+ (short) 14,
+ 536870914L,
+ 33944L,
+ 8592,
+ 4919,
+ 42L,
+ (short) 3,
+ 2101812L,
+ new NetworkConnectionParameters(
+ 4002,
+ false,
+ (byte) 2,
+ (byte) 0,
+ true,
+ this.configuration.getByteOrder()
+ ),
+ (long) 2113537,
+ new NetworkConnectionParameters(
+ 4002,
+ false,
+ (byte) 2,
+ (byte) 0,
+ true,
+ this.configuration.getByteOrder()
+ ),
+ new TransportType(true, (byte) 2, (byte) 3, this.configuration.getByteOrder()),
+ (short) 3,
+ new PortSegment(false, (byte) 1, (short) 0, this.configuration.getByteOrder()),
+ new LogicalSegment(new ClassID((byte) 0, (short) 2, this.configuration.getByteOrder()), this.configuration.getByteOrder()),
+ new LogicalSegment(new InstanceID((byte) 0, (short) 1, this.configuration.getByteOrder()), this.configuration.getByteOrder()),
+ (int) 0,
+ this.configuration.getByteOrder()
+ ),
+ this.configuration.getByteOrder()
+ );
+
+ List<TypeId> typeIds = new ArrayList<TypeId>() {
+ {
+ add(exchange);
+ }
+ };
+
+ CipRRData eipWrapper = new CipRRData(
+ sessionHandle,
+ response.getStatus(),
+ senderContext,
+ 0L,
+ EMPTY_INTERFACE_HANDLE,
+ 0,
+ 2,
+ typeIds,
+ this.configuration.getByteOrder(),
+ -1
+ );
+
+
+ context.sendRequest(eipWrapper)
+ .expectResponse(EipPacket.class, REQUEST_TIMEOUT).unwrap(p -> p)
+ .check(p -> p instanceof CipRRData)
+ .handle(p -> {
+ if (p.getStatus() == 0L) {
+ CipRRData rrData = (CipRRData) p;
+ sessionHandle = rrData.getSessionHandle();
+ senderContext = rrData.getSenderContext();
+ List<TypeId> connectionManagerExchange = rrData.getTypeId();
+ CipConnectionManagerResponse connectionManagerResponse = (CipConnectionManagerResponse) ((ConnectedDataItem) connectionManagerExchange.get(0)).getService();
+ this.connectionId = connectionManagerResponse.getOtConnectionId();
+
logger.debug("Got assigned with Session {}", sessionHandle);
// Send an event that connection setup is complete.
context.fireConnected();
@@ -92,10 +191,90 @@ public class EipProtocolLogic extends Plc4xProtocolBase<EipPacket> implements Ha
});
}
+
+ @Override
+ public void onDisconnect(ConversationContext<EipPacket> context) {
+ if (this.connectionId != 0L) {
+ logger.debug("Sending Connection Manager Close Event");
+ PathSegment classSegment = new LogicalSegment(new ClassID((byte) 0, (short) 6, this.configuration.getByteOrder()), this.configuration.getByteOrder());
+ PathSegment instanceSegment = new LogicalSegment(new InstanceID((byte) 0, (short) 1, this.configuration.getByteOrder()), this.configuration.getByteOrder());
+
+ UnConnectedDataItem exchange = new UnConnectedDataItem(
+ new CipConnectionManagerCloseRequest(
+ (byte) 2,
+ classSegment,
+ instanceSegment,
+ (byte) 0,
+ (byte) 10,
+ (short) 14,
+ 8592,
+ 4919,
+ 42L,
+ (short) 3,
+ new PortSegment(false, (byte) 1, (short) 0, this.configuration.getByteOrder()),
+ new LogicalSegment(new ClassID((byte) 0, (short) 2, this.configuration.getByteOrder()), this.configuration.getByteOrder()),
+ new LogicalSegment(new InstanceID((byte) 0, (short) 1, this.configuration.getByteOrder()), this.configuration.getByteOrder()),
+ 0,
+ this.configuration.getByteOrder()
+ ),
+ this.configuration.getByteOrder()
+ );
+
+ List<TypeId> typeIds = new ArrayList<TypeId>() {
+ {
+ add(exchange);
+ }
+ };
+
+ CipRRData eipWrapper = new CipRRData(
+ sessionHandle,
+ 0L,
+ senderContext,
+ 0L,
+ EMPTY_INTERFACE_HANDLE,
+ 0,
+ 2,
+ typeIds,
+ this.configuration.getByteOrder(),
+ -1
+ );
+
+
+ context.sendRequest(eipWrapper)
+ .expectResponse(EipPacket.class, REQUEST_TIMEOUT).unwrap(p -> p)
+ .check(p -> p instanceof CipRRData)
+ .handle(p -> {
+ logger.debug("Un-Registering Session");
+ onDisconnectUnregisterSession(context);
+ });
+ } else {
+ onDisconnectUnregisterSession(context);
+ }
+ }
+
+
+ public void onDisconnectUnregisterSession(ConversationContext<EipPacket> context) {
+ logger.debug("Sending Un RegisterSession EIP Package");
+ EipDisconnectRequest connectionRequest =
+ new EipDisconnectRequest(
+ 0L,
+ sessionHandle,
+ DEFAULT_SENDER_CONTEXT,
+ 0L,
+ this.configuration.getByteOrder());
+ context.sendRequest(connectionRequest)
+ .expectResponse(EipPacket.class, Duration.ofMillis(1))
+ .onTimeout(p -> context.fireDisconnected())
+ .handle(p -> context.fireDisconnected());
+ }
+
@Override
public CompletableFuture<PlcReadResponse> read(PlcReadRequest readRequest) {
+ CompletableFuture<PlcReadResponse> future = new CompletableFuture<>();
+ RequestTransactionManager.RequestTransaction transaction = tm.startRequest();
+
DefaultPlcReadRequest request = (DefaultPlcReadRequest) readRequest;
- List<CipReadRequest> requests = new ArrayList<>(request.getNumberOfFields());
+ List<CipService> requests = new ArrayList<>(request.getNumberOfFields());
for (PlcField field : request.getFields()) {
EipField plcField = (EipField) field;
String tag = plcField.getTag();
@@ -103,171 +282,109 @@ public class EipProtocolLogic extends Plc4xProtocolBase<EipPacket> implements Ha
if (plcField.getElementNb() > 1) {
elements = plcField.getElementNb();
}
- CipReadRequest req = new CipReadRequest(getRequestSize(tag), toAnsi(tag), elements, -1);
- requests.add(req);
- }
- return toPlcReadResponse(readRequest, readInternal(requests));
- }
-
- private byte getRequestSize(String tag) {
- //We need the size of the request in words (0x91, tagLength, ... tag + possible pad)
- // Taking half to get word size
- boolean isArray = false;
- boolean isStruct = false;
- String tagIsolated = tag;
- if (tag.contains("[")) {
- isArray = true;
- tagIsolated = tag.substring(0, tag.indexOf("["));
+ try {
+ CipReadRequest req = new CipReadRequest(
+ toAnsi(tag, this.configuration.getByteOrder()),
+ 1,
+ -1,
+ this.configuration.getByteOrder());
+ requests.add(req);
+ } catch (SerializationException e) {
+ e.printStackTrace();
+ }
}
- if (tag.contains(".")) {
- isStruct = true;
- tagIsolated = tagIsolated.replace(".", "");
- }
- int dataLength = (tagIsolated.length() + 2)
- + (tagIsolated.length() % 2)
- + (isArray ? 2 : 0)
- + (isStruct ? 2 : 0);
- byte requestPathSize = (byte) (dataLength / 2);
- return requestPathSize;
- }
+ List<TypeId> typeIds =new ArrayList<>(2);
+ typeIds.add(new ConnectedAddressItem(this.connectionId, this.configuration.getByteOrder()));
+ if (requests.size() == 1) {
+ typeIds.add(new ConnectedDataItem(this.sequenceCount, requests.get(0), this.configuration.getByteOrder()));
+ } else {
+ List<Integer> offsets = new ArrayList<>(requests.size());
+ offsets.add(6);
+ for (CipService cipRequest : requests) {
+ if (requests.indexOf(cipRequest) != (requests.size() - 1)) {
+ offsets.add(offsets.get(requests.indexOf(cipRequest)) + cipRequest.getLengthInBytes());
+ }
- private byte[] toAnsi(String tag) {
- int arrayIndex = 0;
- boolean isArray = false;
- boolean isStruct = false;
- String tagFinal = tag;
- if (tag.contains("[")) {
- isArray = true;
- String index = tag.substring(tag.indexOf("[") + 1, tag.indexOf("]"));
- arrayIndex = Integer.parseInt(index);
- tagFinal = tag.substring(0, tag.indexOf("["));
- }
- if (tag.contains(".")) {
- tagFinal = tag.substring(0, tag.indexOf("."));
- isStruct = true;
- }
- boolean isPadded = tagFinal.length() % 2 != 0;
- int dataSegLength = 2 + tagFinal.length()
- + (isPadded ? 1 : 0)
- + (isArray ? 2 : 0);
-
- if (isStruct) {
- for (String subStr : tag.substring(tag.indexOf(".") + 1).split("\\.", -1)) {
- dataSegLength += 2 + subStr.length() + subStr.length() % 2;
}
+ MultipleServiceRequest serviceRequest = new MultipleServiceRequest(new Services(requests.size(), offsets, requests, 0, this.configuration.getByteOrder()), 0, this.configuration.getByteOrder());
+ typeIds.add(new ConnectedDataItem(this.sequenceCount, serviceRequest, this.configuration.getByteOrder()));
}
- ByteBuffer buffer = ByteBuffer.allocate(dataSegLength).order(ByteOrder.LITTLE_ENDIAN);
-
- buffer.put((byte) 0x91);
- buffer.put((byte) tagFinal.length());
- byte[] tagBytes = null;
- tagBytes = tagFinal.getBytes(StandardCharsets.US_ASCII);
-
- buffer.put(tagBytes);
- buffer.position(2 + tagBytes.length);
+ SendUnitData pkt = new SendUnitData(
+ sessionHandle,
+ CIPStatus.Success.getValue(),
+ DEFAULT_SENDER_CONTEXT,
+ 0L,
+ 0,
+ 2,
+ typeIds,
+ this.configuration.getByteOrder()
+ );
+
+ transaction.submit(() -> context.sendRequest(pkt)
+ .expectResponse(EipPacket.class, REQUEST_TIMEOUT)
+ .onTimeout(future::completeExceptionally)
+ .onError((p, e) -> future.completeExceptionally(e))
+ .check(p -> p instanceof SendUnitData)
+ .check(p -> p.getSessionHandle() == sessionHandle)
+ //.check(p -> p.getSenderContext() == senderContext)
+ .unwrap(p -> (SendUnitData) p)
+ .handle(p -> {
+ SendUnitData unitData = (SendUnitData) p;
+ List<TypeId> responseTypeIds = unitData.getTypeId();
+ ConnectedDataItem dataItem = (ConnectedDataItem) responseTypeIds.get(1);
+ future.complete(decodeReadResponse(dataItem.getService(), request));
+ // Finish the request-transaction.
+ transaction.endRequest();
+ }));
- if (isPadded) {
- buffer.put((byte) 0x00);
- }
-
- if (isArray) {
- buffer.put((byte) 0x28);
- buffer.put((byte) arrayIndex);
- }
- if (isStruct) {
- buffer.put(toAnsi(tag.substring(tag.indexOf(".") + 1, tag.length())));
- }
- return buffer.array();
- }
-
- private CompletableFuture<PlcReadResponse> toPlcReadResponse(PlcReadRequest readRequest, CompletableFuture<CipService> response) {
- return response
- .thenApply(p -> {
- return ((PlcReadResponse) decodeReadResponse(p, readRequest));
- });
+ return future;
}
- private CompletableFuture<CipService> readInternal(List<CipReadRequest> request) {
- CompletableFuture<CipService> future = new CompletableFuture<>();
- RequestTransactionManager.RequestTransaction transaction = tm.startRequest();
- if (request.size() > 1) {
-
- short nb = (short) request.size();
- List<Integer> offsets = new ArrayList<>(nb);
- int offset = 2 + nb * 2;
- for (int i = 0; i < nb; i++) {
- offsets.add(offset);
- offset += request.get(i).getLengthInBytes();
- }
-
- List<CipService> serviceArr = new ArrayList<>(nb);
- for (int i = 0; i < nb; i++) {
- serviceArr.add(request.get(i));
+ /*
+ Takes a Tag name e.g. ZZZ_ZZZ.XXX and returns a buffer containing an array of ANSI Extended Symbol Seqments
+ */
+ public static byte[] toAnsi(String tag, IntegerEncoding order) throws SerializationException {
+ final Pattern RESOURCE_ADDRESS_PATTERN = Pattern.compile("([.\\[\\]])*([A-Za-z_0-9]+){1}");
+ Matcher matcher = RESOURCE_ADDRESS_PATTERN.matcher(tag);
+ List<PathSegment> segments = new LinkedList<>();
+ String tagWithoutQualifiers = "";
+ int lengthBytes = 0;
+ while (matcher.find()) {
+ String identifier = matcher.group(2);
+ String qualifier = matcher.group(1);
+
+ PathSegment newSegment;
+ if (qualifier != null) {
+ switch (qualifier) {
+ case "[":
+ newSegment = new LogicalSegment(new MemberID((byte) 0x00, (short) Short.parseShort(identifier), order), order);
+ segments.add(newSegment);
+ break;
+ default:
+ newSegment = new DataSegment(new AnsiExtendedSymbolSegment(identifier, (short) 0, order), order);
+ segments.add(newSegment);
+ tagWithoutQualifiers += identifier;
+ }
+ } else {
+ newSegment = new DataSegment(new AnsiExtendedSymbolSegment(identifier, (short) 0, order), order);
+ segments.add(newSegment);
+ tagWithoutQualifiers += identifier;
}
- Services data = new Services(nb, offsets, serviceArr, -1);
- //Encapsulate the data
-
- CipRRData pkt = new CipRRData(sessionHandle, 0L, emptySenderContext, 0L,
- new CipExchange(
- new CipUnconnectedRequest(
- new MultipleServiceRequest(data, -1),
- (byte) configuration.getBackplane(),
- (byte) configuration.getSlot(),
- -1
- ),
- -1
- ),
- -1
- );
+ lengthBytes += newSegment.getLengthInBytes();
+ }
+ WriteBufferByteBased buffer = new WriteBufferByteBased(lengthBytes, org.apache.plc4x.java.spi.generation.ByteOrder.LITTLE_ENDIAN);
- transaction.submit(() -> context.sendRequest(pkt)
- .expectResponse(EipPacket.class, REQUEST_TIMEOUT)
- .onTimeout(future::completeExceptionally)
- .onError((p, e) -> future.completeExceptionally(e))
- .check(p -> p instanceof CipRRData)
- .check(p -> p.getSessionHandle() == sessionHandle)
- //.check(p -> p.getSenderContext() == senderContext)
- .unwrap(p -> (CipRRData) p)
- .unwrap(p -> p.getExchange().getService()).check(p -> p instanceof MultipleServiceResponse)
- .unwrap(p -> (MultipleServiceResponse) p)
- .check(p -> p.getServiceNb() == nb)
- .handle(p -> {
- future.complete(p);
- // Finish the request-transaction.
- transaction.endRequest();
- }));
- } else if (request.size() == 1) {
- CipExchange exchange = new CipExchange(
- new CipUnconnectedRequest(
- request.get(0), (byte) configuration.getBackplane(), (byte) configuration.getSlot(), -1
- ),
- -1
- );
- CipRRData pkt = new CipRRData(sessionHandle, 0L, emptySenderContext, 0L, exchange, -1);
- transaction.submit(() -> context.sendRequest(pkt)
- .expectResponse(EipPacket.class, REQUEST_TIMEOUT)
- .onTimeout(future::completeExceptionally)
- .onError((p, e) -> future.completeExceptionally(e))
- .check(p -> p instanceof CipRRData)
- .check(p -> p.getSessionHandle() == sessionHandle)
- //.check(p -> p.getSenderContext() == senderContext)
- .unwrap(p -> (CipRRData) p)
- .unwrap(p -> p.getExchange().getService()).check(p -> p instanceof CipReadResponse)
- .unwrap(p -> (CipReadResponse) p)
- .handle(p -> {
- future.complete(p);
- // Finish the request-transaction.
- transaction.endRequest();
- }));
+ for (PathSegment segment : segments) {
+ segment.serialize(buffer);
}
- return future;
+ return buffer.getData();
}
- private PlcResponse decodeReadResponse(CipService p, PlcReadRequest readRequest) {
+ private PlcReadResponse decodeReadResponse(CipService p, PlcReadRequest readRequest) {
Map<String, ResponseItem<PlcValue>> values = new HashMap<>();
// only 1 field
if (p instanceof CipReadResponse) {
@@ -308,7 +425,7 @@ public class EipProtocolLogic extends Plc4xProtocolBase<EipPacket> implements Ha
throw new PlcRuntimeException(e);
}
}
- Services services = new Services(nb, responses.getOffsets(), arr, -1);
+ Services services = new Services(nb, responses.getOffsets(), arr, -1, this.configuration.getByteOrder());
Iterator<String> it = readRequest.getFieldNames().iterator();
for (int i = 0; i < nb && it.hasNext(); i++) {
String fieldName = it.next();
@@ -444,38 +561,53 @@ public class EipProtocolLogic extends Plc4xProtocolBase<EipPacket> implements Ha
elements = field.getElementNb();
}
- //We need the size of the request in words (0x91, tagLength, ... tag + possible pad)
- // Taking half to get word size
- boolean isArray = false;
- boolean isStruct = false;
- String tagIsolated = tag;
- if (tag.contains("[")) {
- isArray = true;
- tagIsolated = tag.substring(0, tag.indexOf("["));
- }
-
- if (tag.contains(".")) {
- isStruct = true;
- tagIsolated = tagIsolated.replace(".", "");
+ byte[] data = encodeValue(value, field.getType(), (short) elements);
+ try {
+ CipWriteRequest writeReq = new CipWriteRequest(toAnsi(tag, this.configuration.getByteOrder()), field.getType(), elements, data, -1, this.configuration.getByteOrder());
+ items.add(writeReq);
+ } catch (SerializationException e) {
+ e.printStackTrace();
}
- int dataLength = (tagIsolated.length() + 2 + ((tagIsolated.length() % 2) * 2) + (isArray ? 2 : 0) + (isStruct ? 2 : 0));
- byte requestPathSize = (byte) (dataLength / 2);
- byte[] data = encodeValue(value, field.getType(), (short) elements);
- CipWriteRequest writeReq = new CipWriteRequest(requestPathSize, toAnsi(tag), field.getType(), elements, data, -1);
- items.add(writeReq);
}
RequestTransactionManager.RequestTransaction transaction = tm.startRequest();
if (items.size() == 1) {
tm.startRequest();
- CipRRData rrdata = new CipRRData(sessionHandle, 0L, senderContext, 0L,
- new CipExchange(
- new CipUnconnectedRequest(
- items.get(0), (byte) configuration.getBackplane(), (byte) configuration.getSlot(), -1
- ),
- -1
+
+ PathSegment classSegment = new LogicalSegment(new ClassID((byte) 0, (short) 6, this.configuration.getByteOrder()), this.configuration.getByteOrder());
+ PathSegment instanceSegment = new LogicalSegment(new InstanceID((byte) 0, (short) 1, this.configuration.getByteOrder()), this.configuration.getByteOrder());
+
+ UnConnectedDataItem exchange = new UnConnectedDataItem(
+ new CipUnconnectedRequest(
+ classSegment,
+ instanceSegment,
+ items.get(0),
+ (byte) configuration.getBackplane(),
+ (byte) configuration.getSlot(),
+ -1,
+ this.configuration.getByteOrder()
+
),
+ this.configuration.getByteOrder()
+ );
+
+ List<TypeId> typeIds = new ArrayList<TypeId>() {
+ {
+ add(exchange);
+ }
+ };
+
+ CipRRData rrdata = new CipRRData(
+ sessionHandle,
+ 0L,
+ senderContext,
+ 0L,
+ EMPTY_INTERFACE_HANDLE,
+ 0,
+ 2,
+ typeIds,
+ this.configuration.getByteOrder(),
-1
);
transaction.submit(() -> context.sendRequest(rrdata)
@@ -485,8 +617,8 @@ public class EipProtocolLogic extends Plc4xProtocolBase<EipPacket> implements Ha
.check(p -> p instanceof CipRRData).unwrap(p -> (CipRRData) p)
.check(p -> p.getSessionHandle() == sessionHandle)
//.check(p -> p.getSenderContext() == senderContext)
- .check(p -> p.getExchange().getService() instanceof CipWriteResponse)
- .unwrap(p -> (CipWriteResponse) p.getExchange().getService())
+ .check(p -> ((UnConnectedDataItem) p.getTypeId().get(0)).getService() instanceof CipWriteResponse)
+ .unwrap(p -> (CipWriteResponse) ((UnConnectedDataItem) p.getTypeId().get(0)).getService())
.handle(p -> {
future.complete((PlcWriteResponse) decodeWriteResponse(p, writeRequest));
transaction.endRequest();
@@ -506,19 +638,41 @@ public class EipProtocolLogic extends Plc4xProtocolBase<EipPacket> implements Ha
for (int i = 0; i < nb; i++) {
serviceArr.add(items.get(i));
}
- Services data = new Services(nb, offsets, serviceArr, -1);
+ Services data = new Services(nb, offsets, serviceArr, -1, this.configuration.getByteOrder());
//Encapsulate the data
- CipRRData pkt = new CipRRData(sessionHandle, 0L, emptySenderContext, 0L,
- new CipExchange(
- new CipUnconnectedRequest(
- new MultipleServiceRequest(data, -1),
- (byte) configuration.getBackplane(),
- (byte) configuration.getSlot(),
- -1
- ),
- -1
+ PathSegment classSegment = new LogicalSegment(new ClassID((byte) 0, (short) 6, this.configuration.getByteOrder()), this.configuration.getByteOrder());
+ PathSegment instanceSegment = new LogicalSegment(new InstanceID((byte) 0, (short) 1, this.configuration.getByteOrder()), this.configuration.getByteOrder());
+
+ UnConnectedDataItem exchange = new UnConnectedDataItem(
+ new CipUnconnectedRequest(
+ classSegment,
+ instanceSegment,
+ new MultipleServiceRequest(data, -1, this.configuration.getByteOrder()),
+ (byte) configuration.getBackplane(),
+ (byte) configuration.getSlot(),
+ (Integer) 0,
+ this.configuration.getByteOrder()
),
+ this.configuration.getByteOrder()
+ );
+
+ List<TypeId> typeIds = new ArrayList<TypeId>() {
+ {
+ add(exchange);
+ }
+ };
+
+ CipRRData pkt = new CipRRData(
+ sessionHandle,
+ 0L,
+ DEFAULT_SENDER_CONTEXT,
+ 0L,
+ EMPTY_INTERFACE_HANDLE,
+ 0,
+ 2,
+ typeIds,
+ this.configuration.getByteOrder(),
-1
);
@@ -531,7 +685,7 @@ public class EipProtocolLogic extends Plc4xProtocolBase<EipPacket> implements Ha
.check(p -> p.getSessionHandle() == sessionHandle)
//.check(p -> p.getSenderContext() == senderContext)
.unwrap(p -> (CipRRData) p)
- .unwrap(p -> p.getExchange().getService()).check(p -> p instanceof MultipleServiceResponse)
+ .unwrap(p -> ((UnConnectedDataItem) p.getTypeId().get(0)).getService()).check(p -> p instanceof MultipleServiceResponse)
.unwrap(p -> (MultipleServiceResponse) p)
.check(p -> p.getServiceNb() == nb)
.handle(p -> {
@@ -575,7 +729,7 @@ public class EipProtocolLogic extends Plc4xProtocolBase<EipPacket> implements Ha
throw new PlcRuntimeException(e);
}
}
- Services services = new Services(nb, resp.getOffsets(), arr, -1);
+ Services services = new Services(nb, resp.getOffsets(), arr, -1, this.configuration.getByteOrder());
Iterator<String> it = writeRequest.getFieldNames().iterator();
for (int i = 0; i < nb && it.hasNext(); i++) {
String fieldName = it.next();
@@ -638,8 +792,6 @@ public class EipProtocolLogic extends Plc4xProtocolBase<EipPacket> implements Ha
@Override
public void close(ConversationContext<EipPacket> context) {
- logger.debug("Sending UnregisterSession EIP Pakcet");
- context.sendRequest(new EipDisconnectRequest(sessionHandle, 0L, emptySenderContext, 0L)); //Unregister gets no response
- logger.debug("Unregistred Session {}", sessionHandle);
+ onDisconnect(context);
}
}
diff --git a/plc4j/drivers/eip/src/test/java/org/apache/plc4x/java/eip/readwrite/EIPDriverTestsuite.java b/plc4j/drivers/eip/src/test/java/org/apache/plc4x/java/eip/readwrite/EIPDriverTestsuite.java
index 143b3cca35..ce60f09dd3 100644
--- a/plc4j/drivers/eip/src/test/java/org/apache/plc4x/java/eip/readwrite/EIPDriverTestsuite.java
+++ b/plc4j/drivers/eip/src/test/java/org/apache/plc4x/java/eip/readwrite/EIPDriverTestsuite.java
@@ -23,7 +23,7 @@ import org.apache.plc4x.test.driver.DriverTestsuiteRunner;
public class EIPDriverTestsuite extends DriverTestsuiteRunner {
public EIPDriverTestsuite() {
- super("/protocols/eip/DriverTestsuite.xml");
+ super("/protocols/eip/DriverTestsuite.xml", true);
}
}
diff --git a/plc4j/drivers/eip/src/test/java/org/apache/plc4x/java/eip/readwrite/EIPParserSerializerTest.java b/plc4j/drivers/eip/src/test/java/org/apache/plc4x/java/eip/readwrite/EIPParserSerializerTest.java
index a150b82fe0..a63007e5c8 100644
--- a/plc4j/drivers/eip/src/test/java/org/apache/plc4x/java/eip/readwrite/EIPParserSerializerTest.java
+++ b/plc4j/drivers/eip/src/test/java/org/apache/plc4x/java/eip/readwrite/EIPParserSerializerTest.java
@@ -23,7 +23,7 @@ import org.apache.plc4x.test.parserserializer.ParserSerializerTestsuiteRunner;
public class EIPParserSerializerTest extends ParserSerializerTestsuiteRunner {
public EIPParserSerializerTest() {
- super("/protocols/eip/ParserSerializerTestsuite.xml");
+ super("/protocols/eip/ParserSerializerTestsuite.xml", true);
}
}
diff --git a/plc4j/drivers/eip/src/test/resources/logback-test.xml b/plc4j/drivers/eip/src/test/resources/logback-test.xml
index 2b9cea25dc..efb9ecdbeb 100644
--- a/plc4j/drivers/eip/src/test/resources/logback-test.xml
+++ b/plc4j/drivers/eip/src/test/resources/logback-test.xml
@@ -29,7 +29,7 @@
</encoder>
</appender>
- <root level="error">
+ <root level="trace">
<appender-ref ref="STDOUT" />
</root>
diff --git a/protocols/eip/src/main/resources/protocols/eip/eip.mspec b/protocols/eip/src/main/resources/protocols/eip/eip.mspec
index 9285bd5e2c..5be1b0e686 100644
--- a/protocols/eip/src/main/resources/protocols/eip/eip.mspec
+++ b/protocols/eip/src/main/resources/protocols/eip/eip.mspec
@@ -21,12 +21,12 @@
///EthernetIP Header of size 24
/////////////////////////////////////////////////////////////////
-[discriminatedType EipPacket byteOrder='BIG_ENDIAN'
+[discriminatedType EipPacket (IntegerEncoding order) byteOrder='order == IntegerEncoding.BIG_ENDIAN ? BIG_ENDIAN : LITTLE_ENDIAN'
[discriminator uint 16 command]
[implicit uint 16 len 'lengthInBytes - 24']
[simple uint 32 sessionHandle]
[simple uint 32 status]
- [array uint 8 senderContext count '8']
+ [array byte senderContext count '8']
[simple uint 32 options]
[typeSwitch command
['0x0065' EipConnectionRequest
@@ -36,54 +36,101 @@
['0x0066' EipDisconnectRequest
]
['0x006F' CipRRData(uint 16 len)
- [reserved uint 32 '0x00000000']
- [reserved uint 16 '0x0000']
- [simple CipExchange('len - 6') exchange]
+ [simple uint 32 interfaceHandle]
+ [simple uint 16 timeout]
+ [simple uint 16 itemCount]
+ [array TypeId('order') typeId count 'itemCount']
+ ]
+ ['0x0070' SendUnitData
+ [const uint 32 interfaceHandle 0x00000000]
+ [simple uint 16 timeout]
+ [simple uint 16 itemCount]
+ [array TypeId('order') typeId count 'itemCount']
]
]
]
-[type CipExchange (uint 16 exchangeLen) //We pass then length down to evey sub-type to be able to provide the remaining data size
- [const uint 16 itemCount 0x02 ] //2 items
- [const uint 32 nullPtr 0x0 ] //NullPointerAddress
- [const uint 16 unconnectedData 0x00B2 ] //Connection Manager
- [implicit uint 16 size 'lengthInBytes - 8 - 2' ] //remove fields above and routing
- [simple CipService('exchangeLen - 10') service ]
+[discriminatedType TypeId(IntegerEncoding order) byteOrder='order == IntegerEncoding.BIG_ENDIAN ? BIG_ENDIAN : LITTLE_ENDIAN'
+ [discriminator uint 16 id]
+ [typeSwitch id
+ ['0x0000' NullAddressItem
+ [reserved uint 16 '0x0000']
+ ]
+ ['0x00A1' ConnectedAddressItem
+ [reserved uint 16 '0x0400']
+ [simple uint 32 connectionId]
+ ]
+ ['0x00B1' ConnectedDataItem
+ [implicit uint 16 size 'service.lengthInBytes + 2']
+ [simple uint 16 sequenceCount]
+ [simple CipService('true', 'size - 2', 'order') service]
+ ]
+ ['0x00B2' UnConnectedDataItem
+ [implicit uint 16 size 'service.lengthInBytes']
+ [simple CipService('false', 'size', 'order') service]
+ ]
+ ]
]
-[discriminatedType CipService(uint 16 serviceLen)
- [discriminator uint 8 service]
- [typeSwitch service
- ['0x4C' CipReadRequest
- [simple int 8 requestPathSize]
- [array byte tag length '(requestPathSize * 2)']
+[discriminatedType CipService(bit connected, uint 16 serviceLen, IntegerEncoding order) byteOrder='order == IntegerEncoding.BIG_ENDIAN ? BIG_ENDIAN : LITTLE_ENDIAN'
+ [discriminator bit response]
+ [discriminator uint 7 service]
+ [typeSwitch service,response,connected
+ ['0x4C','false' CipReadRequest
+ [implicit int 8 requestPathSize 'COUNT(tag) / 2']
+ [array byte tag count '(requestPathSize * 2)']
[simple uint 16 elementNb]
]
- ['0xCC' CipReadResponse
+ ['0x4C','true' CipReadResponse
[reserved uint 8 '0x00']
[simple uint 8 status]
[simple uint 8 extStatus]
[simple CIPDataTypeCode dataType]
[array byte data count 'serviceLen - 6']
]
- ['0x4D' CipWriteRequest
- [simple int 8 requestPathSize]
- [array byte tag length 'requestPathSize * 2']
+ ['0x4D','false' CipWriteRequest
+ [implicit int 8 requestPathSize 'COUNT(tag) / 2']
+ [array byte tag length 'requestPathSize * 2']
[simple CIPDataTypeCode dataType]
[simple uint 16 elementNb]
[array byte data length 'dataType.size * elementNb']
]
- ['0xCD' CipWriteResponse
+ ['0x4D','true' CipWriteResponse
[reserved uint 8 '0x00']
[simple uint 8 status]
[simple uint 8 extStatus]
]
- ['0x0A' MultipleServiceRequest
+ ['0x4E','false' CipConnectionManagerCloseRequest
+ [simple int 8 requestPathSize]
+ [simple PathSegment('order') classSegment]
+ [simple PathSegment('order') instanceSegment]
+ [simple uint 4 priority]
+ [simple uint 4 tickTime]
+ [simple uint 8 timeoutTicks]
+ [simple uint 16 connectionSerialNumber]
+ [simple uint 16 originatorVendorId]
+ [simple uint 32 originatorSerialNumber]
+ [simple uint 8 connectionPathSize]
+ [reserved byte '0x00']
+ [simple PathSegment('order') connectionPathPortSegment]
+ [simple PathSegment('order') connectionPathClassSegment]
+ [simple PathSegment('order') connectionPathInstanceSegment]
+ ]
+ ['0x4E','true' CipConnectionManagerCloseResponse
+ [simple uint 8 status]
+ [simple uint 8 additionalStatusWords]
+ [simple uint 16 connectionSerialNumber]
+ [simple uint 16 originatorVendorId]
+ [simple uint 32 originatorSerialNumber]
+ [simple uint 8 applicationReplySize]
+ [reserved uint 8 '0x00']
+ ]
+ ['0x0A','false' MultipleServiceRequest
[const int 8 requestPathSize 0x02]
[const uint 32 requestPath 0x01240220] //Logical Segment: Class(0x20) 0x02, Instance(0x24) 01 (Message Router)
- [simple Services('serviceLen - 6 ') data ]
+ [simple Services('serviceLen - 6 ', 'order') data ]
]
- ['0x8A' MultipleServiceResponse
+ ['0x0A','true' MultipleServiceResponse
[reserved uint 8 '0x0']
[simple uint 8 status]
[simple uint 8 extStatus]
@@ -91,26 +138,144 @@
[array uint 16 offsets count 'serviceNb']
[array byte servicesData count 'serviceLen - 6 - (2 * serviceNb)']
]
- ['0x52' CipUnconnectedRequest
- [reserved uint 8 '0x02']
- [reserved uint 8 '0x20'] // setRequestPathLogicalClassSegment
- [reserved uint 8 '0x06'] // set request class path
- [reserved uint 8 '0x24'] // setRequestPathLogicalInstanceSegment
- [reserved uint 8 '0x01'] // setRequestPathInstance
+ ['0x52','false','false' CipUnconnectedRequest
+ [implicit int 8 requestPathSize '(classSegment.lengthInBytes + instanceSegment.lengthInBytes)/2']
+ [simple PathSegment('order') classSegment]
+ [simple PathSegment('order') instanceSegment]
[reserved uint 16 '0x9D05'] //Timeout 5s
[implicit uint 16 messageSize 'lengthInBytes - 10 - 4'] //subtract above and routing
- [simple CipService('messageSize') unconnectedService ]
+ [simple CipService('false','messageSize','order') unconnectedService ]
[const uint 16 route 0x0001]
[simple int 8 backPlane]
[simple int 8 slot]
]
+ ['0x52','false','true' CipConnectedRequest
+ [implicit uint 8 requestPathSize 'COUNT(pathSegments)']
+ [array byte pathSegments count 'requestPathSize*2']
+ [reserved byte 30 '0x00000000']
+ ]
+ ['0x5B','false' CipConnectionManagerRequest
+ [implicit int 8 requestPathSize '(classSegment.lengthInBytes + instanceSegment.lengthInBytes)/2']
+ [simple PathSegment('order') classSegment]
+ [simple PathSegment('order') instanceSegment]
+ [simple uint 4 priority]
+ [simple uint 4 tickTime]
+ [simple uint 8 timeoutTicks]
+ [simple uint 32 otConnectionId]
+ [simple uint 32 toConnectionId]
+ [simple uint 16 connectionSerialNumber]
+ [simple uint 16 originatorVendorId]
+ [simple uint 32 originatorSerialNumber]
+ [simple uint 8 timeoutMultiplier]
+ [reserved uint 24 '0x000000']
+ [simple uint 32 otRpi]
+ [simple NetworkConnectionParameters('order') otConnectionParameters]
+ [simple uint 32 toRpi]
+ [simple NetworkConnectionParameters('order') toConnectionParameters]
+ [simple TransportType('order') transportType]
+ [simple uint 8 connectionPathSize]
+ [simple PathSegment('order') connectionPathPortSegment]
+ [simple PathSegment('order') connectionPathClassSegment]
+ [simple PathSegment('order') connectionPathInstanceSegment]
+
+ ]
+ ['0x5B','true' CipConnectionManagerResponse
+ [reserved uint 24 '0x000000']
+ [simple uint 32 otConnectionId]
+ [simple uint 32 toConnectionId]
+ [simple uint 16 connectionSerialNumber]
+ [simple uint 16 originatorVendorId]
+ [simple uint 32 originatorSerialNumber]
+ [simple uint 32 otApi]
+ [simple uint 32 toApi]
+ [implicit uint 8 replySize 'serviceLen - 30']
+ [reserved uint 8 '0x00']
+ ]
+ ]
+]
+
+[discriminatedType PathSegment(IntegerEncoding order) byteOrder='order == IntegerEncoding.BIG_ENDIAN ? BIG_ENDIAN : LITTLE_ENDIAN'
+ [discriminator uint 3 pathSegment]
+ [typeSwitch pathSegment
+ ['0x00' PortSegment
+ [simple bit extendedLinkAddress]
+ [simple uint 4 port]
+ [simple uint 8 linkAddress]
+ ]
+ ['0x01' LogicalSegment
+ [simple LogicalSegmentType('order') segmentType]
+ ]
+ ['0x04' DataSegment
+ [simple DataSegmentType('order') segmentType]
+ ]
]
]
-[type Services (uint 16 servicesLen)
+[discriminatedType LogicalSegmentType(IntegerEncoding order) byteOrder='order == IntegerEncoding.BIG_ENDIAN ? BIG_ENDIAN : LITTLE_ENDIAN'
+ [discriminator uint 3 logicalSegmentType]
+ [typeSwitch logicalSegmentType
+ ['0x00' ClassID
+ [simple uint 2 format]
+ [simple uint 8 segmentClass]
+ ]
+ ['0x01' InstanceID
+ [simple uint 2 format]
+ [simple uint 8 instance]
+ ]
+ ['0x02' MemberID
+ [simple uint 2 format]
+ [simple uint 8 instance]
+ ]
+ ]
+]
+
+[discriminatedType DataSegmentType(IntegerEncoding order) byteOrder='order == IntegerEncoding.BIG_ENDIAN ? BIG_ENDIAN : LITTLE_ENDIAN'
+ [discriminator uint 5 dataSegmentType]
+ [typeSwitch dataSegmentType
+ ['0x11' AnsiExtendedSymbolSegment
+ [implicit uint 8 dataSize 'symbol.length']
+ [simple vstring 'dataSize * 8' symbol]
+ [optional uint 8 pad 'symbol.length % 2 != 0']
+ ]
+ ]
+]
+
+[type InstanceSegment(IntegerEncoding order) byteOrder='order == IntegerEncoding.BIG_ENDIAN ? BIG_ENDIAN : LITTLE_ENDIAN'
+ [simple uint 3 pathSegmentType]
+ [simple uint 3 logicalSegmentType]
+ [simple uint 2 logicalSegmentFormat]
+ [simple uint 8 instance]
+]
+
+[type ClassSegment(IntegerEncoding order) byteOrder='order == IntegerEncoding.BIG_ENDIAN ? BIG_ENDIAN : LITTLE_ENDIAN'
+ [simple uint 3 pathSegmentType]
+ [simple uint 3 logicalSegmentType]
+ [simple uint 2 logicalSegmentFormat]
+ [simple uint 8 classSegment]
+]
+
+
+[type NetworkConnectionParameters(IntegerEncoding order) byteOrder='order == IntegerEncoding.BIG_ENDIAN ? BIG_ENDIAN : LITTLE_ENDIAN'
+ [simple uint 16 connectionSize]
+ [reserved uint 8 '0x00']
+ [simple bit owner]
+ [simple uint 2 connectionType]
+ [reserved bit 'false']
+ [simple uint 2 priority]
+ [simple bit connectionSizeType]
+ [reserved bit 'false']
+]
+
+[type TransportType(IntegerEncoding order) byteOrder='order == IntegerEncoding.BIG_ENDIAN ? BIG_ENDIAN : LITTLE_ENDIAN'
+ [simple bit direction]
+ [simple uint 3 trigger]
+ [simple uint 4 classTransport]
+]
+
+[type Services (uint 16 servicesLen, IntegerEncoding order) byteOrder='order == IntegerEncoding.BIG_ENDIAN ? BIG_ENDIAN : LITTLE_ENDIAN'
[simple uint 16 serviceNb]
[array uint 16 offsets count 'serviceNb']
- [array CipService('servicesLen / serviceNb') services count 'serviceNb' ]
+ [array CipService('false', 'servicesLen / serviceNb', 'order') services count 'serviceNb' ]
]
[enum uint 16 CIPDataTypeCode(uint 8 size)
@@ -136,4 +301,44 @@
['0x0065' RegisterSession ]
['0x0066' UnregisterSession ]
['0x006F' SendRRData ]
+]
+
+[enum uint 4 IntegerEncoding
+ ['0x0' BIG_ENDIAN]
+ ['0x1' LITTLE_ENDIAN]
+]
+
+[enum uint 32 CIPStatus
+ ['0x00000000' Success]
+ ['0x00000001' ConnectionFailure]
+ ['0x00000002' ResourceUnAvailable]
+ ['0x00000003' InvalidParameterValue]
+ ['0x00000004' PathSegmentError]
+ ['0x00000005' PathDestinationUnknown]
+ ['0x00000006' PartialTransfer]
+ ['0x00000007' ConnectionIDNotValid]
+ ['0x00000008' ServiceNotSupported]
+ ['0x00000009' InvalidAttributeValue]
+ ['0x0000000A' AttributeListError]
+ ['0x0000000B' AlreadyInRequestedState]
+ ['0x0000000C' ObjectStateConflict]
+ ['0x0000000D' ObjectAlreadyExists]
+ ['0x0000000E' AttributeNotSettable]
+ ['0x0000000F' PriviligeViolation]
+ ['0x00000010' DeviceStateConflict]
+ ['0x00000011' ReplyDataTooLarge]
+ ['0x00000012' FragmentationOfPrimitiveValue]
+ ['0x00000013' NotEnoughData]
+ ['0x00000014' AttributeNotSupported]
+ ['0x00000015' TooMuchData]
+ ['0x00000016' ObjectDoesNotExist]
+ ['0x00000017' ServiceFragmentation]
+ ['0x00000018' NoStoredAttributeData]
+ ['0x00000019' StoreOperationFailure]
+ ['0x0000001A' RequestPacketTooLarge]
+ ['0x0000001B' ResponsePacketTooLarge]
+ ['0x0000001C' MissingAttributeListEntryData]
+ ['0x0000001D' InvalidAttributeValueList]
+ ['0x0000001E' EmbeddedServiceError]
+ ['0x0000001F' VendorSpecificError]
]
\ No newline at end of file
diff --git a/protocols/eip/src/test/resources/protocols/eip/DriverTestsuite.xml b/protocols/eip/src/test/resources/protocols/eip/DriverTestsuite.xml
index 2959fc4bf9..1d043e9432 100644
--- a/protocols/eip/src/test/resources/protocols/eip/DriverTestsuite.xml
+++ b/protocols/eip/src/test/resources/protocols/eip/DriverTestsuite.xml
@@ -30,6 +30,9 @@
<setup>
<!-- First the driver is expected to send a RegisterSession connection request -->
<outgoing-plc-message name="Send connection request">
+ <parser-arguments>
+ <byteOrder>BIG_ENDIAN</byteOrder>
+ </parser-arguments>
<EipPacket>
<command dataType="uint" bitLength="16">101</command>
<len dataType="uint" bitLength="16">4</len>
@@ -54,6 +57,9 @@
</outgoing-plc-message>
<!-- The PLC will send the connection response with a sender context and session handle-->
<incoming-plc-message name="Receive connection response">
+ <parser-arguments>
+ <byteOrder>BIG_ENDIAN</byteOrder>
+ </parser-arguments>
<EipPacket>
<command dataType="uint" bitLength="16">101</command>
<len dataType="uint" bitLength="16">4</len>
@@ -92,6 +98,9 @@
</TestReadRequest>
</api-request>
<outgoing-plc-message name="Send CipReadRequest to PLC">
+ <parser-arguments>
+ <byteOrder>BIG_ENDIAN</byteOrder>
+ </parser-arguments>
<EipPacket>
<command dataType="uint" bitLength="16">111</command>
<len dataType="uint" bitLength="16">40</len>
@@ -150,6 +159,9 @@
</EipPacket>
</outgoing-plc-message>
<incoming-plc-message name="Get CipReadResponse from PLC">
+ <parser-arguments>
+ <byteOrder>BIG_ENDIAN</byteOrder>
+ </parser-arguments>
<EipPacket>
<command dataType="uint" bitLength="16">111</command>
<len dataType="uint" bitLength="16">26</len>
diff --git a/protocols/eip/src/test/resources/protocols/eip/ParserSerializerTestsuite.xml b/protocols/eip/src/test/resources/protocols/eip/ParserSerializerTestsuite.xml
index 331299cc64..6f22b201e8 100644
--- a/protocols/eip/src/test/resources/protocols/eip/ParserSerializerTestsuite.xml
+++ b/protocols/eip/src/test/resources/protocols/eip/ParserSerializerTestsuite.xml
@@ -29,22 +29,16 @@
<name>Register Session</name>
<raw>00650004000000000000000000000000000000000000000000010000</raw>
<root-type>EipPacket</root-type>
+ <parser-arguments>
+ <byteOrder>BIG_ENDIAN</byteOrder>
+ </parser-arguments>
<xml>
<EipPacket>
<command dataType="uint" bitLength="16">101</command>
<len dataType="uint" bitLength="16">4</len>
<sessionHandle dataType="uint" bitLength="32">0</sessionHandle>
<status dataType="uint" bitLength="32">0</status>
- <senderContext isList="true">
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- </senderContext>
+ <senderContext dataType="byte" bitLength="64">0x0000000000000000</senderContext>
<options dataType="uint" bitLength="32">0</options>
<EipConnectionRequest>
<protocolVersion dataType="uint" bitLength="16">1</protocolVersion>
@@ -60,61 +54,92 @@
006F0028000012340000000001000000000000010000000000000000000000020000000000B200185202200624019D05000A4C03910472617465000100010104
</raw>
<root-type>EipPacket</root-type>
+ <parser-arguments>
+ <byteOrder>BIG_ENDIAN</byteOrder>
+ </parser-arguments>
<xml>
<EipPacket>
<command dataType="uint" bitLength="16">111</command>
<len dataType="uint" bitLength="16">40</len>
<sessionHandle dataType="uint" bitLength="32">4660</sessionHandle>
<status dataType="uint" bitLength="32">0</status>
- <senderContext isList="true">
- <value dataType="uint" bitLength="8">1</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">1</value>
- </senderContext>
+ <senderContext dataType="byte" bitLength="64">0x0100000000000001</senderContext>
<options dataType="uint" bitLength="32">0</options>
<CipRRData>
- <reserved dataType="uint" bitLength="32">0</reserved>
- <reserved dataType="uint" bitLength="16">0</reserved>
- <exchange>
- <CipExchange>
- <itemCount dataType="uint" bitLength="16">2</itemCount>
- <nullPtr dataType="uint" bitLength="32">0</nullPtr>
- <unconnectedData dataType="uint" bitLength="16">178</unconnectedData>
- <size dataType="uint" bitLength="16">24</size>
- <service>
- <CipService>
- <service dataType="uint" bitLength="8">82</service>
- <CipUnconnectedRequest>
- <reserved dataType="uint" bitLength="8">2</reserved>
- <reserved dataType="uint" bitLength="8">32</reserved>
- <reserved dataType="uint" bitLength="8">6</reserved>
- <reserved dataType="uint" bitLength="8">36</reserved>
- <reserved dataType="uint" bitLength="8">1</reserved>
- <reserved dataType="uint" bitLength="16">40197</reserved>
- <messageSize dataType="uint" bitLength="16">10</messageSize>
- <unconnectedService>
- <CipService>
- <service dataType="uint" bitLength="8">76</service>
- <CipReadRequest>
- <requestPathSize dataType="int" 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">4</slot>
- </CipUnconnectedRequest>
- </CipService>
- </service>
- </CipExchange>
- </exchange>
+ <interfaceHandle dataType="uint" bitLength="32">0</interfaceHandle>
+ <timeout dataType="uint" bitLength="16">0</timeout>
+ <itemCount dataType="uint" bitLength="16">2</itemCount>
+ <typeId 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>
+ <size dataType="uint" bitLength="16">24</size>
+ <service>
+ <CipService>
+ <response dataType="bit" bitLength="1">false</response>
+ <service dataType="uint" bitLength="7">82</service>
+ <CipUnconnectedRequest>
+ <requestPathSize dataType="int" 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="int" 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">4</slot>
+ </CipUnconnectedRequest>
+ </CipService>
+ </service>
+ </UnConnectedDataItem>
+ </TypeId>
+ </typeId>
</CipRRData>
</EipPacket>
</xml>
@@ -124,48 +149,50 @@
<name>CIP Read Response</name>
<raw>006F001A000012340000000001000000000000010000000000000000000000020000000000B2000ACC00000000C400000216</raw>
<root-type>EipPacket</root-type>
+ <parser-arguments>
+ <byteOrder>BIG_ENDIAN</byteOrder>
+ </parser-arguments>
<xml>
<EipPacket>
<command dataType="uint" bitLength="16">111</command>
<len dataType="uint" bitLength="16">26</len>
<sessionHandle dataType="uint" bitLength="32">4660</sessionHandle>
<status dataType="uint" bitLength="32">0</status>
- <senderContext isList="true">
- <value dataType="uint" bitLength="8">1</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">1</value>
- </senderContext>
+ <senderContext dataType="byte" bitLength="64">0x0100000000000001</senderContext>
<options dataType="uint" bitLength="32">0</options>
<CipRRData>
- <reserved dataType="uint" bitLength="32">0</reserved>
- <reserved dataType="uint" bitLength="16">0</reserved>
- <exchange>
- <CipExchange>
- <itemCount dataType="uint" bitLength="16">2</itemCount>
- <nullPtr dataType="uint" bitLength="32">0</nullPtr>
- <unconnectedData dataType="uint" bitLength="16">178</unconnectedData>
- <size dataType="uint" bitLength="16">10</size>
- <service>
- <CipService>
- <service dataType="uint" bitLength="8">204</service>
- <CipReadResponse>
- <reserved dataType="uint" bitLength="8">0</reserved>
- <status dataType="uint" bitLength="8">0</status>
- <extStatus dataType="uint" bitLength="8">0</extStatus>
- <dataType> <!--0xC4-->
- <CIPDataTypeCode dataType="uint" bitLength="16" stringRepresentation="DINT">196</CIPDataTypeCode>
- </dataType>
- <data dataType="byte" bitLength="32">0x00000216</data> <!--0x216 but again issue when parsing Object to XML-->
- </CipReadResponse>
- </CipService>
- </service>
- </CipExchange>
- </exchange>
+ <interfaceHandle dataType="uint" bitLength="32">0</interfaceHandle>
+ <timeout dataType="uint" bitLength="16">0</timeout>
+ <itemCount dataType="uint" bitLength="16">2</itemCount>
+ <typeId 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>
+ <size dataType="uint" bitLength="16">10</size>
+ <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>
+ <dataType>
+ <CIPDataTypeCode dataType="uint" bitLength="16" stringRepresentation="DINT">196</CIPDataTypeCode>
+ </dataType>
+ <data dataType="byte" bitLength="32">0x00000216</data>
+ </CipReadResponse>
+ </CipService>
+ </service>
+ </UnConnectedDataItem>
+ </TypeId>
+ </typeId>
</CipRRData>
</EipPacket>
</xml>
@@ -177,65 +204,96 @@
006F0034000012340000000001000000000000010000000000000000000000020000000000B200245202200624019D0500164D069116436172746F6E53697A6500C400010000000E00010104
</raw>
<root-type>EipPacket</root-type>
+ <parser-arguments>
+ <byteOrder>BIG_ENDIAN</byteOrder>
+ </parser-arguments>
<xml>
<EipPacket>
<command dataType="uint" bitLength="16">111</command>
<len dataType="uint" bitLength="16">52</len>
<sessionHandle dataType="uint" bitLength="32">4660</sessionHandle>
<status dataType="uint" bitLength="32">0</status>
- <senderContext isList="true">
- <value dataType="uint" bitLength="8">1</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">1</value>
- </senderContext>
+ <senderContext dataType="byte" bitLength="64">0x0100000000000001</senderContext>
<options dataType="uint" bitLength="32">0</options>
<CipRRData>
- <reserved dataType="uint" bitLength="32">0</reserved>
- <reserved dataType="uint" bitLength="16">0</reserved>
- <exchange>
- <CipExchange>
- <itemCount dataType="uint" bitLength="16">2</itemCount>
- <nullPtr dataType="uint" bitLength="32">0</nullPtr>
- <unconnectedData dataType="uint" bitLength="16">178</unconnectedData>
- <size dataType="uint" bitLength="16">36</size>
- <service>
- <CipService>
- <service dataType="uint" bitLength="8">82</service>
- <CipUnconnectedRequest>
- <reserved dataType="uint" bitLength="8">2</reserved>
- <reserved dataType="uint" bitLength="8">32</reserved>
- <reserved dataType="uint" bitLength="8">6</reserved>
- <reserved dataType="uint" bitLength="8">36</reserved>
- <reserved dataType="uint" bitLength="8">1</reserved>
- <reserved dataType="uint" bitLength="16">40197</reserved>
- <messageSize dataType="uint" bitLength="16">22</messageSize>
- <unconnectedService>
- <CipService>
- <service dataType="uint" bitLength="8">77</service>
- <CipWriteRequest>
- <requestPathSize dataType="int" bitLength="8">6</requestPathSize>
- <tag dataType="byte" bitLength="96">0x9116436172746f6e53697a65</tag>
- <dataType>
- <CIPDataTypeCode dataType="uint" bitLength="16" stringRepresentation="DINT">196</CIPDataTypeCode>
- </dataType>
- <elementNb dataType="uint" bitLength="16">1</elementNb>
- <data dataType="byte" bitLength="32">0x0000000e</data>
- </CipWriteRequest>
- </CipService>
- </unconnectedService>
- <route dataType="uint" bitLength="16">1</route>
- <backPlane dataType="int" bitLength="8">1</backPlane>
- <slot dataType="int" bitLength="8">4</slot>
- </CipUnconnectedRequest>
- </CipService>
- </service>
- </CipExchange>
- </exchange>
+ <interfaceHandle dataType="uint" bitLength="32">0</interfaceHandle>
+ <timeout dataType="uint" bitLength="16">0</timeout>
+ <itemCount dataType="uint" bitLength="16">2</itemCount>
+ <typeId 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>
+ <size dataType="uint" bitLength="16">36</size>
+ <service>
+ <CipService>
+ <response dataType="bit" bitLength="1">false</response>
+ <service dataType="uint" bitLength="7">82</service>
+ <CipUnconnectedRequest>
+ <requestPathSize dataType="int" 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">22</messageSize>
+ <unconnectedService>
+ <CipService>
+ <response dataType="bit" bitLength="1">false</response>
+ <service dataType="uint" bitLength="7">77</service>
+ <CipWriteRequest>
+ <requestPathSize dataType="int" bitLength="8">6</requestPathSize>
+ <tag dataType="byte" bitLength="96">0x9116436172746f6e53697a65</tag>
+ <dataType>
+ <CIPDataTypeCode dataType="uint" bitLength="16" stringRepresentation="DINT">196</CIPDataTypeCode>
+ </dataType>
+ <elementNb dataType="uint" bitLength="16">1</elementNb>
+ <data dataType="byte" bitLength="32">0x0000000e</data>
+ </CipWriteRequest>
+ </CipService>
+ </unconnectedService>
+ <route dataType="uint" bitLength="16">1</route>
+ <backPlane dataType="int" bitLength="8">1</backPlane>
+ <slot dataType="int" bitLength="8">4</slot>
+ </CipUnconnectedRequest>
+ </CipService>
+ </service>
+ </UnConnectedDataItem>
+ </TypeId>
+ </typeId>
</CipRRData>
</EipPacket>
</xml>
@@ -245,48 +303,102 @@
<name>CIP Write Response</name>
<raw>006F0014000012340000000001000000000000010000000000000000000000020000000000B20004CD000000</raw>
<root-type>EipPacket</root-type>
+ <parser-arguments>
+ <byteOrder>BIG_ENDIAN</byteOrder>
+ </parser-arguments>
<xml>
<EipPacket>
<command dataType="uint" bitLength="16">111</command>
<len dataType="uint" bitLength="16">20</len>
<sessionHandle dataType="uint" bitLength="32">4660</sessionHandle>
<status dataType="uint" bitLength="32">0</status>
- <senderContext isList="true">
- <value dataType="uint" bitLength="8">1</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">0</value>
- <value dataType="uint" bitLength="8">1</value>
- </senderContext>
+ <senderContext dataType="byte" bitLength="64">0x0100000000000001</senderContext>
<options dataType="uint" bitLength="32">0</options>
<CipRRData>
- <reserved dataType="uint" bitLength="32">0</reserved>
- <reserved dataType="uint" bitLength="16">0</reserved>
- <exchange>
- <CipExchange>
- <itemCount dataType="uint" bitLength="16">2</itemCount>
- <nullPtr dataType="uint" bitLength="32">0</nullPtr>
- <unconnectedData dataType="uint" bitLength="16">178</unconnectedData>
- <size dataType="uint" bitLength="16">4</size>
- <service>
- <CipService>
- <service dataType="uint" bitLength="8">205</service>
- <CipWriteResponse>
- <reserved dataType="uint" bitLength="8">0</reserved>
- <status dataType="uint" bitLength="8">0</status>
- <extStatus dataType="uint" bitLength="8">0</extStatus>
- </CipWriteResponse>
- </CipService>
- </service>
- </CipExchange>
- </exchange>
+ <interfaceHandle dataType="uint" bitLength="32">0</interfaceHandle>
+ <timeout dataType="uint" bitLength="16">0</timeout>
+ <itemCount dataType="uint" bitLength="16">2</itemCount>
+ <typeId 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>
+ <size dataType="uint" bitLength="16">4</size>
+ <service>
+ <CipService>
+ <response dataType="bit" bitLength="1">true</response>
+ <service dataType="uint" bitLength="7">77</service>
+ <CipWriteResponse>
+ <reserved dataType="uint" bitLength="8">0</reserved>
+ <status dataType="uint" bitLength="8">0</status>
+ <extStatus dataType="uint" bitLength="8">0</extStatus>
+ </CipWriteResponse>
+ </CipService>
+ </service>
+ </UnConnectedDataItem>
+ </TypeId>
+ </typeId>
</CipRRData>
</EipPacket>
</xml>
</testcase>
+ <testcase>
+ <name>CIP Connected Read Request</name>
+ <raw>70003800c9070440000000005765277265000000000000000000000000000200a10004005942feffb10024000100520d91124b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b910370707000010000000000</raw>
+ <root-type>EipPacket</root-type>
+ <parser-arguments>
+ <byteOrder>LITTLE_ENDIAN</byteOrder>
+ </parser-arguments>
+ <xml>
+ <EipPacket>
+ <command dataType="uint" bitLength="16">112</command>
+ <len dataType="uint" bitLength="16">51</len>
+ <sessionHandle dataType="uint" bitLength="32">1074005961</sessionHandle>
+ <status dataType="uint" bitLength="32">0</status>
+ <senderContext dataType="byte" bitLength="64">0x5765277265000000</senderContext>
+ <options dataType="uint" bitLength="32">0</options>
+ <SendUnitData>
+ <interfaceHandle dataType="uint" bitLength="32">0</interfaceHandle>
+ <timeout dataType="uint" bitLength="16">0</timeout>
+ <itemCount dataType="uint" bitLength="16">2</itemCount>
+ <typeId isList="true">
+ <TypeId>
+ <id dataType="uint" bitLength="16">161</id>
+ <ConnectedAddressItem>
+ <reserved dataType="uint" bitLength="16">1024</reserved>
+ <connectionId dataType="uint" bitLength="32">4294853209</connectionId>
+ </ConnectedAddressItem>
+ </TypeId>
+ <TypeId>
+ <id dataType="uint" bitLength="16">177</id>
+ <ConnectedDataItem>
+ <size dataType="uint" bitLength="16">31</size>
+ <sequenceCount dataType="uint" bitLength="16">1</sequenceCount>
+ <service>
+ <CipService>
+ <response dataType="bit" bitLength="1">false</response>
+ <service dataType="uint" bitLength="7">82</service>
+ <CipConnectedRequest>
+ <requestPathSize dataType="uint" bitLength="8">26</requestPathSize>
+ <pathSegments dataType="byte" bitLength="208">0x91124b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b4b910370707000</pathSegments>
+ <reserved dataType="byte" bitLength="8">0x00</reserved>
+ </CipConnectedRequest>
+ </CipService>
+ </service>
+ </ConnectedDataItem>
+ </TypeId>
+ </typeId>
+ </SendUnitData>
+ </EipPacket>
+ </xml>
+ </testcase>
+
+
</test:testsuite>
\ No newline at end of file