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 2022/08/10 11:11:03 UTC

[plc4x] 03/06: chore(ads): Finished implementing a first version of the symbol-table and the datatype-table extraction

This is an automated email from the ASF dual-hosted git repository.

cdutz pushed a commit to branch splatch/ads-symbol-discovery
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit 42f31216fdf7e18298726298b43819b8df24a1d0
Author: christoferdutz <ch...@c-ware.de>
AuthorDate: Thu Aug 4 23:00:09 2022 +0200

    chore(ads): Finished implementing a first version of the symbol-table and the datatype-table extraction
---
 .../plc4x/java/ads/protocol/AdsProtocolLogic.java  | 80 ++++++++++++----------
 .../ads/src/main/resources/protocols/ads/ads.mspec | 57 +++++++++------
 2 files changed, 79 insertions(+), 58 deletions(-)

diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/protocol/AdsProtocolLogic.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/protocol/AdsProtocolLogic.java
index 0d4128e85..9641148d2 100644
--- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/protocol/AdsProtocolLogic.java
+++ b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/protocol/AdsProtocolLogic.java
@@ -98,6 +98,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
     public void onConnect(ConversationContext<AmsTCPPacket> context) {
         LOGGER.debug("Fetching sizes of symbol and datatype table sizes.");
         final CompletableFuture<Void> future = new CompletableFuture<>();
+
         List<AdsDataTypeTableEntry> dataTypes = new ArrayList<>();
         List<AdsSymbolTableEntry> symbols = new ArrayList<>();
         // Initialize the request.
@@ -115,66 +116,69 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
             .check(responseAmsPacket -> responseAmsPacket.getUserdata().getInvokeId() == amsPacket.getInvokeId())
             .unwrap(response -> (AdsReadResponse) response.getUserdata().getData())
             .handle(responseAdsData -> {
+                transaction.endRequest();
                 if (responseAdsData.getResult() == ReturnCode.OK) {
                     ReadBuffer readBuffer = new ReadBufferByteBased(responseAdsData.getData());
                     try {
                         AdsTableSizes adsTableSizes = AdsTableSizes.staticParse(readBuffer);
                         LOGGER.info("PLC contains {} symbols and {} datatypes", adsTableSizes.getSymbolCount(), adsTableSizes.getDataTypeCount());
 
-                        AdsData adsReadSymbolTableData = new AdsReadRequest(AdsSignificantGroupAddresses.SYMBOL_TABLE.getValue(), 0x00000000, adsTableSizes.getSymbolLength());
-                        AmsPacket amsReadSymbolTablePacket = new AmsPacket(configuration.getTargetAmsNetId(), configuration.getTargetAmsPort(),
-                            configuration.getSourceAmsNetId(), configuration.getSourceAmsPort(),
-                            CommandId.ADS_READ, DEFAULT_COMMAND_STATE, 0, getInvokeId(), adsReadSymbolTableData);
-                        AmsTCPPacket amsReadSymbolTableTCPPacket = new AmsTCPPacket(amsReadSymbolTablePacket);
-                        transaction.submit(() -> context.sendRequest(amsReadSymbolTableTCPPacket)
-                            .expectResponse(AmsTCPPacket.class, Duration.ofMillis(configuration.getTimeoutRequest()))
-                            .onTimeout(future::completeExceptionally)
-                            .onError((p, e) -> future.completeExceptionally(e))
-                            .check(responseAmsPacket -> responseAmsPacket.getUserdata().getInvokeId() == amsReadSymbolTablePacket.getInvokeId())
-                            .unwrap(response -> (AdsReadResponse) response.getUserdata().getData())
-                            .handle(responseAdsReadSymbolTableData -> {
-                                if (responseAdsData.getResult() == ReturnCode.OK) {
-                                    ReadBuffer rb2 = new ReadBufferByteBased(responseAdsReadSymbolTableData.getData());
-                                    for (int i = 0; i < adsTableSizes.getSymbolCount(); i++) {
-                                        try {
-                                            AdsSymbolTableEntry adsSymbolTableEntry = AdsSymbolTableEntry.staticParse(rb2);
-                                            System.out.println(adsSymbolTableEntry);
-                                            symbols.add(adsSymbolTableEntry);
-                                        } catch (ParseException e) {
-                                            throw new RuntimeException(e);
-                                        }
-                                    }
-                                    future.complete(null);
-                                }
-                            }));
-
-                        // TODO: Now we load the symbol-table and the datatype definitions.
-                        /*AdsData adsReadTypeTableData = new AdsReadRequest(AdsSignificantGroupAddresses.DATA_TYPE_TABLE.getValue(), 0x00000000, adsTableSizes.getDataTypeLength());
+                        // Now we load the datatype definitions.
+                        AdsData adsReadTypeTableData = new AdsReadRequest(AdsSignificantGroupAddresses.DATA_TYPE_TABLE.getValue(), 0x00000000, adsTableSizes.getDataTypeLength());
                         AmsPacket amsReadTablePacket = new AmsPacket(configuration.getTargetAmsNetId(), configuration.getTargetAmsPort(),
                             configuration.getSourceAmsNetId(), configuration.getSourceAmsPort(),
                             CommandId.ADS_READ, DEFAULT_COMMAND_STATE, 0, getInvokeId(), adsReadTypeTableData);
+                        RequestTransactionManager.RequestTransaction transaction2 = tm.startRequest();
                         AmsTCPPacket amsReadTableTCPPacket = new AmsTCPPacket(amsReadTablePacket);
-                        transaction.submit(() -> context.sendRequest(amsReadTableTCPPacket)
+                        transaction2.submit(() -> context.sendRequest(amsReadTableTCPPacket)
                             .expectResponse(AmsTCPPacket.class, Duration.ofMillis(configuration.getTimeoutRequest()))
                             .onTimeout(future::completeExceptionally)
                             .onError((p, e) -> future.completeExceptionally(e))
                             .check(responseAmsPacket -> responseAmsPacket.getUserdata().getInvokeId() == amsReadTablePacket.getInvokeId())
                             .unwrap(response -> (AdsReadResponse) response.getUserdata().getData())
                             .handle(responseAdsReadTableData -> {
+                                transaction2.endRequest();
                                 if (responseAdsData.getResult() == ReturnCode.OK) {
                                     // Parse the result.
                                     ReadBuffer rb = new ReadBufferByteBased(responseAdsReadTableData.getData());
-                                    while (rb.hasMore(8)) {
+                                    for (int i = 0; i < adsTableSizes.getDataTypeCount(); i++) {
                                         try {
                                             AdsDataTypeTableEntry adsDataTypeTableEntry = AdsDataTypeTableEntry.staticParse(rb);
-                                            System.out.println(adsDataTypeTableEntry);
                                             dataTypes.add(adsDataTypeTableEntry);
                                         } catch (ParseException e) {
                                             throw new RuntimeException(e);
                                         }
                                     }
+
+                                    AdsData adsReadSymbolTableData = new AdsReadRequest(AdsSignificantGroupAddresses.SYMBOL_TABLE.getValue(), 0x00000000, adsTableSizes.getSymbolLength());
+                                    AmsPacket amsReadSymbolTablePacket = new AmsPacket(configuration.getTargetAmsNetId(), configuration.getTargetAmsPort(),
+                                        configuration.getSourceAmsNetId(), configuration.getSourceAmsPort(),
+                                        CommandId.ADS_READ, DEFAULT_COMMAND_STATE, 0, getInvokeId(), adsReadSymbolTableData);
+                                    RequestTransactionManager.RequestTransaction transaction3 = tm.startRequest();
+                                    AmsTCPPacket amsReadSymbolTableTCPPacket = new AmsTCPPacket(amsReadSymbolTablePacket);
+                                    transaction3.submit(() -> context.sendRequest(amsReadSymbolTableTCPPacket)
+                                        .expectResponse(AmsTCPPacket.class, Duration.ofMillis(configuration.getTimeoutRequest()))
+                                        .onTimeout(future::completeExceptionally)
+                                        .onError((p, e) -> future.completeExceptionally(e))
+                                        .check(responseAmsPacket -> responseAmsPacket.getUserdata().getInvokeId() == amsReadSymbolTablePacket.getInvokeId())
+                                        .unwrap(response -> (AdsReadResponse) response.getUserdata().getData())
+                                        .handle(responseAdsReadSymbolTableData -> {
+                                            transaction3.endRequest();
+                                            if (responseAdsData.getResult() == ReturnCode.OK) {
+                                                ReadBuffer rb2 = new ReadBufferByteBased(responseAdsReadSymbolTableData.getData());
+                                                for (int i = 0; i < adsTableSizes.getSymbolCount(); i++) {
+                                                    try {
+                                                        AdsSymbolTableEntry adsSymbolTableEntry = AdsSymbolTableEntry.staticParse(rb2);
+                                                        symbols.add(adsSymbolTableEntry);
+                                                    } catch (ParseException e) {
+                                                        throw new RuntimeException(e);
+                                                    }
+                                                }
+                                                future.complete(null);
+                                            }
+                                        }));
                                 }
-                            }));*/
+                            }));
                     } catch (ParseException e) {
                         future.completeExceptionally(new PlcException("Error loading the table sizes", e));
                     }
@@ -182,13 +186,17 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
                     // TODO: Implement this correctly.
                     future.completeExceptionally(new PlcException("Result is " + responseAdsData.getResult()));
                 }
