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']
]