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

[Bug]: [PLC4J] [EtherNet/IP] All values read are null for Allen-Bradley PLC with EtherNet/IP or Logix #1646

Open
2 of 16 tasks
meichf opened this issue Jun 7, 2024 · 18 comments
Assignees
Labels
bug Ethernet/IP https://plc4x.apache.org/users/protocols/eip.html java Pull requests that update Java code

Comments

@meichf
Copy link

meichf commented Jun 7, 2024

What happened?

I wrote two programs according to the documentation on the official website of PLC4X to read Allen Bradley PLC, model Logix5571, but all the values read were null.

Here is the code. The result is that all four tag values in asPlcValue are null.

code for EtherNet/IP protocol:

    String connectionString = "eip:https://192.168.0.2:44818?slot=0&bigEndian=false";

    try (PlcConnection plcConnection = PlcDriverManager.getDefault().getConnectionManager().getConnection(connectionString)) {
        final PlcReadRequest.Builder readrequest = plcConnection.readRequestBuilder();

    //(3.1)
        readrequest.addTagAddress("tag1", "%A:DINT");
        readrequest.addTagAddress("tag2", "%B:INT");
        readrequest.addTagAddress("tag3", "%C:SINT");
        readrequest.addTagAddress("tag4", "%D:REAL");

        //(3.2)
        final PlcReadRequest rr = readrequest.build();
        //(3.3)
        final PlcReadResponse szlresponse = rr.execute().get();

        PlcValue asPlcValue = szlresponse.getAsPlcValue();

    } catch (PlcConnectionException e) {
        throw new RuntimeException(e);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }

