From 810fb905d17a26709ace1dc36c635737c49b3e58 Mon Sep 17 00:00:00 2001 From: Anderson Vasconcelos Pires Date: Fri, 14 Mar 2025 14:33:39 -0300 Subject: [PATCH 1/2] Enable Allen Bradley ETH reading. Add the possibility of multiple readings. --- .../apache/plc4x/java/abeth/AbEthDriver.java | 5 + .../abeth/protocol/AbEthProtocolLogic.java | 144 ++++++++---------- 2 files changed, 70 insertions(+), 79 deletions(-) diff --git a/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/AbEthDriver.java b/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/AbEthDriver.java index 877d8b8274..e526218ca0 100644 --- a/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/AbEthDriver.java +++ b/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/AbEthDriver.java @@ -84,6 +84,11 @@ protected boolean awaitDisconnectComplete() { return false; } + @Override + protected boolean canRead() { + return true; + } + @Override protected ProtocolStackConfigurer getStackConfigurer() { return SingleProtocolStackConfigurer.builder(CIPEncapsulationPacket.class, CIPEncapsulationPacket::staticParse) diff --git a/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/protocol/AbEthProtocolLogic.java b/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/protocol/AbEthProtocolLogic.java index d5c25986a2..723733de0b 100644 --- a/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/protocol/AbEthProtocolLogic.java +++ b/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/protocol/AbEthProtocolLogic.java @@ -24,7 +24,6 @@ import org.apache.plc4x.java.abeth.tag.AbEthTagHandler; import org.apache.plc4x.java.api.messages.PlcReadRequest; import org.apache.plc4x.java.api.messages.PlcReadResponse; -import org.apache.plc4x.java.api.messages.PlcResponse; import org.apache.plc4x.java.api.model.PlcTag; import org.apache.plc4x.java.api.types.PlcResponseCode; import org.apache.plc4x.java.api.value.PlcValue; @@ -45,7 +44,6 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicInteger; @@ -97,7 +95,8 @@ public void onConnect(ConversationContext context) { @Override public CompletableFuture read(PlcReadRequest readRequest) { - // TODO: Warning ... we are sending one request per tag ... the result has to be merged back together ... + DefaultPlcReadResponse plcReadResponse = new DefaultPlcReadResponse(readRequest, new HashMap<>(readRequest.getNumberOfTags())); + CompletableFuture combinedFuture = CompletableFuture.completedFuture(plcReadResponse); for (String tagName : readRequest.getTagNames()) { PlcTag tag = readRequest.getTag(tagName); if (!(tag instanceof AbEthTag)) { @@ -122,6 +121,7 @@ public CompletableFuture read(PlcReadRequest readRequest) { sessionHandle, 0, emptySenderContext, 0, requestMessage); CompletableFuture future = new CompletableFuture<>(); + combinedFuture = combinedFuture.thenCombine(future, (r1, r2) -> plcReadResponse); RequestTransactionManager.RequestTransaction transaction = tm.startRequest(); transaction.submit(() -> conversationContext.sendRequest(read) .expectResponse(CIPEncapsulationPacket.class, REQUEST_TIMEOUT) @@ -130,92 +130,78 @@ public CompletableFuture read(PlcReadRequest readRequest) { .only(CIPEncapsulationReadResponse.class) .check(p -> p.getResponse().getTransactionCounter() == transactionCounter) .handle(p -> { - PlcResponse response = decodeReadResponse(p, readRequest); + PlcResponseItem response = decodeReadResponse(p, abEthTag, tagName); + plcReadResponse.add(tagName, response); - // TODO: Not sure how to merge things back together ... - - //future.complete(response); + future.complete(plcReadResponse); // Finish the request-transaction. transaction.endRequest(); -// future.complete(((PlcReadResponse) decodeReadResponse(p, ((InternalPlcReadRequest) readRequest)))); })); - - // TODO: This aborts reading other tags after sending the first tags request ... refactor. - return future; } - // TODO: Should return an aggregated future .... - return null; + return combinedFuture; } - private PlcResponse decodeReadResponse( - CIPEncapsulationReadResponse plcReadResponse, PlcReadRequest plcReadRequest) { - Map> values = new HashMap<>(); - for (String tagName : plcReadRequest.getTagNames()) { - AbEthTag tag = (AbEthTag) plcReadRequest.getTag(tagName); - PlcResponseCode responseCode = decodeResponseCode(plcReadResponse.getResponse().getStatus()); - - PlcValue plcValue = null; - if (responseCode == PlcResponseCode.OK) { - try { - switch (tag.getFileType()) { - case INTEGER: // output as single bytes - if (plcReadResponse.getResponse() instanceof DF1CommandResponseMessageProtectedTypedLogicalRead) { - DF1CommandResponseMessageProtectedTypedLogicalRead df1PTLR = (DF1CommandResponseMessageProtectedTypedLogicalRead) plcReadResponse.getResponse(); - List data = df1PTLR.getData(); - if (data.size() == 1) { - plcValue = new PlcINT(data.get(0)); - } else { - plcValue = DefaultPlcValueHandler.of(tag, data); - } - } - break; - case WORD: - if (plcReadResponse.getResponse() instanceof DF1CommandResponseMessageProtectedTypedLogicalRead) { - DF1CommandResponseMessageProtectedTypedLogicalRead df1PTLR = (DF1CommandResponseMessageProtectedTypedLogicalRead) plcReadResponse.getResponse(); - List data = df1PTLR.getData(); - if (((data.get(1) >> 7) & 1) == 0) { - plcValue = DefaultPlcValueHandler.of(tag, (data.get(1) << 8) + data.get(0)); // positive number - } else { - plcValue = DefaultPlcValueHandler.of(tag, (((~data.get(1) & 0b01111111) << 8) + (-data.get(0) & 0b11111111)) * -1); // negative number - } - } - break; - case DWORD: - if (plcReadResponse.getResponse() instanceof DF1CommandResponseMessageProtectedTypedLogicalRead) { - DF1CommandResponseMessageProtectedTypedLogicalRead df1PTLR = (DF1CommandResponseMessageProtectedTypedLogicalRead) plcReadResponse.getResponse(); - List data = df1PTLR.getData(); - if (((data.get(3) >> 7) & 1) == 0) { - plcValue = DefaultPlcValueHandler.of(tag, (data.get(3) << 24) + (data.get(2) << 16) + (data.get(1) << 8) + data.get(0)); // positive number - } else { - plcValue = DefaultPlcValueHandler.of(tag, (((~data.get(3) & 0b01111111) << 24) + ((-data.get(2) & 0b11111111) << 16) + ((-data.get(1) & 0b11111111) << 8) + (-data.get(0) & 0b11111111)) * -1); // negative number - } - } - break; - case SINGLEBIT: - if (plcReadResponse.getResponse() instanceof DF1CommandResponseMessageProtectedTypedLogicalRead) { - DF1CommandResponseMessageProtectedTypedLogicalRead df1PTLR = (DF1CommandResponseMessageProtectedTypedLogicalRead) plcReadResponse.getResponse(); - List data = df1PTLR.getData(); - if (tag.getBitNumber() < 8) { - plcValue = DefaultPlcValueHandler.of(tag, (data.get(0) & (1 << tag.getBitNumber())) != 0); // read from first byte - } else { - plcValue = DefaultPlcValueHandler.of(tag, (data.get(1) & (1 << (tag.getBitNumber() - 8))) != 0); // read from second byte - } - } - break; - default: - logger.warn("Problem during decoding of tag {}: Decoding of file type not implemented; " + - "TagInformation: {}", tagName, tag); + private PlcResponseItem decodeReadResponse( + CIPEncapsulationReadResponse plcReadResponse, AbEthTag tag, String tagName) { + PlcResponseCode responseCode = decodeResponseCode(plcReadResponse.getResponse().getStatus()); + PlcValue plcValue = null; + if (responseCode != PlcResponseCode.OK) { + return new DefaultPlcResponseItem<>(responseCode, plcValue); + } + try { + switch (tag.getFileType()) { + case INTEGER: // output as single bytes + if (plcReadResponse.getResponse() instanceof DF1CommandResponseMessageProtectedTypedLogicalRead) { + DF1CommandResponseMessageProtectedTypedLogicalRead df1PTLR = (DF1CommandResponseMessageProtectedTypedLogicalRead) plcReadResponse.getResponse(); + List data = df1PTLR.getData(); + if (data.size() == 1) { + plcValue = new PlcINT(data.get(0)); + } else { + plcValue = DefaultPlcValueHandler.of(tag, data); + } + } + break; + case WORD: + if (plcReadResponse.getResponse() instanceof DF1CommandResponseMessageProtectedTypedLogicalRead) { + DF1CommandResponseMessageProtectedTypedLogicalRead df1PTLR = (DF1CommandResponseMessageProtectedTypedLogicalRead) plcReadResponse.getResponse(); + List data = df1PTLR.getData(); + if (((data.get(1) >> 7) & 1) == 0) { + plcValue = DefaultPlcValueHandler.of(tag, (data.get(1) << 8) + data.get(0)); // positive number + } else { + plcValue = DefaultPlcValueHandler.of(tag, (((~data.get(1) & 0b01111111) << 8) + (-data.get(0) & 0b11111111)) * -1); // negative number + } } - } catch (Exception e) { - logger.warn("Some other error occurred casting tag {}, TagInformation: {}", tagName, tag, e); - } + break; + case DWORD: + if (plcReadResponse.getResponse() instanceof DF1CommandResponseMessageProtectedTypedLogicalRead) { + DF1CommandResponseMessageProtectedTypedLogicalRead df1PTLR = (DF1CommandResponseMessageProtectedTypedLogicalRead) plcReadResponse.getResponse(); + List data = df1PTLR.getData(); + if (((data.get(3) >> 7) & 1) == 0) { + plcValue = DefaultPlcValueHandler.of(tag, (data.get(3) << 24) + (data.get(2) << 16) + (data.get(1) << 8) + data.get(0)); // positive number + } else { + plcValue = DefaultPlcValueHandler.of(tag, (((~data.get(3) & 0b01111111) << 24) + ((-data.get(2) & 0b11111111) << 16) + ((-data.get(1) & 0b11111111) << 8) + (-data.get(0) & 0b11111111)) * -1); // negative number + } + } + break; + case SINGLEBIT: + if (plcReadResponse.getResponse() instanceof DF1CommandResponseMessageProtectedTypedLogicalRead) { + DF1CommandResponseMessageProtectedTypedLogicalRead df1PTLR = (DF1CommandResponseMessageProtectedTypedLogicalRead) plcReadResponse.getResponse(); + List data = df1PTLR.getData(); + if (tag.getBitNumber() < 8) { + plcValue = DefaultPlcValueHandler.of(tag, (data.get(0) & (1 << tag.getBitNumber())) != 0); // read from first byte + } else { + plcValue = DefaultPlcValueHandler.of(tag, (data.get(1) & (1 << (tag.getBitNumber() - 8))) != 0); // read from second byte + } + } + break; + default: + logger.warn("Problem during decoding of tag {}: Decoding of file type not implemented; " + + "TagInformation: {}", tagName, tag); } - PlcResponseItem result = new DefaultPlcResponseItem<>(responseCode, plcValue); - values.put(tagName, result); + } catch (Exception e) { + logger.warn("Some other error occurred casting tag {}, TagInformation: {}", tagName, tag, e); } - - // TODO: Double check if it's really a InternalPlcReadRequest ... - return new DefaultPlcReadResponse(plcReadRequest, values); + return new DefaultPlcResponseItem<>(responseCode, plcValue); } private PlcResponseCode decodeResponseCode(short status) { From ece8489629eb8e1cc64e757daf592b5f13570e9c Mon Sep 17 00:00:00 2001 From: Anderson Vasconcelos Pires Date: Sat, 22 Mar 2025 16:34:41 -0300 Subject: [PATCH 2/2] Initializing the transactionCounterGenerator to the same value as in the reinitialization (1) . This way we can avoid a future problem that could happen in the reinitialization. --- .../apache/plc4x/java/abeth/protocol/AbEthProtocolLogic.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/protocol/AbEthProtocolLogic.java b/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/protocol/AbEthProtocolLogic.java index 723733de0b..0175e4ca13 100644 --- a/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/protocol/AbEthProtocolLogic.java +++ b/plc4j/drivers/ab-eth/src/main/java/org/apache/plc4x/java/abeth/protocol/AbEthProtocolLogic.java @@ -57,7 +57,7 @@ public class AbEthProtocolLogic extends Plc4xProtocolBase