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 2019/08/27 11:14:59 UTC
[plc4x] branch develop updated: - First Implementation of a driver
for AB-ETH without any testing and without decoding of the response.
This is an automated email from the ASF dual-hosted git repository.
cdutz pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git
The following commit(s) were added to refs/heads/develop by this push:
new d744d4d - First Implementation of a driver for AB-ETH without any testing and without decoding of the response.
d744d4d is described below
commit d744d4d03765a458320b60e576eb149572ca28f1
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Tue Aug 27 13:14:53 2019 +0200
- First Implementation of a driver for AB-ETH without any testing and without decoding of the response.
---
sandbox/test-java-ab-eth-driver/pom.xml | 16 +++
.../org/apache/plc4x/java/abeth/AbEthDriver.java | 72 ++++++++++
.../java/abeth/connection/AbEthPlcConnection.java | 123 ++++++++++++++++
.../apache/plc4x/java/abeth/model/AbEthField.java | 86 ++++++++++++
.../plc4x/java/abeth/model/types/FileType.java | 61 ++++++++
.../plc4x/java/abeth/protocol/AbEthProtocol.java | 69 +++++++++
.../java/abeth/protocol/Plc4xAbEthProtocol.java | 155 +++++++++++++++++++++
.../services/org.apache.plc4x.java.spi.PlcDriver | 19 +++
8 files changed, 601 insertions(+)
diff --git a/sandbox/test-java-ab-eth-driver/pom.xml b/sandbox/test-java-ab-eth-driver/pom.xml
index 136aeae..4750ea2 100644
--- a/sandbox/test-java-ab-eth-driver/pom.xml
+++ b/sandbox/test-java-ab-eth-driver/pom.xml
@@ -55,12 +55,28 @@
</build>
<dependencies>
+
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4j-api</artifactId>
+ <version>0.5.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.plc4x</groupId>
<artifactId>plc4j-utils-driver-base-java</artifactId>
<version>0.5.0-SNAPSHOT</version>
</dependency>
<dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4j-protocol-driver-base</artifactId>
+ <version>0.5.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.plc4x</groupId>
+ <artifactId>plc4j-protocol-driver-base-tcp</artifactId>
+ <version>0.5.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
diff --git a/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/AbEthDriver.java b/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/AbEthDriver.java
new file mode 100644
index 0000000..9b36cfc
--- /dev/null
+++ b/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/AbEthDriver.java
@@ -0,0 +1,72 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+package org.apache.plc4x.java.abeth;
+
+import org.apache.plc4x.java.abeth.connection.AbEthPlcConnection;
+import org.apache.plc4x.java.api.PlcConnection;
+import org.apache.plc4x.java.api.authentication.PlcAuthentication;
+import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
+import org.apache.plc4x.java.spi.PlcDriver;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class AbEthDriver implements PlcDriver {
+
+ private static final Pattern ABETH_URI_PATTERN = Pattern.compile("^ab-eth://(?<host>.*)(?<params>\\?.*)?");
+
+ @Override
+ public String getProtocolCode() {
+ return "ab-eth";
+ }
+
+ @Override
+ public String getProtocolName() {
+ return "Allen Bradley ETH";
+ }
+
+ @Override
+ public PlcConnection connect(String url) throws PlcConnectionException {
+ Matcher matcher = ABETH_URI_PATTERN.matcher(url);
+ if (!matcher.matches()) {
+ throw new PlcConnectionException(
+ "Connection url doesn't match the format 'ab-eth://{host|ip}'");
+ }
+ String host = matcher.group("host");
+
+ String params = matcher.group("params") != null ? matcher.group("params").substring(1) : null;
+
+ try {
+ InetAddress serverInetAddress = InetAddress.getByName(host);
+ return new AbEthPlcConnection(serverInetAddress, params);
+ } catch (UnknownHostException e) {
+ throw new PlcConnectionException("Error parsing address", e);
+ } catch (Exception e) {
+ throw new PlcConnectionException("Error connecting to host", e);
+ }
+ }
+
+ @Override
+ public PlcConnection connect(String url, PlcAuthentication authentication) throws PlcConnectionException {
+ throw new PlcConnectionException("AB-ETH connections don't support authentication.");
+ }
+
+}
diff --git a/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/connection/AbEthPlcConnection.java b/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/connection/AbEthPlcConnection.java
new file mode 100644
index 0000000..7c0228c
--- /dev/null
+++ b/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/connection/AbEthPlcConnection.java
@@ -0,0 +1,123 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+package org.apache.plc4x.java.abeth.connection;
+
+import io.netty.channel.*;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.plc4x.java.abeth.model.AbEthField;
+import org.apache.plc4x.java.abeth.protocol.AbEthProtocol;
+import org.apache.plc4x.java.abeth.protocol.Plc4xAbEthProtocol;
+import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
+import org.apache.plc4x.java.api.messages.PlcReadRequest;
+import org.apache.plc4x.java.api.messages.PlcReadResponse;
+import org.apache.plc4x.java.api.model.PlcField;
+import org.apache.plc4x.java.base.connection.ChannelFactory;
+import org.apache.plc4x.java.base.connection.NettyPlcConnection;
+import org.apache.plc4x.java.base.connection.TcpSocketChannelFactory;
+import org.apache.plc4x.java.base.events.ConnectedEvent;
+import org.apache.plc4x.java.base.messages.InternalPlcReadRequest;
+import org.apache.plc4x.java.base.messages.InternalPlcReadResponse;
+import org.apache.plc4x.java.base.messages.PlcReader;
+import org.apache.plc4x.java.base.messages.PlcRequestContainer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.InetAddress;
+import java.util.concurrent.CompletableFuture;
+
+public class AbEthPlcConnection extends NettyPlcConnection implements PlcReader {
+
+ private static final int AB_ETH_PORT = 2222;
+ private static final Logger logger = LoggerFactory.getLogger(AbEthPlcConnection.class);
+
+ public AbEthPlcConnection(InetAddress address, String params) {
+ this(new TcpSocketChannelFactory(address, AB_ETH_PORT), params);
+
+ logger.info("Setting up AB-ETH Connection with: host-name {}", address.getHostAddress());
+ }
+
+ public AbEthPlcConnection(ChannelFactory channelFactory, String params) {
+ super(channelFactory, true);
+
+ if (!StringUtils.isEmpty(params)) {
+ for (String param : params.split("&")) {
+ String[] paramElements = param.split("=");
+ String paramName = paramElements[0];
+ if (paramElements.length == 2) {
+ String paramValue = paramElements[1];
+ switch (paramName) {
+ default:
+ logger.debug("Unknown parameter {} with value {}", paramName, paramValue);
+ }
+ } else {
+ logger.debug("Unknown no-value parameter {}", paramName);
+ }
+ }
+ }
+ }
+
+ @Override
+ public PlcField prepareField(String fieldQuery) throws PlcInvalidFieldException {
+ return AbEthField.of(fieldQuery);
+ }
+
+ @Override
+ protected ChannelHandler getChannelHandler(CompletableFuture<Void> sessionSetupCompleteFuture) {
+ return new ChannelInitializer() {
+ @Override
+ protected void initChannel(Channel channel) {
+ // Build the protocol stack for communicating with the s7 protocol.
+ ChannelPipeline pipeline = channel.pipeline();
+ pipeline.addLast(new ChannelInboundHandlerAdapter() {
+ @Override
+ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
+ if (evt instanceof ConnectedEvent) {
+ sessionSetupCompleteFuture.complete(null);
+ } else {
+ super.userEventTriggered(ctx, evt);
+ }
+ }
+ });
+ pipeline.addLast(new AbEthProtocol());
+ pipeline.addLast(new Plc4xAbEthProtocol());
+ }
+ };
+ }
+
+ @Override
+ public boolean canRead() {
+ return true;
+ }
+
+ @Override
+ public CompletableFuture<PlcReadResponse> read(PlcReadRequest readRequest) {
+ InternalPlcReadRequest internalReadRequest = checkInternal(readRequest, InternalPlcReadRequest.class);
+ CompletableFuture<InternalPlcReadResponse> future = new CompletableFuture<>();
+ PlcRequestContainer<InternalPlcReadRequest, InternalPlcReadResponse> container =
+ new PlcRequestContainer<>(internalReadRequest, future);
+ channel.writeAndFlush(container).addListener(f -> {
+ if (!f.isSuccess()) {
+ future.completeExceptionally(f.cause());
+ }
+ });
+ return future
+ .thenApply(PlcReadResponse.class::cast);
+ }
+
+}
diff --git a/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/model/AbEthField.java b/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/model/AbEthField.java
new file mode 100644
index 0000000..49143d3
--- /dev/null
+++ b/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/model/AbEthField.java
@@ -0,0 +1,86 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+package org.apache.plc4x.java.abeth.model;
+
+import org.apache.plc4x.java.abeth.model.types.FileType;
+import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException;
+import org.apache.plc4x.java.api.model.PlcField;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class AbEthField implements PlcField {
+
+ private static final Pattern ADDRESS_PATTERN =
+ Pattern.compile("^N(?<fileNumber>\\d{1,7})\\:(?<elementNumber>\\d{1,7})/(?<subElementNumber>\\d{1,7}):(?<dataType>[a-zA-Z_]+)(\\[(?<size>\\d+)])?");
+
+ private static final String FILE_NUMBER = "fileNumber";
+ private static final String ELEMENT_NUMBER = "elementNumber";
+ private static final String SUB_ELEMENT_NUMBER = "subElementNumber";
+ private static final String DATA_TYPE = "dataType";
+ private static final String SIZE = "size";
+
+ private final short byteSize;
+ private final short fileNumber;
+ private final FileType fileType;
+ private final short elementNumber;
+ private final short subElementNumber;
+
+ public AbEthField(short byteSize, short fileNumber, FileType fileType, short elementNumber, short subElementNumber) {
+ this.byteSize = byteSize;
+ this.fileNumber = fileNumber;
+ this.fileType = fileType;
+ this.elementNumber = elementNumber;
+ this.subElementNumber = subElementNumber;
+ }
+
+ public short getByteSize() {
+ return byteSize;
+ }
+
+ public short getFileNumber() {
+ return fileNumber;
+ }
+
+ public FileType getFileType() {
+ return fileType;
+ }
+
+ public short getElementNumber() {
+ return elementNumber;
+ }
+
+ public short getSubElementNumber() {
+ return subElementNumber;
+ }
+
+ public static AbEthField of(String fieldString) {
+ Matcher matcher = ADDRESS_PATTERN.matcher(fieldString);
+ if(matcher.matches()) {
+ short fileNumber = Short.parseShort(matcher.group(FILE_NUMBER));
+ short elementNumber = Short.parseShort(matcher.group(ELEMENT_NUMBER));
+ short subElementNumber = Short.parseShort(matcher.group(SUB_ELEMENT_NUMBER));
+ FileType fileType = FileType.valueOf(Short.parseShort(matcher.group(DATA_TYPE)));
+ short byteSize = Short.parseShort(matcher.group(SIZE));
+ return new AbEthField(byteSize, fileNumber, fileType,elementNumber, subElementNumber);
+ }
+ throw new PlcInvalidFieldException("Unable to parse address: " + fieldString);
+ }
+
+}
diff --git a/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/model/types/FileType.java b/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/model/types/FileType.java
new file mode 100644
index 0000000..3c3df85
--- /dev/null
+++ b/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/model/types/FileType.java
@@ -0,0 +1,61 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+package org.apache.plc4x.java.abeth.model.types;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public enum FileType {
+
+ STATUS((short) 0x84),
+ BIT((short) 0x85),
+ TIMER((short) 0x86),
+ COUNTER((short) 0x87),
+ CONTROL((short) 0x88),
+ INTEGER((short) 0x89),
+ FLOAT((short) 0x8A),
+ OUTPUT((short) 0x8B),
+ INPUT((short) 0x8C),
+ STRING((short) 0x8D),
+ ASCII((short) 0x8E),
+ BCD((short) 0x8F);
+
+ private final short typeCode;
+
+ FileType(short typeCode) {
+ this.typeCode = typeCode;
+ }
+
+ public short getTypeCode() {
+ return typeCode;
+ }
+
+ private static final Map<Short, FileType> map;
+ static {
+ map = new HashMap<>();
+ for (FileType dataType : FileType.values()) {
+ map.put(dataType.typeCode, dataType);
+ }
+ }
+
+ public static FileType valueOf(short code) {
+ return map.get(code);
+ }
+
+}
diff --git a/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/protocol/AbEthProtocol.java b/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/protocol/AbEthProtocol.java
new file mode 100644
index 0000000..c45d9e6
--- /dev/null
+++ b/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/protocol/AbEthProtocol.java
@@ -0,0 +1,69 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+package org.apache.plc4x.java.abeth.protocol;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandlerContext;
+import org.apache.plc4x.java.abeth.CIPEncapsulationConnectionRequest;
+import org.apache.plc4x.java.abeth.CIPEncapsulationConnectionResponse;
+import org.apache.plc4x.java.abeth.CIPEncapsulationPacket;
+import org.apache.plc4x.java.abeth.io.CIPEncapsulationPacketIO;
+import org.apache.plc4x.java.base.PlcByteToMessageCodec;
+import org.apache.plc4x.java.base.events.ConnectEvent;
+import org.apache.plc4x.java.base.events.ConnectedEvent;
+import org.apache.plc4x.java.utils.ReadBuffer;
+import org.apache.plc4x.java.utils.WriteBuffer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+public class AbEthProtocol extends PlcByteToMessageCodec<CIPEncapsulationPacket> {
+
+ private static final Logger logger = LoggerFactory.getLogger(AbEthProtocol.class);
+
+ private CIPEncapsulationPacketIO io;
+
+ public AbEthProtocol() {
+ io = new CIPEncapsulationPacketIO();
+ }
+
+ @Override
+ protected void encode(ChannelHandlerContext ctx, CIPEncapsulationPacket cipEncapsulationPacket, ByteBuf byteBuf) throws Exception {
+ WriteBuffer buffer = new WriteBuffer(cipEncapsulationPacket.getLengthInBytes());
+ io.serialize(buffer, cipEncapsulationPacket);
+ byteBuf.writeBytes(buffer.getData());
+ }
+
+ @Override
+ protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> out) throws Exception {
+ byte[] bytes = new byte[byteBuf.readableBytes()];
+ byteBuf.readBytes(bytes);
+ ReadBuffer readBuffer = new ReadBuffer(bytes);
+ while (readBuffer.getPos() < bytes.length) {
+ try {
+ CIPEncapsulationPacket packet = io.parse(readBuffer);
+ out.add(packet);
+ } catch (Exception e) {
+ logger.warn("Error decoding package: " + e.getMessage());
+ }
+ }
+ }
+
+}
diff --git a/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/protocol/Plc4xAbEthProtocol.java b/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/protocol/Plc4xAbEthProtocol.java
new file mode 100644
index 0000000..7e90dfd
--- /dev/null
+++ b/sandbox/test-java-ab-eth-driver/src/main/java/org/apache/plc4x/java/abeth/protocol/Plc4xAbEthProtocol.java
@@ -0,0 +1,155 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+package org.apache.plc4x.java.abeth.protocol;
+
+import io.netty.channel.ChannelHandlerContext;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.plc4x.java.abeth.*;
+import org.apache.plc4x.java.abeth.model.AbEthField;
+import org.apache.plc4x.java.api.exceptions.PlcProtocolException;
+import org.apache.plc4x.java.api.messages.PlcReadRequest;
+import org.apache.plc4x.java.api.messages.PlcRequest;
+import org.apache.plc4x.java.api.messages.PlcResponse;
+import org.apache.plc4x.java.api.model.PlcField;
+import org.apache.plc4x.java.api.types.PlcResponseCode;
+import org.apache.plc4x.java.base.PlcMessageToMessageCodec;
+import org.apache.plc4x.java.base.events.ConnectEvent;
+import org.apache.plc4x.java.base.events.ConnectedEvent;
+import org.apache.plc4x.java.base.messages.DefaultPlcReadResponse;
+import org.apache.plc4x.java.base.messages.InternalPlcReadRequest;
+import org.apache.plc4x.java.base.messages.PlcRequestContainer;
+import org.apache.plc4x.java.base.messages.items.BaseDefaultFieldItem;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class Plc4xAbEthProtocol extends PlcMessageToMessageCodec<CIPEncapsulationPacket, PlcRequestContainer> {
+
+ private static final Logger logger = LoggerFactory.getLogger(Plc4xAbEthProtocol.class);
+
+ private static final AtomicInteger transactionCounterGenerator = new AtomicInteger(10);
+ private static final short[] emptySenderContext = new short[] {(short) 0x00 ,(short) 0x00 ,(short) 0x00,
+ (short) 0x00,(short) 0x00,(short) 0x00, (short) 0x00,(short) 0x00};
+
+ private long sessionHandle;
+ private Map<Integer, PlcRequestContainer> requests;
+
+ public Plc4xAbEthProtocol() {
+ this.requests = new HashMap<>();
+ }
+
+ @Override
+ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
+ // If the connection has just been established, start setting up the connection
+ // by sending a connection request to the plc.
+ if (evt instanceof ConnectEvent) {
+ logger.debug("AB-ETH Sending Connection Request");
+ // Open the session on ISO Transport Protocol first.
+ CIPEncapsulationConnectionRequest connectionRequest = new CIPEncapsulationConnectionRequest(0L, 0L,
+ emptySenderContext, 0L);
+ ctx.channel().writeAndFlush(connectionRequest);
+ } else {
+ super.userEventTriggered(ctx, evt);
+ }
+ }
+
+ @Override
+ protected void encode(ChannelHandlerContext ctx, PlcRequestContainer msg, List<Object> out) throws Exception {
+ PlcRequest request = msg.getRequest();
+ if (request instanceof PlcReadRequest) {
+ PlcReadRequest readRequest = (PlcReadRequest) msg.getRequest();
+
+ for (String fieldName : readRequest.getFieldNames()) {
+ PlcField field = readRequest.getField(fieldName);
+ if (!(field instanceof AbEthField)) {
+ throw new PlcProtocolException("The field should have been of type AbEthField");
+ }
+ AbEthField abEthField = (AbEthField) field;
+
+ DF1RequestProtectedTypedLogicalRead logicalRead = new DF1RequestProtectedTypedLogicalRead(
+ abEthField.getByteSize(), abEthField.getFileNumber(), abEthField.getFileType().getTypeCode(),
+ abEthField.getElementNumber(), abEthField.getSubElementNumber());
+ DF1RequestMessage requestMessage = new DF1CommandRequestMessage(
+ (short) 8, (short) 5, (short) 0, transactionCounterGenerator.incrementAndGet(), logicalRead);
+ CIPEncapsulationReadRequest read = new CIPEncapsulationReadRequest(
+ sessionHandle, 0, emptySenderContext, 0, requestMessage);
+
+ requests.put(requestMessage.getTransactionCounter(), msg);
+
+ out.add(read);
+ }
+ } else {
+ ctx.fireExceptionCaught(
+ new PlcProtocolException("Unsupported request type " + request.getClass().getName()));
+ }
+ }
+
+ @Override
+ protected void decode(ChannelHandlerContext ctx, CIPEncapsulationPacket packet, List<Object> out) throws Exception {
+ if(packet instanceof CIPEncapsulationConnectionResponse) {
+ CIPEncapsulationConnectionResponse connectionResponse = (CIPEncapsulationConnectionResponse) packet;
+ // Save the session handle
+ sessionHandle = connectionResponse.getSessionHandle();
+
+ // Tell Netty we're finished connecting
+ ctx.channel().pipeline().fireUserEventTriggered(new ConnectedEvent());
+ } else {
+ // We're currently just expecting responses.
+ if (!(packet instanceof CIPEncapsulationReadResponse)) {
+ return;
+ }
+ CIPEncapsulationReadResponse cipResponse = (CIPEncapsulationReadResponse) packet;
+ int transactionCounter = cipResponse.getResponse().getTransactionCounter();
+ if(!requests.containsKey(transactionCounter)) {
+ ctx.fireExceptionCaught(
+ new PlcProtocolException(
+ "Couldn't find request for response with transaction counter " + transactionCounter));
+ return;
+ }
+
+ PlcRequestContainer requestContainer = requests.remove(transactionCounter);
+ PlcRequest request = requestContainer.getRequest();
+ PlcResponse response = null;
+ if (request instanceof PlcReadRequest) {
+ response = decodeReadResponse(cipResponse, requestContainer);
+ } else {
+ ctx.fireExceptionCaught(
+ new PlcProtocolException("Unsupported request type " + request.getClass().getName()));
+ }
+
+ // Confirm the response being handled.
+ if (response != null) {
+ requestContainer.getResponseFuture().complete(response);
+ }
+ }
+ }
+
+ private PlcResponse decodeReadResponse(
+ CIPEncapsulationReadResponse cipResponse, PlcRequestContainer requestContainer) {
+
+ InternalPlcReadRequest readRequest = (InternalPlcReadRequest) requestContainer.getRequest();
+
+ Map<String, Pair<PlcResponseCode, BaseDefaultFieldItem>> fields = new HashMap<>();
+ return new DefaultPlcReadResponse(readRequest, fields);
+ }
+}
diff --git a/sandbox/test-java-ab-eth-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver b/sandbox/test-java-ab-eth-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver
new file mode 100644
index 0000000..a8f485e
--- /dev/null
+++ b/sandbox/test-java-ab-eth-driver/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.PlcDriver
@@ -0,0 +1,19 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+org.apache.plc4x.java.abeth.AbEthDriver