-                // Finish the request-transaction.
-                transaction.endRequest();
             }));
         future.whenComplete((unused, throwable) -> {
             if(throwable != null) {
                 LOGGER.error("Error fetching symbol and datatype table sizes");
             } else {
+                for (AdsSymbolTableEntry symbol : symbols) {
+                    System.out.println(symbol.getName());
+                }
+                /*for (AdsDataTypeTableEntry dataType : dataTypes) {
+                    System.out.println(dataType);
+                }*/
                 context.fireConnected();
             }
         });
@@ -332,7 +340,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements
             ReservedIndexGroups.ADSIGRP_MULTIPLE_READ.getValue(), directAdsFields.size(), expectedResponseDataSize,
             directAdsFields.stream().map(directAdsField -> new AdsMultiRequestItemRead(
                     directAdsField.getIndexGroup(), directAdsField.getIndexOffset(),
-                    (directAdsField.getAdsDataType().getNumBytes() * directAdsField.getNumberOfElements())))
+                    ((long) directAdsField.getAdsDataType().getNumBytes() * directAdsField.getNumberOfElements())))
                 .collect(Collectors.toList()), null);
 
         AmsPacket amsPacket = new AmsPacket(configuration.getTargetAmsNetId(), configuration.getTargetAmsPort(),
diff --git a/protocols/ads/src/main/resources/protocols/ads/ads.mspec b/protocols/ads/src/main/resources/protocols/ads/ads.mspec
index a5d6bde5f..1b79e178b 100644
--- a/protocols/ads/src/main/resources/protocols/ads/ads.mspec
+++ b/protocols/ads/src/main/resources/protocols/ads/ads.mspec
@@ -795,29 +795,42 @@
 	// Will have to continue searching for more details on how to decode this.
 	// I would assume that we'll have some "optional" fields here which depend
 	// on values in the flags section.
-	[array    byte                         rest               count 'entryLength - curPos']
+	[array    byte                         rest               length 'entryLength - curPos']
 ]
 
 // https://gitlab.com/xilix-systems-llc/go-native-ads/-/blob/master/symbols.go#L15
