Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(plc4j/ab-eth): Enable AB-Ethernet Driver reading #2040

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ protected boolean awaitDisconnectComplete() {
return false;
}

@Override
protected boolean canRead() {
return true;
}

@Override
protected ProtocolStackConfigurer<CIPEncapsulationPacket> getStackConfigurer() {
return SingleProtocolStackConfigurer.builder(CIPEncapsulationPacket.class, CIPEncapsulationPacket::staticParse)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -97,7 +95,8 @@ public void onConnect(ConversationContext<CIPEncapsulationPacket> context) {

@Override
public CompletableFuture<PlcReadResponse> 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<PlcReadResponse> combinedFuture = CompletableFuture.completedFuture(plcReadResponse);
for (String tagName : readRequest.getTagNames()) {
PlcTag tag = readRequest.getTag(tagName);
if (!(tag instanceof AbEthTag)) {
Expand All @@ -122,6 +121,7 @@ public CompletableFuture<PlcReadResponse> read(PlcReadRequest readRequest) {
sessionHandle, 0, emptySenderContext, 0, requestMessage);

CompletableFuture<PlcReadResponse> 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)
Expand All @@ -130,92 +130,78 @@ public CompletableFuture<PlcReadResponse> read(PlcReadRequest readRequest) {
.only(CIPEncapsulationReadResponse.class)
.check(p -> p.getResponse().getTransactionCounter() == transactionCounter)
.handle(p -> {
PlcResponse response = decodeReadResponse(p, readRequest);
PlcResponseItem<PlcValue> 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<String, PlcResponseItem<PlcValue>> 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<Short> 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<Short> 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<Short> 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<Short> 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<PlcValue> 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<Short> 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<Short> 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<Short> 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<Short> 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<PlcValue> 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) {
Expand Down