code for Logix protocol:

   String connectionString = "logix:https://192.168.0.2:44818?slot=0&bigEndian=false";

    try (PlcConnection plcConnection = PlcDriverManager.getDefault().getConnectionManager().getConnection(connectionString)) {
        PlcConnectionMetadata metadata = plcConnection.getMetadata();
        final PlcReadRequest.Builder readrequest = plcConnection.readRequestBuilder();

        //(3.1)
        readrequest.addTagAddress("tag1", "A:DINT");
        readrequest.addTagAddress("tag2", "B:INT");
        readrequest.addTagAddress("tag3", "C:SINT");
        readrequest.addTagAddress("tag4", "D:REAL");

        //(3.2)
        final PlcReadRequest rr = readrequest.build();
        //(3.3)
        final PlcReadResponse szlresponse = rr.execute().get();
        //(3.4)
        PlcValue asPlcValue = szlresponse.getAsPlcValue();
        log.info("Tags: " + asPlcValue);
    } catch (PlcConnectionException e) {
        throw new RuntimeException(e);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }`

here is the tags:

tags

Version

v0.12.0

Programming Languages

  • plc4j
  • plc4go
  • plc4c
  • plc4net

Protocols

  • AB-Ethernet
  • ADS /AMS
  • BACnet/IP
  • CANopen
  • DeltaV
  • DF1
  • EtherNet/IP
  • Firmata
  • KNXnet/IP
  • Modbus
  • OPC-UA
  • S7
@meichf meichf added the bug label Jun 7, 2024
@chrisdutz
Copy link
Contributor

chrisdutz commented Jun 14, 2024

So I've just created a ManualTest for my Logix device.
I created several Controller Tags (Including UDTs)
They are all called "hurz_{datatypeName}" for simplicity.
the Following program works when reading:

    public static void main(String[] args) throws Exception {
        ManualEipLogixDriverTest test = new ManualEipLogixDriverTest("logix:https://192.168.23.40");
        // This is the very limited number of types my controller supports.
        test.addTestCase("hurz_BOOL", new PlcBOOL(true));
        test.addTestCase("hurz_SINT", new PlcSINT(-42));
        test.addTestCase("hurz_INT", new PlcINT(-2424));
        test.addTestCase("hurz_DINT", new PlcDINT(-242442424));
        test.addTestCase("hurz_REAL", new PlcREAL(3.141593F));
        //test.addTestCase("hurz_UDT", new PlcStruct());

        long start = System.currentTimeMillis();
        test.run();
        long end = System.currentTimeMillis();
        System.out.printf("Finished in %d ms", end - start);
    }

However I can see the UDT being correctly sent on the wire using WireShark, just it seems that decoding it is a problem for the driver. Also can't I write. As soon as I try that I get errors.

@chrisdutz
Copy link
Contributor

So if I look at your code, omit the "%" and the datatypes. Just "A", "B", "C", or "D" should be enough.

chrisdutz added a commit that referenced this issue Jun 14, 2024
@chrisdutz
Copy link
Contributor

Ok ... I learned something more ... when reading, you can omit the datatype ... however when writing it seems to be mandatory. I think that in general we will have to implement some sort of "load the symbol table when connecting" similar to what we do for ADS and use that information throughout the session ... especially for UDTs I otherwise have no way to process them correctly.

@meichf
Copy link
Author

meichf commented Jun 18, 2024

So if I look at your code, omit the "%" and the datatypes. Just "A", "B", "C", or "D" should be enough.

I‘ve tried this, but it doesn't work

@chrisdutz
Copy link
Contributor

Are the tags you are trying to read controller tags or program tags? I tried with my logix device and above only worked for controller tags.

@meichf
Copy link
Author

meichf commented Jun 18, 2024

Are the tags you are trying to read controller tags or program tags? I tried with my logix device and above only worked for controller tags.
It's controller tags. My device is the Allen Bradley 1756-L71, I don't know if the logix protocol is valid for this device.

@hutcheb
Copy link
Contributor

hutcheb commented Jun 18, 2024

The L71 is a little older than the one Chris has, it is probably running v20 and I think he should be using v35 or something. Can you confirm which version?
There is probably going to be differences between v20 and the higher versions.

@meichf
Copy link
Author

meichf commented Jun 18, 2024

s
Do you mean programming tools? I'm using the studio 5000, v33.

@hutcheb
Copy link
Contributor

hutcheb commented Jun 18, 2024

Then thats probably not the issue, Which version of PLC4X are you using?

@meichf
Copy link
Author

meichf commented Jun 18, 2024

I have tried both 0.12.0 and 0.13.0-SNAPSHOT

@meichf
Copy link
Author

meichf commented Jun 18, 2024

I have identified the problem, it works on version 0.11.0 .

@chrisdutz
Copy link
Contributor

I think that is just plain EIP/CIP and no Logix extensions, right? I think we completely rewrote the driver for 0.12.0

@hutcheb
Copy link
Contributor

hutcheb commented Jun 18, 2024

@meichf Why are you setting the bigEndian parameter to false? Specifically for the logix driver in 0.13-SNAPSHOT.

@meichf
Copy link
Author

meichf commented Jun 19, 2024

I think that is just plain EIP/CIP and no Logix extensions, right? I think we completely rewrote the driver for 0.12.0

In version 0.11.0, both EtherNet/IP and Logix were successful, while in version 0.12.0, neither was successful.

@meichf
Copy link
Author

meichf commented Jun 19, 2024

@meichf Why are you setting the bigEndian parameter to false? Specifically for the logix driver in 0.13-SNAPSHOT.

It seems that without this parameter, I am unable to connect to the device.

@meichf
Copy link
Author

meichf commented Jun 19, 2024

I found that using version 0.11.0 to read data is slow, and the duration of returning data increases with the number of points. Then, I found the problem in issue #1373, so I rewrote the method. Now, reading values is relatively normal.

private CompletableFuture<PlcReadResponse> readWithoutMessageRouter(PlcReadRequest readRequest) {
   CompletableFuture<PlcReadResponse> future = new CompletableFuture<>();
   Map<String, ResponseItem<PlcValue>> values = new HashMap<>();
   List<CompletableFuture<Void>> internalFutures = new ArrayList<>();
   PathSegment classSegment = new LogicalSegment(new ClassID((byte) 0, (short) 6));
   PathSegment instanceSegment = new LogicalSegment(new InstanceID((byte) 0, (short) 1));

   DefaultPlcReadRequest request = (DefaultPlcReadRequest) readRequest;
   for (String tagName : request.getTagNames()) {
       CompletableFuture<Void> internalFuture = new CompletableFuture<>();
       RequestTransactionManager.RequestTransaction transaction = tm.startRequest();
       EipTag eipTag = (EipTag) request.getTag(tagName);
       String tag = eipTag.getTag();

       try {
           CipReadRequest req = new CipReadRequest(toAnsi(tag), 1);
           CipUnconnectedRequest requestItem = new CipUnconnectedRequest(classSegment, instanceSegment, req, (byte) this.configuration.getBackplane(), (byte) this.configuration.getSlot());
           List<TypeId> typeIds = new ArrayList<>(2);
           typeIds.add(nullAddressItem);
           typeIds.add(new UnConnectedDataItem(requestItem));
           CipRRData pkt = new CipRRData(sessionHandle, CIPStatus.Success.getValue(), DEFAULT_SENDER_CONTEXT, 0L, 0L, 0, typeIds);

           transaction.submit(() -> context.sendRequest(pkt)
                   .expectResponse(EipPacket.class, REQUEST_TIMEOUT)
                   .onTimeout(future::completeExceptionally)
                   .onError((p, e) -> future.completeExceptionally(e))
                   .check(p -> p instanceof CipRRData)
                   .unwrap(p -> (CipRRData) p)
                   .check(p -> p.getSessionHandle() == sessionHandle)
                   .handle(p -> {
                       List<TypeId> responseTypeIds = p.getTypeIds();
                       UnConnectedDataItem dataItem = (UnConnectedDataItem) responseTypeIds.get(1);
                       Map<String, ResponseItem<PlcValue>> readResponse = decodeSingleReadResponse(dataItem.getService(), tagName, eipTag);
                       values.putAll(readResponse);
                       internalFuture.complete(null);
                       transaction.endRequest();
                   }));
           internalFutures.add(internalFuture);
       } catch (SerializationException e) {
           future.completeExceptionally(e);
       }
   }

   CompletableFuture.allOf(internalFutures.toArray(new CompletableFuture[0])).thenRun(() -> {
       PlcReadResponse readResponse = new DefaultPlcReadResponse(readRequest, values);
       future.complete(readResponse);
   }).exceptionally(e -> {
       future.completeExceptionally(e);
       return null;
   });

   return future;
}

@acfly
Copy link

acfly commented Jun 20, 2024

@chrisdutz The Rewritten method readWithoutMessageRouter realy works. Hope it will be merged into the next version.

@chrisdutz
Copy link
Contributor

I think the new version of the driver sort of does an auto-detection of the PLC and decides which technique to use, based on that. Will see if I can have a look tomorrow afternoon.

@ottlukas ottlukas added java Pull requests that update Java code Ethernet/IP https://plc4x.apache.org/users/protocols/eip.html labels Jul 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Ethernet/IP https://plc4x.apache.org/users/protocols/eip.html java Pull requests that update Java code
Projects
None yet
Development

No branches or pull requests

5 participants