-[type AdsDataTypeTableEntry byteOrder='LITTLE_ENDIAN'
-	[simple   uint 32                            entryLength                           ]
-	[simple   uint 32                            version                               ]
-	[simple   uint 32                            hashValue                             ]
-	[simple   uint 32                            typeHashValue                         ]
-	[simple   uint 32                            size                                  ]
-	[simple   uint 32                            offs                                  ]
-	[simple   uint 32                            dataType                              ]
-	[simple   uint 32                            flags                                 ]
-	[implicit uint 16                            nameLength         'STR_LEN(name)'    ]
-	[implicit uint 16                            typeNameLength     'STR_LEN(typeName)']
-	[implicit uint 16                            commentLength      'STR_LEN(comment)' ]
-	[simple   uint 16                            arrayDim                              ]
-	[simple   uint 16                            subItems                              ]
-	[simple   vstring '(nameLength - 1) * 8'     name                                  ]
-	[const    uint 8                             nameTerminator     0x00               ]
-	[simple   vstring '(typeNameLength - 1) * 8' typeName                              ]
-	[const    uint 8                             typeNameTerminator 0x00               ]
-	[simple   vstring '(commentLength - 1) * 8'  comment                               ]
-	[const    uint 8                             commentTerminator  0x00               ]
-	//[array    AdsDataTypeTableEntry              children           length               '']
+[discriminatedType AdsDataTypeTableEntry byteOrder='LITTLE_ENDIAN'
+	[simple   uint 32                      entryLength                                                  ]
+	[simple   uint 32                      version                                                      ]
+	[simple   uint 32                      hashValue                                                    ]
+	[simple   uint 32                      typeHashValue                                                ]
+	[simple   uint 32                      size                                                         ]
+	[simple   uint 32                      offs                                                         ]
+	[simple   uint 32                      dataType                                                     ]
+	[simple   uint 32                      flags                                                        ]
+	[implicit uint 16                      nameLength         'STR_LEN(name)'                           ]
+	[implicit uint 16                      typeNameLength     'STR_LEN(typeName)'                       ]
+	[implicit uint 16                      commentLength      'STR_LEN(comment)'                        ]
+	[simple   uint 16                      arrayDimensions                                              ]
+	[simple   uint 16                      numChildren                                                  ]
+	[simple   vstring 'nameLength * 8'     name                                                         ]
+	[const    uint 8                       nameTerminator     0x00                                      ]
+	[simple   vstring 'typeNameLength * 8' typeName                                                     ]
+	[const    uint 8                       typeNameTerminator 0x00                                      ]
+	[simple   vstring 'commentLength * 8'  comment                                                      ]
+	[const    uint 8                       commentTerminator  0x00                                      ]
+    [array    AdsDataTypeArrayInfo         arrayInfo          count               'arrayDimensions'     ]
+   	[array    AdsDataTypeTableEntry        children           count               'numChildren'         ]
+	// Gobbling up the rest, but it seems there is content in here, when looking
+	// at the data in wireshark, it seems to be related to the flags field.
+	// Will have to continue searching for more details on how to decode this.
+	// I would assume that we'll have some "optional" fields here which depend
+	// on values in the flags section.
+	[array    byte                         rest               length              'entryLength - curPos']
+]
+
+[type AdsDataTypeArrayInfo byteOrder='LITTLE_ENDIAN'
+    [simple  uint 32 lowerBound                            ]
+    [simple  uint 32 numElements                           ]
+    [virtual uint 32 upperBound  'lowerBound + numElements']
 ]