This is an automated email from the ASF dual-hosted git repository. cdutz pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/plc4x.git
The following commit(s) were added to refs/heads/develop by this push: new afd3939c6 chore(protocol/ads): Work on the new ADS driver - Switched the dataIo parsing of STRING and WSTRING from manual fields to simple fields with vstring - Fixed a problem in the go code generation causing problems accessing the "stringLength" serializer argument in dataIo types - Implemented the new state-machine for PLC4J ads driver afd3939c6 is described below commit afd3939c6eaf52670e69b3daaa4ecea87a5c3ab0 Author: Christofer Dutz <christofer.d...@c-ware.de> AuthorDate: Mon Sep 26 10:37:30 2022 +0200 chore(protocol/ads): Work on the new ADS driver - Switched the dataIo parsing of STRING and WSTRING from manual fields to simple fields with vstring - Fixed a problem in the go code generation causing problems accessing the "stringLength" serializer argument in dataIo types - Implemented the new state-machine for PLC4J ads driver --- .../language/go/GoLanguageTemplateHelper.java | 12 +- .../mspec/model/definitions/DefaultArgument.java | 5 + plc4go/protocols/ads/readwrite/model/DataItem.go | 44 +- .../ads/readwrite/model/DefaultAmsPorts.go | 552 +++++++++++++++++++++ .../ads/readwrite/model/ReservedIndexGroups.go | 8 + .../knxnetip/readwrite/model/KnxManufacturer.go | 34 +- plc4go/protocols/s7/readwrite/model/DataItem.go | 4 +- .../plc4x/java/ads/protocol/AdsProtocolLogic.java | 444 ++++++++++++----- .../java/ads/readwrite/utils/StaticHelper.java | 93 ---- .../plc4x/protocol/ads/ManualAdsDriverTest.java | 50 +- .../java/canopen/readwrite/utils/StaticHelper.java | 2 +- .../java/s7/readwrite/utils/StaticHelper.java | 2 +- .../plc4x/java/spi/generation/ReadBuffer.java | 4 +- .../java/spi/generation/ReadBufferByteBased.java | 69 ++- .../plc4x/java/spi/generation/ReadBufferTest.java | 2 +- .../apache/plc4x/java/s7/utils/StaticHelper.java | 2 +- .../org/apache/plc4x/test/manual/ManualTest.java | 13 +- .../knxnetip/readwrite/model/KnxManufacturer.cs | 23 +- .../ads/src/main/resources/protocols/ads/ads.mspec | 10 +- 19 files changed, 1060 insertions(+), 313 deletions(-) diff --git a/code-generation/language-go/src/main/java/org/apache/plc4x/language/go/GoLanguageTemplateHelper.java b/code-generation/language-go/src/main/java/org/apache/plc4x/language/go/GoLanguageTemplateHelper.java index 0afc466df..858ef2c34 100644 --- a/code-generation/language-go/src/main/java/org/apache/plc4x/language/go/GoLanguageTemplateHelper.java +++ b/code-generation/language-go/src/main/java/org/apache/plc4x/language/go/GoLanguageTemplateHelper.java @@ -20,9 +20,11 @@ package org.apache.plc4x.language.go; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; +import org.apache.plc4x.plugins.codegenerator.language.mspec.model.definitions.DefaultArgument; import org.apache.plc4x.plugins.codegenerator.language.mspec.model.references.DefaultBooleanTypeReference; import org.apache.plc4x.plugins.codegenerator.language.mspec.model.references.DefaultFloatTypeReference; import org.apache.plc4x.plugins.codegenerator.language.mspec.model.references.DefaultIntegerTypeReference; +import org.apache.plc4x.plugins.codegenerator.language.mspec.model.references.DefaultVstringTypeReference; import org.apache.plc4x.plugins.codegenerator.language.mspec.model.terms.DefaultStringLiteral; import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.BaseFreemarkerLanguageTemplateHelper; import org.apache.plc4x.plugins.codegenerator.protocol.freemarker.FreemarkerException; @@ -467,7 +469,7 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp .orElseThrow(() -> new RuntimeException("Encoding must be a literal")) .asStringLiteral() .orElseThrow(() -> new RuntimeException("Encoding must be a quoted string value")).getValue(); - String lengthExpression = toExpression(field, null, vstringTypeReference.getLengthExpression(), null, null, true, false); + String lengthExpression = toExpression(field, null, vstringTypeReference.getLengthExpression(), null, Collections.singletonList(new DefaultArgument("stringLength", new DefaultIntegerTypeReference(SimpleTypeReference.SimpleBaseType.INT, 32))), true, false); String length = Integer.toString(simpleTypeReference.getSizeInBits()); return "writeBuffer.WriteString(\"" + logicalName + "\", uint32(" + lengthExpression + "), \"" + encoding + "\", " + fieldName + writerArgsString + ")"; @@ -847,7 +849,15 @@ public class GoLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelp } } + // This is a special case for DataIo string types, which need to access the stringLength if ((serializerArguments != null) && serializerArguments.stream() + .anyMatch(argument -> argument.getName().equals(variableLiteralName)) && "stringLength".equals(variableLiteralName)) { + tracer = tracer.dive("serialization argument"); + return tracer + variableLiteralName + + variableLiteral.getChild() + .map(child -> "." + capitalize(toVariableExpression(field, typeReference, child, parserArguments, serializerArguments, false, suppressPointerAccess, true))) + .orElse(""); + } else if ((serializerArguments != null) && serializerArguments.stream() .anyMatch(argument -> argument.getName().equals(variableLiteralName))) { tracer = tracer.dive("serialization argument"); return tracer + "m." + capitalize(variableLiteralName) + diff --git a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultArgument.java b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultArgument.java index 93c57f81b..df1fad80e 100644 --- a/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultArgument.java +++ b/code-generation/protocol-base-mspec/src/main/java/org/apache/plc4x/plugins/codegenerator/language/mspec/model/definitions/DefaultArgument.java @@ -37,6 +37,11 @@ public class DefaultArgument implements Argument { this.name = Objects.requireNonNull(name); } + public DefaultArgument(String name, TypeReference type) { + this.name = Objects.requireNonNull(name); + this.type = type; + } + public String getName() { return name; } diff --git a/plc4go/protocols/ads/readwrite/model/DataItem.go b/plc4go/protocols/ads/readwrite/model/DataItem.go index ad0f76c64..4eb0283da 100644 --- a/plc4go/protocols/ads/readwrite/model/DataItem.go +++ b/plc4go/protocols/ads/readwrite/model/DataItem.go @@ -166,19 +166,29 @@ func DataItemParse(readBuffer utils.ReadBuffer, plcValueType PlcValueType, strin readBuffer.CloseContext("DataItem") return values.NewPlcSTRING(value), nil case plcValueType == PlcValueType_STRING: // STRING - // Manual Field (value) - value, _valueErr := ParseAmsString(readBuffer, stringLength, "UTF-8") + // Simple Field (value) + value, _valueErr := readBuffer.ReadString("value", uint32((stringLength)*(8))) if _valueErr != nil { return nil, errors.Wrap(_valueErr, "Error parsing 'value' field") } + + // Reserved Field (Just skip the bytes) + if _, _err := readBuffer.ReadUint8("reserved", 8); _err != nil { + return nil, errors.Wrap(_err, "Error parsing reserved field") + } readBuffer.CloseContext("DataItem") return values.NewPlcSTRING(value), nil case plcValueType == PlcValueType_WSTRING: // STRING - // Manual Field (value) - value, _valueErr := ParseAmsString(readBuffer, stringLength, "UTF-16") + // Simple Field (value) + value, _valueErr := readBuffer.ReadString("value", uint32(((stringLength)*(8))*(2))) if _valueErr != nil { return nil, errors.Wrap(_valueErr, "Error parsing 'value' field") } + + // Reserved Field (Just skip the bytes) + if _, _err := readBuffer.ReadUint16("reserved", 16); _err != nil { + return nil, errors.Wrap(_err, "Error parsing reserved field") + } readBuffer.CloseContext("DataItem") return values.NewPlcSTRING(value), nil case plcValueType == PlcValueType_TIME: // TIME @@ -320,20 +330,28 @@ func DataItemSerialize(writeBuffer utils.WriteBuffer, value api.PlcValue, plcVal } case plcValueType == PlcValueType_WCHAR: // STRING // Simple Field (value) - if _err := writeBuffer.WriteString("value", uint32(16), "UTF-16", value.GetString()); _err != nil { + if _err := writeBuffer.WriteString("value", uint32(16), "UTF-16LE", value.GetString()); _err != nil { return errors.Wrap(_err, "Error serializing 'value' field") } case plcValueType == PlcValueType_STRING: // STRING - // Manual Field (value) - _valueErr := SerializeAmsString(writeBuffer, value, m.StringLength, "UTF-8") - if _valueErr != nil { - return errors.Wrap(_valueErr, "Error serializing 'value' field") + // Simple Field (value) + if _err := writeBuffer.WriteString("value", uint32((stringLength)*(8)), "UTF-8", value.GetString()); _err != nil { + return errors.Wrap(_err, "Error serializing 'value' field") + } + + // Reserved Field (Just skip the bytes) + if _err := writeBuffer.WriteUint8("reserved", 8, uint8(0x00)); _err != nil { + return errors.Wrap(_err, "Error serializing reserved field") } case plcValueType == PlcValueType_WSTRING: // STRING - // Manual Field (value) - _valueErr := SerializeAmsString(writeBuffer, value, m.StringLength, "UTF-16") - if _valueErr != nil { - return errors.Wrap(_valueErr, "Error serializing 'value' field") + // Simple Field (value) + if _err := writeBuffer.WriteString("value", uint32(((stringLength)*(8))*(2)), "UTF-16LE", value.GetString()); _err != nil { + return errors.Wrap(_err, "Error serializing 'value' field") + } + + // Reserved Field (Just skip the bytes) + if _err := writeBuffer.WriteUint16("reserved", 16, uint16(0x0000)); _err != nil { + return errors.Wrap(_err, "Error serializing reserved field") } case plcValueType == PlcValueType_TIME: // TIME // Simple Field (value) diff --git a/plc4go/protocols/ads/readwrite/model/DefaultAmsPorts.go b/plc4go/protocols/ads/readwrite/model/DefaultAmsPorts.go new file mode 100644 index 000000000..2219b94a7 --- /dev/null +++ b/plc4go/protocols/ads/readwrite/model/DefaultAmsPorts.go @@ -0,0 +1,552 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package model + +import ( + "github.com/apache/plc4x/plc4go/spi/utils" + "github.com/pkg/errors" +) + +// Code generated by code-generation. DO NOT EDIT. + +// DefaultAmsPorts is an enum +type DefaultAmsPorts uint16 + +type IDefaultAmsPorts interface { + Serialize(writeBuffer utils.WriteBuffer) error +} + +const ( + DefaultAmsPorts_CAM_CONTROLLER DefaultAmsPorts = 900 + DefaultAmsPorts_RUNTIME_SYSTEM_01 DefaultAmsPorts = 851 + DefaultAmsPorts_RUNTIME_SYSTEM_02 DefaultAmsPorts = 852 + DefaultAmsPorts_RUNTIME_SYSTEM_03 DefaultAmsPorts = 853 + DefaultAmsPorts_RUNTIME_SYSTEM_04 DefaultAmsPorts = 854 + DefaultAmsPorts_RUNTIME_SYSTEM_05 DefaultAmsPorts = 855 + DefaultAmsPorts_RUNTIME_SYSTEM_06 DefaultAmsPorts = 856 + DefaultAmsPorts_RUNTIME_SYSTEM_07 DefaultAmsPorts = 857 + DefaultAmsPorts_RUNTIME_SYSTEM_08 DefaultAmsPorts = 858 + DefaultAmsPorts_RUNTIME_SYSTEM_09 DefaultAmsPorts = 859 + DefaultAmsPorts_RUNTIME_SYSTEM_10 DefaultAmsPorts = 860 + DefaultAmsPorts_RUNTIME_SYSTEM_11 DefaultAmsPorts = 861 + DefaultAmsPorts_RUNTIME_SYSTEM_12 DefaultAmsPorts = 862 + DefaultAmsPorts_RUNTIME_SYSTEM_13 DefaultAmsPorts = 863 + DefaultAmsPorts_RUNTIME_SYSTEM_14 DefaultAmsPorts = 864 + DefaultAmsPorts_RUNTIME_SYSTEM_15 DefaultAmsPorts = 865 + DefaultAmsPorts_RUNTIME_SYSTEM_16 DefaultAmsPorts = 866 + DefaultAmsPorts_RUNTIME_SYSTEM_17 DefaultAmsPorts = 867 + DefaultAmsPorts_RUNTIME_SYSTEM_18 DefaultAmsPorts = 868 + DefaultAmsPorts_RUNTIME_SYSTEM_19 DefaultAmsPorts = 869 + DefaultAmsPorts_RUNTIME_SYSTEM_20 DefaultAmsPorts = 870 + DefaultAmsPorts_RUNTIME_SYSTEM_21 DefaultAmsPorts = 871 + DefaultAmsPorts_RUNTIME_SYSTEM_22 DefaultAmsPorts = 872 + DefaultAmsPorts_RUNTIME_SYSTEM_23 DefaultAmsPorts = 873 + DefaultAmsPorts_RUNTIME_SYSTEM_24 DefaultAmsPorts = 874 + DefaultAmsPorts_RUNTIME_SYSTEM_25 DefaultAmsPorts = 875 + DefaultAmsPorts_RUNTIME_SYSTEM_26 DefaultAmsPorts = 876 + DefaultAmsPorts_RUNTIME_SYSTEM_27 DefaultAmsPorts = 877 + DefaultAmsPorts_RUNTIME_SYSTEM_28 DefaultAmsPorts = 878 + DefaultAmsPorts_RUNTIME_SYSTEM_29 DefaultAmsPorts = 879 + DefaultAmsPorts_RUNTIME_SYSTEM_30 DefaultAmsPorts = 880 + DefaultAmsPorts_RUNTIME_SYSTEM_31 DefaultAmsPorts = 881 + DefaultAmsPorts_RUNTIME_SYSTEM_32 DefaultAmsPorts = 882 + DefaultAmsPorts_RUNTIME_SYSTEM_33 DefaultAmsPorts = 883 + DefaultAmsPorts_RUNTIME_SYSTEM_34 DefaultAmsPorts = 884 + DefaultAmsPorts_RUNTIME_SYSTEM_35 DefaultAmsPorts = 885 + DefaultAmsPorts_RUNTIME_SYSTEM_36 DefaultAmsPorts = 886 + DefaultAmsPorts_RUNTIME_SYSTEM_37 DefaultAmsPorts = 887 + DefaultAmsPorts_RUNTIME_SYSTEM_38 DefaultAmsPorts = 888 + DefaultAmsPorts_RUNTIME_SYSTEM_39 DefaultAmsPorts = 889 + DefaultAmsPorts_RUNTIME_SYSTEM_40 DefaultAmsPorts = 890 + DefaultAmsPorts_RUNTIME_SYSTEM_41 DefaultAmsPorts = 891 + DefaultAmsPorts_RUNTIME_SYSTEM_42 DefaultAmsPorts = 892 + DefaultAmsPorts_RUNTIME_SYSTEM_43 DefaultAmsPorts = 893 + DefaultAmsPorts_RUNTIME_SYSTEM_44 DefaultAmsPorts = 894 + DefaultAmsPorts_RUNTIME_SYSTEM_45 DefaultAmsPorts = 895 + DefaultAmsPorts_RUNTIME_SYSTEM_46 DefaultAmsPorts = 896 + DefaultAmsPorts_RUNTIME_SYSTEM_47 DefaultAmsPorts = 897 + DefaultAmsPorts_RUNTIME_SYSTEM_48 DefaultAmsPorts = 898 + DefaultAmsPorts_RUNTIME_SYSTEM_49 DefaultAmsPorts = 899 + DefaultAmsPorts_NC DefaultAmsPorts = 500 + DefaultAmsPorts_RESERVED DefaultAmsPorts = 400 + DefaultAmsPorts_IO DefaultAmsPorts = 300 + DefaultAmsPorts_REAL_TIME_CORE DefaultAmsPorts = 200 + DefaultAmsPorts_EVENT_SYSTEM_LOGGER DefaultAmsPorts = 100 +) + +var DefaultAmsPortsValues []DefaultAmsPorts + +func init() { + _ = errors.New + DefaultAmsPortsValues = []DefaultAmsPorts{ + DefaultAmsPorts_CAM_CONTROLLER, + DefaultAmsPorts_RUNTIME_SYSTEM_01, + DefaultAmsPorts_RUNTIME_SYSTEM_02, + DefaultAmsPorts_RUNTIME_SYSTEM_03, + DefaultAmsPorts_RUNTIME_SYSTEM_04, + DefaultAmsPorts_RUNTIME_SYSTEM_05, + DefaultAmsPorts_RUNTIME_SYSTEM_06, + DefaultAmsPorts_RUNTIME_SYSTEM_07, + DefaultAmsPorts_RUNTIME_SYSTEM_08, + DefaultAmsPorts_RUNTIME_SYSTEM_09, + DefaultAmsPorts_RUNTIME_SYSTEM_10, + DefaultAmsPorts_RUNTIME_SYSTEM_11, + DefaultAmsPorts_RUNTIME_SYSTEM_12, + DefaultAmsPorts_RUNTIME_SYSTEM_13, + DefaultAmsPorts_RUNTIME_SYSTEM_14, + DefaultAmsPorts_RUNTIME_SYSTEM_15, + DefaultAmsPorts_RUNTIME_SYSTEM_16, + DefaultAmsPorts_RUNTIME_SYSTEM_17, + DefaultAmsPorts_RUNTIME_SYSTEM_18, + DefaultAmsPorts_RUNTIME_SYSTEM_19, + DefaultAmsPorts_RUNTIME_SYSTEM_20, + DefaultAmsPorts_RUNTIME_SYSTEM_21, + DefaultAmsPorts_RUNTIME_SYSTEM_22, + DefaultAmsPorts_RUNTIME_SYSTEM_23, + DefaultAmsPorts_RUNTIME_SYSTEM_24, + DefaultAmsPorts_RUNTIME_SYSTEM_25, + DefaultAmsPorts_RUNTIME_SYSTEM_26, + DefaultAmsPorts_RUNTIME_SYSTEM_27, + DefaultAmsPorts_RUNTIME_SYSTEM_28, + DefaultAmsPorts_RUNTIME_SYSTEM_29, + DefaultAmsPorts_RUNTIME_SYSTEM_30, + DefaultAmsPorts_RUNTIME_SYSTEM_31, + DefaultAmsPorts_RUNTIME_SYSTEM_32, + DefaultAmsPorts_RUNTIME_SYSTEM_33, + DefaultAmsPorts_RUNTIME_SYSTEM_34, + DefaultAmsPorts_RUNTIME_SYSTEM_35, + DefaultAmsPorts_RUNTIME_SYSTEM_36, + DefaultAmsPorts_RUNTIME_SYSTEM_37, + DefaultAmsPorts_RUNTIME_SYSTEM_38, + DefaultAmsPorts_RUNTIME_SYSTEM_39, + DefaultAmsPorts_RUNTIME_SYSTEM_40, + DefaultAmsPorts_RUNTIME_SYSTEM_41, + DefaultAmsPorts_RUNTIME_SYSTEM_42, + DefaultAmsPorts_RUNTIME_SYSTEM_43, + DefaultAmsPorts_RUNTIME_SYSTEM_44, + DefaultAmsPorts_RUNTIME_SYSTEM_45, + DefaultAmsPorts_RUNTIME_SYSTEM_46, + DefaultAmsPorts_RUNTIME_SYSTEM_47, + DefaultAmsPorts_RUNTIME_SYSTEM_48, + DefaultAmsPorts_RUNTIME_SYSTEM_49, + DefaultAmsPorts_NC, + DefaultAmsPorts_RESERVED, + DefaultAmsPorts_IO, + DefaultAmsPorts_REAL_TIME_CORE, + DefaultAmsPorts_EVENT_SYSTEM_LOGGER, + } +} + +func DefaultAmsPortsByValue(value uint16) (enum DefaultAmsPorts, ok bool) { + switch value { + case 100: + return DefaultAmsPorts_EVENT_SYSTEM_LOGGER, true + case 200: + return DefaultAmsPorts_REAL_TIME_CORE, true + case 300: + return DefaultAmsPorts_IO, true + case 400: + return DefaultAmsPorts_RESERVED, true + case 500: + return DefaultAmsPorts_NC, true + case 851: + return DefaultAmsPorts_RUNTIME_SYSTEM_01, true + case 852: + return DefaultAmsPorts_RUNTIME_SYSTEM_02, true + case 853: + return DefaultAmsPorts_RUNTIME_SYSTEM_03, true + case 854: + return DefaultAmsPorts_RUNTIME_SYSTEM_04, true + case 855: + return DefaultAmsPorts_RUNTIME_SYSTEM_05, true + case 856: + return DefaultAmsPorts_RUNTIME_SYSTEM_06, true + case 857: + return DefaultAmsPorts_RUNTIME_SYSTEM_07, true + case 858: + return DefaultAmsPorts_RUNTIME_SYSTEM_08, true + case 859: + return DefaultAmsPorts_RUNTIME_SYSTEM_09, true + case 860: + return DefaultAmsPorts_RUNTIME_SYSTEM_10, true + case 861: + return DefaultAmsPorts_RUNTIME_SYSTEM_11, true + case 862: + return DefaultAmsPorts_RUNTIME_SYSTEM_12, true + case 863: + return DefaultAmsPorts_RUNTIME_SYSTEM_13, true + case 864: + return DefaultAmsPorts_RUNTIME_SYSTEM_14, true + case 865: + return DefaultAmsPorts_RUNTIME_SYSTEM_15, true + case 866: + return DefaultAmsPorts_RUNTIME_SYSTEM_16, true + case 867: + return DefaultAmsPorts_RUNTIME_SYSTEM_17, true + case 868: + return DefaultAmsPorts_RUNTIME_SYSTEM_18, true + case 869: + return DefaultAmsPorts_RUNTIME_SYSTEM_19, true + case 870: + return DefaultAmsPorts_RUNTIME_SYSTEM_20, true + case 871: + return DefaultAmsPorts_RUNTIME_SYSTEM_21, true + case 872: + return DefaultAmsPorts_RUNTIME_SYSTEM_22, true + case 873: + return DefaultAmsPorts_RUNTIME_SYSTEM_23, true + case 874: + return DefaultAmsPorts_RUNTIME_SYSTEM_24, true + case 875: + return DefaultAmsPorts_RUNTIME_SYSTEM_25, true + case 876: + return DefaultAmsPorts_RUNTIME_SYSTEM_26, true + case 877: + return DefaultAmsPorts_RUNTIME_SYSTEM_27, true + case 878: + return DefaultAmsPorts_RUNTIME_SYSTEM_28, true + case 879: + return DefaultAmsPorts_RUNTIME_SYSTEM_29, true + case 880: + return DefaultAmsPorts_RUNTIME_SYSTEM_30, true + case 881: + return DefaultAmsPorts_RUNTIME_SYSTEM_31, true + case 882: + return DefaultAmsPorts_RUNTIME_SYSTEM_32, true + case 883: + return DefaultAmsPorts_RUNTIME_SYSTEM_33, true + case 884: + return DefaultAmsPorts_RUNTIME_SYSTEM_34, true + case 885: + return DefaultAmsPorts_RUNTIME_SYSTEM_35, true + case 886: + return DefaultAmsPorts_RUNTIME_SYSTEM_36, true + case 887: + return DefaultAmsPorts_RUNTIME_SYSTEM_37, true + case 888: + return DefaultAmsPorts_RUNTIME_SYSTEM_38, true + case 889: + return DefaultAmsPorts_RUNTIME_SYSTEM_39, true + case 890: + return DefaultAmsPorts_RUNTIME_SYSTEM_40, true + case 891: + return DefaultAmsPorts_RUNTIME_SYSTEM_41, true + case 892: + return DefaultAmsPorts_RUNTIME_SYSTEM_42, true + case 893: + return DefaultAmsPorts_RUNTIME_SYSTEM_43, true + case 894: + return DefaultAmsPorts_RUNTIME_SYSTEM_44, true + case 895: + return DefaultAmsPorts_RUNTIME_SYSTEM_45, true + case 896: + return DefaultAmsPorts_RUNTIME_SYSTEM_46, true + case 897: + return DefaultAmsPorts_RUNTIME_SYSTEM_47, true + case 898: + return DefaultAmsPorts_RUNTIME_SYSTEM_48, true + case 899: + return DefaultAmsPorts_RUNTIME_SYSTEM_49, true + case 900: + return DefaultAmsPorts_CAM_CONTROLLER, true + } + return 0, false +} + +func DefaultAmsPortsByName(value string) (enum DefaultAmsPorts, ok bool) { + switch value { + case "EVENT_SYSTEM_LOGGER": + return DefaultAmsPorts_EVENT_SYSTEM_LOGGER, true + case "REAL_TIME_CORE": + return DefaultAmsPorts_REAL_TIME_CORE, true + case "IO": + return DefaultAmsPorts_IO, true + case "RESERVED": + return DefaultAmsPorts_RESERVED, true + case "NC": + return DefaultAmsPorts_NC, true + case "RUNTIME_SYSTEM_01": + return DefaultAmsPorts_RUNTIME_SYSTEM_01, true + case "RUNTIME_SYSTEM_02": + return DefaultAmsPorts_RUNTIME_SYSTEM_02, true + case "RUNTIME_SYSTEM_03": + return DefaultAmsPorts_RUNTIME_SYSTEM_03, true + case "RUNTIME_SYSTEM_04": + return DefaultAmsPorts_RUNTIME_SYSTEM_04, true + case "RUNTIME_SYSTEM_05": + return DefaultAmsPorts_RUNTIME_SYSTEM_05, true + case "RUNTIME_SYSTEM_06": + return DefaultAmsPorts_RUNTIME_SYSTEM_06, true + case "RUNTIME_SYSTEM_07": + return DefaultAmsPorts_RUNTIME_SYSTEM_07, true + case "RUNTIME_SYSTEM_08": + return DefaultAmsPorts_RUNTIME_SYSTEM_08, true + case "RUNTIME_SYSTEM_09": + return DefaultAmsPorts_RUNTIME_SYSTEM_09, true + case "RUNTIME_SYSTEM_10": + return DefaultAmsPorts_RUNTIME_SYSTEM_10, true + case "RUNTIME_SYSTEM_11": + return DefaultAmsPorts_RUNTIME_SYSTEM_11, true + case "RUNTIME_SYSTEM_12": + return DefaultAmsPorts_RUNTIME_SYSTEM_12, true + case "RUNTIME_SYSTEM_13": + return DefaultAmsPorts_RUNTIME_SYSTEM_13, true + case "RUNTIME_SYSTEM_14": + return DefaultAmsPorts_RUNTIME_SYSTEM_14, true + case "RUNTIME_SYSTEM_15": + return DefaultAmsPorts_RUNTIME_SYSTEM_15, true + case "RUNTIME_SYSTEM_16": + return DefaultAmsPorts_RUNTIME_SYSTEM_16, true + case "RUNTIME_SYSTEM_17": + return DefaultAmsPorts_RUNTIME_SYSTEM_17, true + case "RUNTIME_SYSTEM_18": + return DefaultAmsPorts_RUNTIME_SYSTEM_18, true + case "RUNTIME_SYSTEM_19": + return DefaultAmsPorts_RUNTIME_SYSTEM_19, true + case "RUNTIME_SYSTEM_20": + return DefaultAmsPorts_RUNTIME_SYSTEM_20, true + case "RUNTIME_SYSTEM_21": + return DefaultAmsPorts_RUNTIME_SYSTEM_21, true + case "RUNTIME_SYSTEM_22": + return DefaultAmsPorts_RUNTIME_SYSTEM_22, true + case "RUNTIME_SYSTEM_23": + return DefaultAmsPorts_RUNTIME_SYSTEM_23, true + case "RUNTIME_SYSTEM_24": + return DefaultAmsPorts_RUNTIME_SYSTEM_24, true + case "RUNTIME_SYSTEM_25": + return DefaultAmsPorts_RUNTIME_SYSTEM_25, true + case "RUNTIME_SYSTEM_26": + return DefaultAmsPorts_RUNTIME_SYSTEM_26, true + case "RUNTIME_SYSTEM_27": + return DefaultAmsPorts_RUNTIME_SYSTEM_27, true + case "RUNTIME_SYSTEM_28": + return DefaultAmsPorts_RUNTIME_SYSTEM_28, true + case "RUNTIME_SYSTEM_29": + return DefaultAmsPorts_RUNTIME_SYSTEM_29, true + case "RUNTIME_SYSTEM_30": + return DefaultAmsPorts_RUNTIME_SYSTEM_30, true + case "RUNTIME_SYSTEM_31": + return DefaultAmsPorts_RUNTIME_SYSTEM_31, true + case "RUNTIME_SYSTEM_32": + return DefaultAmsPorts_RUNTIME_SYSTEM_32, true + case "RUNTIME_SYSTEM_33": + return DefaultAmsPorts_RUNTIME_SYSTEM_33, true + case "RUNTIME_SYSTEM_34": + return DefaultAmsPorts_RUNTIME_SYSTEM_34, true + case "RUNTIME_SYSTEM_35": + return DefaultAmsPorts_RUNTIME_SYSTEM_35, true + case "RUNTIME_SYSTEM_36": + return DefaultAmsPorts_RUNTIME_SYSTEM_36, true + case "RUNTIME_SYSTEM_37": + return DefaultAmsPorts_RUNTIME_SYSTEM_37, true + case "RUNTIME_SYSTEM_38": + return DefaultAmsPorts_RUNTIME_SYSTEM_38, true + case "RUNTIME_SYSTEM_39": + return DefaultAmsPorts_RUNTIME_SYSTEM_39, true + case "RUNTIME_SYSTEM_40": + return DefaultAmsPorts_RUNTIME_SYSTEM_40, true + case "RUNTIME_SYSTEM_41": + return DefaultAmsPorts_RUNTIME_SYSTEM_41, true + case "RUNTIME_SYSTEM_42": + return DefaultAmsPorts_RUNTIME_SYSTEM_42, true + case "RUNTIME_SYSTEM_43": + return DefaultAmsPorts_RUNTIME_SYSTEM_43, true + case "RUNTIME_SYSTEM_44": + return DefaultAmsPorts_RUNTIME_SYSTEM_44, true + case "RUNTIME_SYSTEM_45": + return DefaultAmsPorts_RUNTIME_SYSTEM_45, true + case "RUNTIME_SYSTEM_46": + return DefaultAmsPorts_RUNTIME_SYSTEM_46, true + case "RUNTIME_SYSTEM_47": + return DefaultAmsPorts_RUNTIME_SYSTEM_47, true + case "RUNTIME_SYSTEM_48": + return DefaultAmsPorts_RUNTIME_SYSTEM_48, true + case "RUNTIME_SYSTEM_49": + return DefaultAmsPorts_RUNTIME_SYSTEM_49, true + case "CAM_CONTROLLER": + return DefaultAmsPorts_CAM_CONTROLLER, true + } + return 0, false +} + +func DefaultAmsPortsKnows(value uint16) bool { + for _, typeValue := range DefaultAmsPortsValues { + if uint16(typeValue) == value { + return true + } + } + return false +} + +func CastDefaultAmsPorts(structType interface{}) DefaultAmsPorts { + castFunc := func(typ interface{}) DefaultAmsPorts { + if sDefaultAmsPorts, ok := typ.(DefaultAmsPorts); ok { + return sDefaultAmsPorts + } + return 0 + } + return castFunc(structType) +} + +func (m DefaultAmsPorts) GetLengthInBits() uint16 { + return 16 +} + +func (m DefaultAmsPorts) GetLengthInBytes() uint16 { + return m.GetLengthInBits() / 8 +} + +func DefaultAmsPortsParse(readBuffer utils.ReadBuffer) (DefaultAmsPorts, error) { + val, err := readBuffer.ReadUint16("DefaultAmsPorts", 16) + if err != nil { + return 0, errors.Wrap(err, "error reading DefaultAmsPorts") + } + if enum, ok := DefaultAmsPortsByValue(val); !ok { + Plc4xModelLog.Debug().Msgf("no value %x found for RequestType", val) + return DefaultAmsPorts(val), nil + } else { + return enum, nil + } +} + +func (e DefaultAmsPorts) Serialize(writeBuffer utils.WriteBuffer) error { + return writeBuffer.WriteUint16("DefaultAmsPorts", 16, uint16(e), utils.WithAdditionalStringRepresentation(e.PLC4XEnumName())) +} + +// PLC4XEnumName returns the name that is used in code to identify this enum +func (e DefaultAmsPorts) PLC4XEnumName() string { + switch e { + case DefaultAmsPorts_EVENT_SYSTEM_LOGGER: + return "EVENT_SYSTEM_LOGGER" + case DefaultAmsPorts_REAL_TIME_CORE: + return "REAL_TIME_CORE" + case DefaultAmsPorts_IO: + return "IO" + case DefaultAmsPorts_RESERVED: + return "RESERVED" + case DefaultAmsPorts_NC: + return "NC" + case DefaultAmsPorts_RUNTIME_SYSTEM_01: + return "RUNTIME_SYSTEM_01" + case DefaultAmsPorts_RUNTIME_SYSTEM_02: + return "RUNTIME_SYSTEM_02" + case DefaultAmsPorts_RUNTIME_SYSTEM_03: + return "RUNTIME_SYSTEM_03" + case DefaultAmsPorts_RUNTIME_SYSTEM_04: + return "RUNTIME_SYSTEM_04" + case DefaultAmsPorts_RUNTIME_SYSTEM_05: + return "RUNTIME_SYSTEM_05" + case DefaultAmsPorts_RUNTIME_SYSTEM_06: + return "RUNTIME_SYSTEM_06" + case DefaultAmsPorts_RUNTIME_SYSTEM_07: + return "RUNTIME_SYSTEM_07" + case DefaultAmsPorts_RUNTIME_SYSTEM_08: + return "RUNTIME_SYSTEM_08" + case DefaultAmsPorts_RUNTIME_SYSTEM_09: + return "RUNTIME_SYSTEM_09" + case DefaultAmsPorts_RUNTIME_SYSTEM_10: + return "RUNTIME_SYSTEM_10" + case DefaultAmsPorts_RUNTIME_SYSTEM_11: + return "RUNTIME_SYSTEM_11" + case DefaultAmsPorts_RUNTIME_SYSTEM_12: + return "RUNTIME_SYSTEM_12" + case DefaultAmsPorts_RUNTIME_SYSTEM_13: + return "RUNTIME_SYSTEM_13" + case DefaultAmsPorts_RUNTIME_SYSTEM_14: + return "RUNTIME_SYSTEM_14" + case DefaultAmsPorts_RUNTIME_SYSTEM_15: + return "RUNTIME_SYSTEM_15" + case DefaultAmsPorts_RUNTIME_SYSTEM_16: + return "RUNTIME_SYSTEM_16" + case DefaultAmsPorts_RUNTIME_SYSTEM_17: + return "RUNTIME_SYSTEM_17" + case DefaultAmsPorts_RUNTIME_SYSTEM_18: + return "RUNTIME_SYSTEM_18" + case DefaultAmsPorts_RUNTIME_SYSTEM_19: + return "RUNTIME_SYSTEM_19" + case DefaultAmsPorts_RUNTIME_SYSTEM_20: + return "RUNTIME_SYSTEM_20" + case DefaultAmsPorts_RUNTIME_SYSTEM_21: + return "RUNTIME_SYSTEM_21" + case DefaultAmsPorts_RUNTIME_SYSTEM_22: + return "RUNTIME_SYSTEM_22" + case DefaultAmsPorts_RUNTIME_SYSTEM_23: + return "RUNTIME_SYSTEM_23" + case DefaultAmsPorts_RUNTIME_SYSTEM_24: + return "RUNTIME_SYSTEM_24" + case DefaultAmsPorts_RUNTIME_SYSTEM_25: + return "RUNTIME_SYSTEM_25" + case DefaultAmsPorts_RUNTIME_SYSTEM_26: + return "RUNTIME_SYSTEM_26" + case DefaultAmsPorts_RUNTIME_SYSTEM_27: + return "RUNTIME_SYSTEM_27" + case DefaultAmsPorts_RUNTIME_SYSTEM_28: + return "RUNTIME_SYSTEM_28" + case DefaultAmsPorts_RUNTIME_SYSTEM_29: + return "RUNTIME_SYSTEM_29" + case DefaultAmsPorts_RUNTIME_SYSTEM_30: + return "RUNTIME_SYSTEM_30" + case DefaultAmsPorts_RUNTIME_SYSTEM_31: + return "RUNTIME_SYSTEM_31" + case DefaultAmsPorts_RUNTIME_SYSTEM_32: + return "RUNTIME_SYSTEM_32" + case DefaultAmsPorts_RUNTIME_SYSTEM_33: + return "RUNTIME_SYSTEM_33" + case DefaultAmsPorts_RUNTIME_SYSTEM_34: + return "RUNTIME_SYSTEM_34" + case DefaultAmsPorts_RUNTIME_SYSTEM_35: + return "RUNTIME_SYSTEM_35" + case DefaultAmsPorts_RUNTIME_SYSTEM_36: + return "RUNTIME_SYSTEM_36" + case DefaultAmsPorts_RUNTIME_SYSTEM_37: + return "RUNTIME_SYSTEM_37" + case DefaultAmsPorts_RUNTIME_SYSTEM_38: + return "RUNTIME_SYSTEM_38" + case DefaultAmsPorts_RUNTIME_SYSTEM_39: + return "RUNTIME_SYSTEM_39" + case DefaultAmsPorts_RUNTIME_SYSTEM_40: + return "RUNTIME_SYSTEM_40" + case DefaultAmsPorts_RUNTIME_SYSTEM_41: + return "RUNTIME_SYSTEM_41" + case DefaultAmsPorts_RUNTIME_SYSTEM_42: + return "RUNTIME_SYSTEM_42" + case DefaultAmsPorts_RUNTIME_SYSTEM_43: + return "RUNTIME_SYSTEM_43" + case DefaultAmsPorts_RUNTIME_SYSTEM_44: + return "RUNTIME_SYSTEM_44" + case DefaultAmsPorts_RUNTIME_SYSTEM_45: + return "RUNTIME_SYSTEM_45" + case DefaultAmsPorts_RUNTIME_SYSTEM_46: + return "RUNTIME_SYSTEM_46" + case DefaultAmsPorts_RUNTIME_SYSTEM_47: + return "RUNTIME_SYSTEM_47" + case DefaultAmsPorts_RUNTIME_SYSTEM_48: + return "RUNTIME_SYSTEM_48" + case DefaultAmsPorts_RUNTIME_SYSTEM_49: + return "RUNTIME_SYSTEM_49" + case DefaultAmsPorts_CAM_CONTROLLER: + return "CAM_CONTROLLER" + } + return "" +} + +func (e DefaultAmsPorts) String() string { + return e.PLC4XEnumName() +} diff --git a/plc4go/protocols/ads/readwrite/model/ReservedIndexGroups.go b/plc4go/protocols/ads/readwrite/model/ReservedIndexGroups.go index 4ea3e9c11..11990ece9 100644 --- a/plc4go/protocols/ads/readwrite/model/ReservedIndexGroups.go +++ b/plc4go/protocols/ads/readwrite/model/ReservedIndexGroups.go @@ -50,6 +50,7 @@ const ( ReservedIndexGroups_ADSIGRP_DATA_TYPE_TABLE_UPLOAD ReservedIndexGroups = 0x0000F00E ReservedIndexGroups_ADSIGRP_SYMBOL_AND_DATA_TYPE_SIZES ReservedIndexGroups = 0x0000F00F ReservedIndexGroups_ADSIGRP_SYMNOTE ReservedIndexGroups = 0x0000F010 + ReservedIndexGroups_ADSIGRP_DT_INFOBYNAMEEX ReservedIndexGroups = 0x0000F011 ReservedIndexGroups_ADSIGRP_IOIMAGE_RWIB ReservedIndexGroups = 0x0000F020 ReservedIndexGroups_ADSIGRP_IOIMAGE_RWIX ReservedIndexGroups = 0x0000F021 ReservedIndexGroups_ADSIGRP_IOIMAGE_RISIZE ReservedIndexGroups = 0x0000F025 @@ -92,6 +93,7 @@ func init() { ReservedIndexGroups_ADSIGRP_DATA_TYPE_TABLE_UPLOAD, ReservedIndexGroups_ADSIGRP_SYMBOL_AND_DATA_TYPE_SIZES, ReservedIndexGroups_ADSIGRP_SYMNOTE, + ReservedIndexGroups_ADSIGRP_DT_INFOBYNAMEEX, ReservedIndexGroups_ADSIGRP_IOIMAGE_RWIB, ReservedIndexGroups_ADSIGRP_IOIMAGE_RWIX, ReservedIndexGroups_ADSIGRP_IOIMAGE_RISIZE, @@ -152,6 +154,8 @@ func ReservedIndexGroupsByValue(value uint32) (enum ReservedIndexGroups, ok bool return ReservedIndexGroups_ADSIGRP_SYMBOL_AND_DATA_TYPE_SIZES, true case 0x0000F010: return ReservedIndexGroups_ADSIGRP_SYMNOTE, true + case 0x0000F011: + return ReservedIndexGroups_ADSIGRP_DT_INFOBYNAMEEX, true case 0x0000F020: return ReservedIndexGroups_ADSIGRP_IOIMAGE_RWIB, true case 0x0000F021: @@ -228,6 +232,8 @@ func ReservedIndexGroupsByName(value string) (enum ReservedIndexGroups, ok bool) return ReservedIndexGroups_ADSIGRP_SYMBOL_AND_DATA_TYPE_SIZES, true case "ADSIGRP_SYMNOTE": return ReservedIndexGroups_ADSIGRP_SYMNOTE, true + case "ADSIGRP_DT_INFOBYNAMEEX": + return ReservedIndexGroups_ADSIGRP_DT_INFOBYNAMEEX, true case "ADSIGRP_IOIMAGE_RWIB": return ReservedIndexGroups_ADSIGRP_IOIMAGE_RWIB, true case "ADSIGRP_IOIMAGE_RWIX": @@ -349,6 +355,8 @@ func (e ReservedIndexGroups) PLC4XEnumName() string { return "ADSIGRP_SYMBOL_AND_DATA_TYPE_SIZES" case ReservedIndexGroups_ADSIGRP_SYMNOTE: return "ADSIGRP_SYMNOTE" + case ReservedIndexGroups_ADSIGRP_DT_INFOBYNAMEEX: + return "ADSIGRP_DT_INFOBYNAMEEX" case ReservedIndexGroups_ADSIGRP_IOIMAGE_RWIB: return "ADSIGRP_IOIMAGE_RWIB" case ReservedIndexGroups_ADSIGRP_IOIMAGE_RWIX: diff --git a/plc4go/protocols/knxnetip/readwrite/model/KnxManufacturer.go b/plc4go/protocols/knxnetip/readwrite/model/KnxManufacturer.go index 9050d1663..4c70cdae6 100644 --- a/plc4go/protocols/knxnetip/readwrite/model/KnxManufacturer.go +++ b/plc4go/protocols/knxnetip/readwrite/model/KnxManufacturer.go @@ -635,8 +635,9 @@ const ( KnxManufacturer_M_GUANGDONG_KANWAY KnxManufacturer = 596 KnxManufacturer_M_PHOENIX_CONTACT_2 KnxManufacturer = 597 KnxManufacturer_M_RAMIREZ_ENGINEERING_GMBH KnxManufacturer = 598 - KnxManufacturer_M_ABB___RESERVED KnxManufacturer = 599 - KnxManufacturer_M_BUSCH_JAEGER_ELEKTRO___RESERVED KnxManufacturer = 600 + KnxManufacturer_M_ZHONGSHAN_TAIYANG_IMPANDEXP__CO_LTD KnxManufacturer = 599 + KnxManufacturer_M_ABB___RESERVED KnxManufacturer = 600 + KnxManufacturer_M_BUSCH_JAEGER_ELEKTRO___RESERVED KnxManufacturer = 601 ) var KnxManufacturerValues []KnxManufacturer @@ -1243,6 +1244,7 @@ func init() { KnxManufacturer_M_GUANGDONG_KANWAY, KnxManufacturer_M_PHOENIX_CONTACT_2, KnxManufacturer_M_RAMIREZ_ENGINEERING_GMBH, + KnxManufacturer_M_ZHONGSHAN_TAIYANG_IMPANDEXP__CO_LTD, KnxManufacturer_M_ABB___RESERVED, KnxManufacturer_M_BUSCH_JAEGER_ELEKTRO___RESERVED, } @@ -3472,7 +3474,7 @@ func (e KnxManufacturer) Number() uint16 { } case 599: { /* '599' */ - return 43954 + return 657 } case 6: { /* '6' */ @@ -3484,6 +3486,10 @@ func (e KnxManufacturer) Number() uint16 { } case 600: { /* '600' */ + return 43954 + } + case 601: + { /* '601' */ return 43959 } case 61: @@ -5894,7 +5900,7 @@ func (e KnxManufacturer) Name() string { } case 599: { /* '599' */ - return "ABB - reserved" + return "Zhongshan Taiyang IMP&EXP. CO LTD" } case 6: { /* '6' */ @@ -5906,6 +5912,10 @@ func (e KnxManufacturer) Name() string { } case 600: { /* '600' */ + return "ABB - reserved" + } + case 601: + { /* '601' */ return "Busch-Jaeger Elektro - reserved" } case 61: @@ -7204,12 +7214,14 @@ func KnxManufacturerByValue(value uint16) (enum KnxManufacturer, ok bool) { case 598: return KnxManufacturer_M_RAMIREZ_ENGINEERING_GMBH, true case 599: - return KnxManufacturer_M_ABB___RESERVED, true + return KnxManufacturer_M_ZHONGSHAN_TAIYANG_IMPANDEXP__CO_LTD, true case 6: return KnxManufacturer_M_BUSCH_JAEGER_ELEKTRO, true case 60: return KnxManufacturer_M_TECHEM, true case 600: + return KnxManufacturer_M_ABB___RESERVED, true + case 601: return KnxManufacturer_M_BUSCH_JAEGER_ELEKTRO___RESERVED, true case 61: return KnxManufacturer_M_SCHNEIDER_ELECTRIC_INDUSTRIES_SAS, true @@ -8411,12 +8423,14 @@ func KnxManufacturerByName(value string) (enum KnxManufacturer, ok bool) { return KnxManufacturer_M_PHOENIX_CONTACT_2, true case "M_RAMIREZ_ENGINEERING_GMBH": return KnxManufacturer_M_RAMIREZ_ENGINEERING_GMBH, true - case "M_ABB___RESERVED": - return KnxManufacturer_M_ABB___RESERVED, true + case "M_ZHONGSHAN_TAIYANG_IMPANDEXP__CO_LTD": + return KnxManufacturer_M_ZHONGSHAN_TAIYANG_IMPANDEXP__CO_LTD, true case "M_BUSCH_JAEGER_ELEKTRO": return KnxManufacturer_M_BUSCH_JAEGER_ELEKTRO, true case "M_TECHEM": return KnxManufacturer_M_TECHEM, true + case "M_ABB___RESERVED": + return KnxManufacturer_M_ABB___RESERVED, true case "M_BUSCH_JAEGER_ELEKTRO___RESERVED": return KnxManufacturer_M_BUSCH_JAEGER_ELEKTRO___RESERVED, true case "M_SCHNEIDER_ELECTRIC_INDUSTRIES_SAS": @@ -9664,12 +9678,14 @@ func (e KnxManufacturer) PLC4XEnumName() string { return "M_PHOENIX_CONTACT_2" case KnxManufacturer_M_RAMIREZ_ENGINEERING_GMBH: return "M_RAMIREZ_ENGINEERING_GMBH" - case KnxManufacturer_M_ABB___RESERVED: - return "M_ABB___RESERVED" + case KnxManufacturer_M_ZHONGSHAN_TAIYANG_IMPANDEXP__CO_LTD: + return "M_ZHONGSHAN_TAIYANG_IMPANDEXP__CO_LTD" case KnxManufacturer_M_BUSCH_JAEGER_ELEKTRO: return "M_BUSCH_JAEGER_ELEKTRO" case KnxManufacturer_M_TECHEM: return "M_TECHEM" + case KnxManufacturer_M_ABB___RESERVED: + return "M_ABB___RESERVED" case KnxManufacturer_M_BUSCH_JAEGER_ELEKTRO___RESERVED: return "M_BUSCH_JAEGER_ELEKTRO___RESERVED" case KnxManufacturer_M_SCHNEIDER_ELECTRIC_INDUSTRIES_SAS: diff --git a/plc4go/protocols/s7/readwrite/model/DataItem.go b/plc4go/protocols/s7/readwrite/model/DataItem.go index 42010eed2..d0ad80537 100644 --- a/plc4go/protocols/s7/readwrite/model/DataItem.go +++ b/plc4go/protocols/s7/readwrite/model/DataItem.go @@ -410,13 +410,13 @@ func DataItemSerialize(writeBuffer utils.WriteBuffer, value api.PlcValue, dataPr } case dataProtocolId == "IEC61131_STRING": // STRING // Manual Field (value) - _valueErr := SerializeS7String(writeBuffer, value, m.StringLength, "UTF-8") + _valueErr := SerializeS7String(writeBuffer, value, stringLength, "UTF-8") if _valueErr != nil { return errors.Wrap(_valueErr, "Error serializing 'value' field") } case dataProtocolId == "IEC61131_WSTRING": // STRING // Manual Field (value) - _valueErr := SerializeS7String(writeBuffer, value, m.StringLength, "UTF-16") + _valueErr := SerializeS7String(writeBuffer, value, stringLength, "UTF-16") if _valueErr != nil { return errors.Wrap(_valueErr, "Error serializing 'value' field") } 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 377334bbe..1f4fa085f 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 @@ -28,10 +28,12 @@ import org.apache.plc4x.java.ads.readwrite.DataItem; import org.apache.plc4x.java.api.authentication.PlcUsernamePasswordAuthentication; import org.apache.plc4x.java.api.exceptions.PlcConnectionException; import org.apache.plc4x.java.api.exceptions.PlcException; +import org.apache.plc4x.java.api.exceptions.PlcInvalidFieldException; import org.apache.plc4x.java.api.exceptions.PlcRuntimeException; import org.apache.plc4x.java.api.messages.*; import org.apache.plc4x.java.api.model.PlcConsumerRegistration; import org.apache.plc4x.java.api.model.PlcField; +import org.apache.plc4x.java.api.model.PlcSubscriptionField; import org.apache.plc4x.java.api.model.PlcSubscriptionHandle; import org.apache.plc4x.java.api.types.PlcResponseCode; import org.apache.plc4x.java.api.types.PlcSubscriptionType; @@ -51,12 +53,14 @@ import org.slf4j.LoggerFactory; import java.math.BigInteger; import java.net.*; +import java.nio.charset.StandardCharsets; import java.time.Duration; import java.time.Instant; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -67,22 +71,28 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements private AdsConfiguration configuration; + private String adsVersion; + private String deviceName; + private final AtomicLong invokeIdGenerator = new AtomicLong(1); private final RequestTransactionManager tm; private final Map<DefaultPlcConsumerRegistration, Consumer<PlcSubscriptionEvent>> consumers = new ConcurrentHashMap<>(); - // private final ConcurrentHashMap<SymbolicAdsField, DirectAdsField> symbolicFieldMapping; private final ConcurrentHashMap<SymbolicAdsField, CompletableFuture<Void>> pendingResolutionRequests; + private int symbolVersion; + private long onlineVersion; private final Map<String, AdsSymbolTableEntry> symbolTable; private final Map<String, AdsDataTypeTableEntry> dataTypeTable; + private final ReentrantLock invalidationLock; public AdsProtocolLogic() { // symbolicFieldMapping = new ConcurrentHashMap<>(); pendingResolutionRequests = new ConcurrentHashMap<>(); symbolTable = new HashMap<>(); dataTypeTable = new HashMap<>(); + invalidationLock = new ReentrantLock(); // Initialize Transaction Manager. // Until the number of concurrent requests is successfully negotiated we set it to a @@ -125,19 +135,104 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements // If the configuration asks us to load the symbol and data type tables, do so, // otherwise just mark the connection as completed instantly. setupAmsRouteFuture.whenComplete((unused, throwable) -> { - if (configuration.isLoadSymbolAndDataTypeTables()) { - LOGGER.debug("Fetching sizes of symbol and datatype table sizes."); - CompletableFuture<Void> readSymbolTableFuture = readSymbolTableAndDatatypeTable(context); - readSymbolTableFuture.whenComplete((unused2, throwable2) -> { - if (throwable2 != null) { - LOGGER.error("Error fetching symbol and datatype table sizes"); - } else { - context.fireConnected(); - } - }); - } else { - context.fireConnected(); + if (!configuration.isLoadSymbolAndDataTypeTables()) { + future.completeExceptionally(new PlcConnectionException( + "Lazy loading is generally planned, but not implemented yet. " + + "If you are in need for this feature, please reach out to the community.")); } + //if (configuration.isLoadSymbolAndDataTypeTables()) { + // Execute a ReadDeviceInfo command + AmsPacket readDeviceInfoRequest = new AdsReadDeviceInfoRequest( + configuration.getTargetAmsNetId(), DefaultAmsPorts.RUNTIME_SYSTEM_01.getValue(), + configuration.getSourceAmsNetId(), 800, 0, getInvokeId()); + RequestTransactionManager.RequestTransaction readDeviceInfoTx = tm.startRequest(); + readDeviceInfoTx.submit(() -> context.sendRequest(new AmsTCPPacket(readDeviceInfoRequest)) + .expectResponse(AmsTCPPacket.class, Duration.ofMillis(configuration.getTimeoutRequest())) + .onTimeout(future::completeExceptionally) + .onError((p, e) -> future.completeExceptionally(e)) + .check(responseAmsPacket -> responseAmsPacket.getUserdata().getInvokeId() == readDeviceInfoRequest.getInvokeId()) + .unwrap(response -> (AdsReadDeviceInfoResponse) response.getUserdata()) + .handle(readDeviceInfoResponse -> { + readDeviceInfoTx.endRequest(); + if (readDeviceInfoResponse.getResult() != ReturnCode.OK) { + // TODO: Handle this + future.completeExceptionally(new PlcException("Result is " + readDeviceInfoResponse.getResult())); + return; + } + + // Get the twin-cat version and PLC name. + adsVersion = String.format("%d.%d.%d", readDeviceInfoResponse.getMajorVersion(), + readDeviceInfoResponse.getMinorVersion(), readDeviceInfoResponse.getVersion()); + deviceName = new String(readDeviceInfoResponse.getDevice()).trim(); + + // Read the online version number (Address; GroupID: 0xF004 (read symbol by name),Offset: 0, Read length: 4, ... Payload: "TwinCAT_SystemInfoVarList._AppInfo.OnlineChangeCnt") + AmsPacket readOnlineVersionNumberRequest = new AdsReadWriteRequest( + configuration.getTargetAmsNetId(), DefaultAmsPorts.RUNTIME_SYSTEM_01.getValue(), + configuration.getSourceAmsNetId(), 800, 0, getInvokeId(), + ReservedIndexGroups.ADSIGRP_SYM_VALBYNAME.getValue(), 0, 4, null, + "TwinCAT_SystemInfoVarList._AppInfo.OnlineChangeCnt".getBytes(StandardCharsets.UTF_8)); + RequestTransactionManager.RequestTransaction readOnlineVersionNumberTx = tm.startRequest(); + readOnlineVersionNumberTx.submit(() -> context.sendRequest(new AmsTCPPacket(readOnlineVersionNumberRequest)) + .expectResponse(AmsTCPPacket.class, Duration.ofMillis(configuration.getTimeoutRequest())) + .onTimeout(future::completeExceptionally) + .onError((p, e) -> future.completeExceptionally(e)) + .check(responseAmsPacket -> responseAmsPacket.getUserdata().getInvokeId() == readOnlineVersionNumberRequest.getInvokeId()) + .unwrap(response -> (AdsReadWriteResponse) response.getUserdata()) + .handle(readOnlineVersionNumberResponse -> { + readOnlineVersionNumberTx.endRequest(); + if (readOnlineVersionNumberResponse.getResult() != ReturnCode.OK) { + // TODO: Handle this + future.completeExceptionally(new PlcException("Result is " + readOnlineVersionNumberResponse.getResult())); + return; + } + try { + ReadBuffer rb = new ReadBufferByteBased(readOnlineVersionNumberResponse.getData()); + onlineVersion = rb.readUnsignedLong(32); + + // Read the offline version number (Address: GroupID: 0xF008, Offset: 0, Read length: 1) + AmsPacket readSymbolVersionNumberRequest = new AdsReadRequest( + configuration.getTargetAmsNetId(), DefaultAmsPorts.RUNTIME_SYSTEM_01.getValue(), + configuration.getSourceAmsNetId(), 800, 0, getInvokeId(), + ReservedIndexGroups.ADSIGRP_SYM_VERSION.getValue(), 0, 1); + RequestTransactionManager.RequestTransaction readSymbolVersionNumberTx = tm.startRequest(); + readSymbolVersionNumberTx.submit(() -> context.sendRequest(new AmsTCPPacket(readSymbolVersionNumberRequest)) + .expectResponse(AmsTCPPacket.class, Duration.ofMillis(configuration.getTimeoutRequest())) + .onTimeout(future::completeExceptionally) + .onError((p, e) -> future.completeExceptionally(e)) + .check(responseAmsPacket -> responseAmsPacket.getUserdata().getInvokeId() == readSymbolVersionNumberRequest.getInvokeId()) + .unwrap(response -> (AdsReadResponse) response.getUserdata()) + .handle(readSymbolVersionNumberResponse -> { + readSymbolVersionNumberTx.endRequest(); + if (readSymbolVersionNumberResponse.getResult() != ReturnCode.OK) { + // TODO: Handle this + future.completeExceptionally(new PlcException("Result is " + readSymbolVersionNumberResponse.getResult())); + return; + } + try { + ReadBuffer rb2 = new ReadBufferByteBased(readSymbolVersionNumberResponse.getData()); + symbolVersion = rb2.readUnsignedInt(8); + + LOGGER.debug("Fetching sizes of symbol and datatype table sizes."); + CompletableFuture<Void> readSymbolTableFuture = readSymbolTableAndDatatypeTable(context); + readSymbolTableFuture.whenComplete((unused2, throwable2) -> { + if (throwable2 != null) { + LOGGER.error("Error fetching symbol and datatype table sizes"); + } else { + context.fireConnected(); + } + }); + } catch (ParseException e) { + future.completeExceptionally(new PlcConnectionException("Error reading the symbol version of data type and symbol data.", e)); + } + })); + } catch (ParseException e) { + future.completeExceptionally(new PlcConnectionException("Error reading the online version of data type and symbol data.", e)); + } + })); + })); + /*} else { + context.fireConnected(); + }*/ }); } @@ -217,88 +312,146 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements protected CompletableFuture<Void> readSymbolTableAndDatatypeTable(ConversationContext<AmsTCPPacket> context) { final CompletableFuture<Void> future = new CompletableFuture<>(); - // Initialize the request. - AmsPacket amsPacket = new AdsReadRequest(configuration.getTargetAmsNetId(), configuration.getTargetAmsPort(), + // Read the data-type and symbol table sizes + AmsPacket readDataAndSymbolTableSizesRequest = new AdsReadRequest(configuration.getTargetAmsNetId(), configuration.getTargetAmsPort(), configuration.getSourceAmsNetId(), configuration.getSourceAmsPort(), 0, getInvokeId(), ReservedIndexGroups.ADSIGRP_SYMBOL_AND_DATA_TYPE_SIZES.getValue(), 0x00000000, 24); - AmsTCPPacket amsTCPPacket = new AmsTCPPacket(amsPacket); - // Start a new request-transaction (Is ended in the response-handler) - RequestTransactionManager.RequestTransaction transaction = tm.startRequest(); - transaction.submit(() -> context.sendRequest(amsTCPPacket) + RequestTransactionManager.RequestTransaction readDataAndSymbolTableSizesTx = tm.startRequest(); + readDataAndSymbolTableSizesTx.submit(() -> context.sendRequest(new AmsTCPPacket(readDataAndSymbolTableSizesRequest)) .expectResponse(AmsTCPPacket.class, Duration.ofMillis(configuration.getTimeoutRequest())) .onTimeout(future::completeExceptionally) .onError((p, e) -> future.completeExceptionally(e)) - .check(responseAmsPacket -> responseAmsPacket.getUserdata().getInvokeId() == amsPacket.getInvokeId()) + .check(responseAmsPacket -> responseAmsPacket.getUserdata().getInvokeId() == readDataAndSymbolTableSizesRequest.getInvokeId()) .unwrap(response -> (AdsReadResponse) response.getUserdata()) - .handle(responseAdsData -> { - transaction.endRequest(); - if (responseAdsData.getResult() == ReturnCode.OK) { - ReadBuffer readBuffer = new ReadBufferByteBased(responseAdsData.getData()); - try { - AdsTableSizes adsTableSizes = AdsTableSizes.staticParse(readBuffer); - LOGGER.debug("PLC contains {} symbols and {} data-types", adsTableSizes.getSymbolCount(), adsTableSizes.getDataTypeCount()); - - // Now we load the datatype definitions. - AmsPacket amsReadTablePacket = new AdsReadRequest(configuration.getTargetAmsNetId(), configuration.getTargetAmsPort(), - configuration.getSourceAmsNetId(), configuration.getSourceAmsPort(), 0, getInvokeId(), - ReservedIndexGroups.ADSIGRP_DATA_TYPE_TABLE_UPLOAD.getValue(), 0x00000000, adsTableSizes.getDataTypeLength()); - RequestTransactionManager.RequestTransaction transaction2 = tm.startRequest(); - AmsTCPPacket amsReadTableTCPPacket = new AmsTCPPacket(amsReadTablePacket); - 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()) - .handle(responseAdsReadTableData -> { - transaction2.endRequest(); - if (responseAdsData.getResult() == ReturnCode.OK) { - // Parse the result. - ReadBuffer rb = new ReadBufferByteBased(responseAdsReadTableData.getData()); - for (int i = 0; i < adsTableSizes.getDataTypeCount(); i++) { + .handle(readDataAndSymbolTableSizesResponse -> { + readDataAndSymbolTableSizesTx.endRequest(); + if (readDataAndSymbolTableSizesResponse.getResult() != ReturnCode.OK) { + // TODO: Handle this + future.completeExceptionally(new PlcException("Reading data type and symbol table sizes failed: " + readDataAndSymbolTableSizesResponse.getResult())); + return; + } + try { + ReadBuffer readBuffer = new ReadBufferByteBased(readDataAndSymbolTableSizesResponse.getData()); + AdsTableSizes adsTableSizes = AdsTableSizes.staticParse(readBuffer); + LOGGER.debug("PLC contains {} symbols and {} data-types", adsTableSizes.getSymbolCount(), adsTableSizes.getDataTypeCount()); + + // Now we load the datatype definitions. + AmsPacket readDataTypeTableRequest = new AdsReadRequest(configuration.getTargetAmsNetId(), configuration.getTargetAmsPort(), + configuration.getSourceAmsNetId(), configuration.getSourceAmsPort(), 0, getInvokeId(), + ReservedIndexGroups.ADSIGRP_DATA_TYPE_TABLE_UPLOAD.getValue(), 0x00000000, adsTableSizes.getDataTypeLength()); + RequestTransactionManager.RequestTransaction readDataTypeTableTx = tm.startRequest(); + AmsTCPPacket amsReadTableTCPPacket = new AmsTCPPacket(readDataTypeTableRequest); + readDataTypeTableTx.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() == readDataTypeTableRequest.getInvokeId()) + .unwrap(response -> (AdsReadResponse) response.getUserdata()) + .handle(readDataTypeTableResponse -> { + readDataTypeTableTx.endRequest(); + if (readDataTypeTableResponse.getResult() != ReturnCode.OK) { + // TODO: Handle this + future.completeExceptionally(new PlcException("Reading data type table failed: " + readDataTypeTableResponse.getResult())); + return; + } + // Parse the result. + ReadBuffer rb = new ReadBufferByteBased(readDataTypeTableResponse.getData()); + for (int i = 0; i < adsTableSizes.getDataTypeCount(); i++) { + try { + AdsDataTypeTableEntry adsDataTypeTableEntry = AdsDataTypeTableEntry.staticParse(rb); + dataTypeTable.put(adsDataTypeTableEntry.getDataTypeName(), adsDataTypeTableEntry); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + // Now we load the symbol definitions + AmsPacket readSymbolTableRequest = new AdsReadRequest(configuration.getTargetAmsNetId(), configuration.getTargetAmsPort(), + configuration.getSourceAmsNetId(), configuration.getSourceAmsPort(), 0, getInvokeId(), + ReservedIndexGroups.ADSIGRP_SYM_UPLOAD.getValue(), 0x00000000, adsTableSizes.getSymbolLength()); + RequestTransactionManager.RequestTransaction readSymbolTableTx = tm.startRequest(); + AmsTCPPacket amsReadSymbolTableTCPPacket = new AmsTCPPacket(readSymbolTableRequest); + readSymbolTableTx.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() == readSymbolTableRequest.getInvokeId()) + .unwrap(response -> (AdsReadResponse) response.getUserdata()) + .handle(readSymbolTableResponse -> { + readSymbolTableTx.endRequest(); + if (readSymbolTableResponse.getResult() != ReturnCode.OK) { + // TODO: Handle this + future.completeExceptionally(new PlcException("Reading symbol table failed: " + readSymbolTableResponse.getResult())); + return; + } + ReadBuffer rb2 = new ReadBufferByteBased(readSymbolTableResponse.getData()); + for (int i = 0; i < adsTableSizes.getSymbolCount(); i++) { try { - AdsDataTypeTableEntry adsDataTypeTableEntry = AdsDataTypeTableEntry.staticParse(rb); - dataTypeTable.put(adsDataTypeTableEntry.getDataTypeName(), adsDataTypeTableEntry); + AdsSymbolTableEntry adsSymbolTableEntry = AdsSymbolTableEntry.staticParse(rb2); + symbolTable.put(adsSymbolTableEntry.getName(), adsSymbolTableEntry); } catch (ParseException e) { throw new RuntimeException(e); } } - AmsPacket amsReadSymbolTablePacket = new AdsReadRequest(configuration.getTargetAmsNetId(), configuration.getTargetAmsPort(), - configuration.getSourceAmsNetId(), configuration.getSourceAmsPort(), 0, getInvokeId(), - ReservedIndexGroups.ADSIGRP_SYM_UPLOAD.getValue(), 0x00000000, adsTableSizes.getSymbolLength()); - 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()) - .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); - symbolTable.put(adsSymbolTableEntry.getName(), adsSymbolTableEntry); - } catch (ParseException e) { - throw new RuntimeException(e); + LinkedHashMap<String, PlcSubscriptionField> subscriptionFields = new LinkedHashMap<>(); + // Subscribe to online-version changes (get the address from the collected data for symbol: "TwinCAT_SystemInfoVarList._AppInfo.OnlineChangeCnt") + subscriptionFields.put("onlineVersion", new DefaultPlcSubscriptionField( + PlcSubscriptionType.CHANGE_OF_STATE, + new SymbolicAdsField("TwinCAT_SystemInfoVarList._AppInfo.OnlineChangeCnt"), + Duration.ofMillis(1000))); + // Subscribe to symbol-version changes (Address: GroupID: 0xF008, Offset: 0, Read length: 1) + subscriptionFields.put("symbolVersion", new DefaultPlcSubscriptionField( + PlcSubscriptionType.CHANGE_OF_STATE, + new DirectAdsField(0xF008, 0x0000, "USINT", 1), + Duration.ofMillis(1000))); + LinkedHashMap<String, List<Consumer<PlcSubscriptionEvent>>> consumer = new LinkedHashMap<>(); + consumer.put("onlineVersion", Collections.singletonList(plcSubscriptionEvent -> { + long oldVersion = onlineVersion; + long newVersion = plcSubscriptionEvent.getPlcValue("onlineVersion").getLong(); + if(oldVersion != newVersion) { + if(invalidationLock.tryLock()) { + LOGGER.info("Detected change of the 'online-version', invalidating data type and symbol information."); + CompletableFuture<Void> reloadingFuture = readSymbolTableAndDatatypeTable(context); + reloadingFuture.whenComplete((unused, throwable) -> { + if(throwable != null) { + LOGGER.error("Error reloading data type and symbol data", throwable); } - } - future.complete(null); + invalidationLock.unlock(); + }); } - })); - } - })); + } + })); + consumer.put("symbolVersion", Collections.singletonList(plcSubscriptionEvent -> { + int oldVersion = symbolVersion; + int newVersion = plcSubscriptionEvent.getPlcValue("symbolVersion").getInteger(); + if(oldVersion != newVersion) { + if(invalidationLock.tryLock()) { + LOGGER.info("Detected change of the 'symbol-version', invalidating data type and symbol information."); + CompletableFuture<Void> reloadingFuture = readSymbolTableAndDatatypeTable(context); + reloadingFuture.whenComplete((unused, throwable) -> { + if(throwable != null) { + LOGGER.error("Error reloading data type and symbol data", throwable); + } + invalidationLock.unlock(); + }); + } + } + })); + PlcSubscriptionRequest subscriptionRequest = new DefaultPlcSubscriptionRequest(this, subscriptionFields, consumer); + CompletableFuture<PlcSubscriptionResponse> subscriptionResponseCompletableFuture = subscribe(subscriptionRequest); + + // Wait for the subscription to be finished + subscriptionResponseCompletableFuture.whenComplete((plcSubscriptionResponse, throwable) -> { + if(throwable == null) { + future.complete(null); + } + }); + })); + })); } catch (ParseException e) { future.completeExceptionally(new PlcException("Error loading the table sizes", e)); } - } else { - // TODO: Implement this correctly. - future.completeExceptionally(new PlcException("Result is " + responseAdsData.getResult())); - } })); return future; } @@ -404,14 +557,14 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements @Override public CompletableFuture<PlcReadResponse> read(PlcReadRequest readRequest) { // Get all ADS addresses in their resolved state. - final CompletableFuture<List<DirectAdsField>> directAdsFieldsFuture = + final CompletableFuture<Map<AdsField, DirectAdsField>> directAdsFieldsFuture = getDirectAddresses(readRequest.getFields()); // If all addresses were already resolved we can send the request immediately. if (directAdsFieldsFuture.isDone()) { - final List<DirectAdsField> fields = directAdsFieldsFuture.getNow(null); - if (fields != null) { - return executeRead(readRequest, fields); + final Map<AdsField, DirectAdsField> resolvedFields = directAdsFieldsFuture.getNow(null); + if (resolvedFields != null) { + return executeRead(readRequest, resolvedFields); } else { final CompletableFuture<PlcReadResponse> errorFuture = new CompletableFuture<>(); errorFuture.completeExceptionally(new PlcException("Fields are null")); @@ -448,15 +601,15 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements } protected CompletableFuture<PlcReadResponse> executeRead(PlcReadRequest readRequest, - List<DirectAdsField> directAdsFields) { + Map<AdsField, DirectAdsField> resolvedFields) { // Depending on the number of fields, use a single item request or a sum-request - if (directAdsFields.size() == 1) { + if (resolvedFields.size() == 1) { // Do a normal (single item) ADS Read Request - return singleRead(readRequest, directAdsFields.get(0)); + return singleRead(readRequest, resolvedFields.values().stream().findFirst().get()); } else { // TODO: Check if the version of the remote station is at least TwinCAT v2.11 Build >= 1550 otherwise split up into single item requests. // Do a ADS-Sum Read Request. - return multiRead(readRequest, directAdsFields); + return multiRead(readRequest, resolvedFields); } } @@ -495,12 +648,12 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements return future; } - protected CompletableFuture<PlcReadResponse> multiRead(PlcReadRequest readRequest, List<DirectAdsField> directAdsFields) { + protected CompletableFuture<PlcReadResponse> multiRead(PlcReadRequest readRequest, Map<AdsField, DirectAdsField> resolvedFields) { CompletableFuture<PlcReadResponse> future = new CompletableFuture<>(); // Calculate the size of all fields together. // Calculate the expected size of the response data. - long expectedResponseDataSize = directAdsFields.stream().mapToLong( + long expectedResponseDataSize = resolvedFields.values().stream().mapToLong( field -> { String dataTypeName = field.getAdsDataTypeName(); AdsDataTypeTableEntry adsDataTypeTableEntry = dataTypeTable.get(dataTypeName); @@ -512,15 +665,17 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements // With multi-requests, the index-group is fixed and the index offset indicates the number of elements. AmsPacket amsPacket = new AdsReadWriteRequest(configuration.getTargetAmsNetId(), configuration.getTargetAmsPort(), configuration.getSourceAmsNetId(), configuration.getSourceAmsPort(), - 0, getInvokeId(), ReservedIndexGroups.ADSIGRP_MULTIPLE_READ.getValue(), directAdsFields.size(), - expectedResponseDataSize, directAdsFields.stream().map(directAdsField -> { - String dataTypeName = directAdsField.getAdsDataTypeName(); - AdsDataTypeTableEntry adsDataTypeTableEntry = dataTypeTable.get(dataTypeName); - long size = adsDataTypeTableEntry.getSize(); - return new AdsMultiRequestItemRead( - directAdsField.getIndexGroup(), directAdsField.getIndexOffset(), - (size * directAdsField.getNumberOfElements())); - }).collect(Collectors.toList()), null); + 0, getInvokeId(), ReservedIndexGroups.ADSIGRP_MULTIPLE_READ.getValue(), resolvedFields.size(), + expectedResponseDataSize, readRequest.getFieldNames().stream().map(fieldName -> { + AdsField field = (AdsField) readRequest.getField(fieldName); + DirectAdsField directAdsField = resolvedFields.get(field); + String dataTypeName = directAdsField.getAdsDataTypeName(); + AdsDataTypeTableEntry adsDataTypeTableEntry = dataTypeTable.get(dataTypeName); + long size = adsDataTypeTableEntry.getSize(); + return new AdsMultiRequestItemRead( + directAdsField.getIndexGroup(), directAdsField.getIndexOffset(), + (size * directAdsField.getNumberOfElements())); + }).collect(Collectors.toList()), null); AmsTCPPacket amsTCPPacket = new AmsTCPPacket(amsPacket); // Start a new request-transaction (Is ended in the response-handler) @@ -561,7 +716,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements } else if (adsData instanceof AdsReadWriteResponse) { AdsReadWriteResponse adsReadWriteResponse = (AdsReadWriteResponse) adsData; readBuffer = new ReadBufferByteBased(adsReadWriteResponse.getData(), ByteOrder.LITTLE_ENDIAN); - // When parsing a multi-item response, the error codes of each items come + // When parsing a multi-item response, the error codes of each item comes // in sequence and then come the values. for (String fieldName : readRequest.getFieldNames()) { try { @@ -613,7 +768,8 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements int strLen = 0; if ((plcValueType == PlcValueType.STRING) || (plcValueType == PlcValueType.WSTRING)) { - strLen = (field instanceof AdsStringField) ? ((AdsStringField) field).getStringLength() : 256; + // Extract the string length from the data type name. + strLen = Integer.parseInt(dataTypeName.substring(dataTypeName.indexOf("(") + 1, dataTypeName.indexOf(")"))); } final int stringLength = strLen; if (field.getNumberOfElements() == 1) { @@ -693,14 +849,14 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements @Override public CompletableFuture<PlcWriteResponse> write(PlcWriteRequest writeRequest) { // Get all ADS addresses in their resolved state. - final CompletableFuture<List<DirectAdsField>> directAdsFieldsFuture = + final CompletableFuture<Map<AdsField, DirectAdsField>> directAdsFieldsFuture = getDirectAddresses(writeRequest.getFields()); // If all addresses were already resolved we can send the request immediately. if (directAdsFieldsFuture.isDone()) { - final List<DirectAdsField> fields = directAdsFieldsFuture.getNow(null); - if (fields != null) { - return executeWrite(writeRequest, fields); + final Map<AdsField, DirectAdsField> resolvedFields = directAdsFieldsFuture.getNow(null); + if (resolvedFields != null) { + return executeWrite(writeRequest, resolvedFields); } else { final CompletableFuture<PlcWriteResponse> errorFuture = new CompletableFuture<>(); errorFuture.completeExceptionally(new PlcException("Fields are null")); @@ -738,15 +894,15 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements } protected CompletableFuture<PlcWriteResponse> executeWrite(PlcWriteRequest writeRequest, - List<DirectAdsField> directAdsFields) { + Map<AdsField, DirectAdsField> resolvedFields) { // Depending on the number of fields, use a single item request or a sum-request - if (directAdsFields.size() == 1) { + if (resolvedFields.size() == 1) { // Do a normal (single item) ADS Write Request - return singleWrite(writeRequest, directAdsFields.get(0)); + return singleWrite(writeRequest, resolvedFields.values().stream().findFirst().get()); } else { // TODO: Check if the version of the remote station is at least TwinCAT v2.11 Build >= 1550 otherwise split up into single item requests. // Do a ADS-Sum Read Request. - return multiWrite(writeRequest, directAdsFields); + return multiWrite(writeRequest, resolvedFields); } } @@ -801,7 +957,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements return future; } - protected CompletableFuture<PlcWriteResponse> multiWrite(PlcWriteRequest writeRequest, List<DirectAdsField> directAdsFields) { + protected CompletableFuture<PlcWriteResponse> multiWrite(PlcWriteRequest writeRequest, Map<AdsField, DirectAdsField> resolvedFields) { CompletableFuture<PlcWriteResponse> future = new CompletableFuture<>(); // Calculate the size of all fields together. @@ -896,7 +1052,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements @Override public CompletableFuture<PlcSubscriptionResponse> subscribe(PlcSubscriptionRequest subscriptionRequest) { // Get all ADS addresses in their resolved state. - final CompletableFuture<List<DirectAdsField>> directAdsFieldsFuture = + final CompletableFuture<Map<AdsField, DirectAdsField>> directAdsFieldsFuture = getDirectAddresses(subscriptionRequest.getFields() .stream() .map(field -> ((DefaultPlcSubscriptionField) field).getPlcField()) @@ -904,9 +1060,9 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements // If all addresses were already resolved we can send the request immediately. if (directAdsFieldsFuture.isDone()) { - final List<DirectAdsField> fields = directAdsFieldsFuture.getNow(null); - if (fields != null) { - return executeSubscribe(subscriptionRequest); + final Map<AdsField, DirectAdsField> resolvedFields = directAdsFieldsFuture.getNow(null); + if (resolvedFields != null) { + return executeSubscribe(subscriptionRequest, resolvedFields); } else { final CompletableFuture<PlcSubscriptionResponse> errorFuture = new CompletableFuture<>(); errorFuture.completeExceptionally(new PlcException("Fields are null")); @@ -922,10 +1078,10 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements // we can complete the initial one. else { CompletableFuture<PlcSubscriptionResponse> delayedSubscribe = new CompletableFuture<>(); - directAdsFieldsFuture.handle((directAdsFields, throwable) -> { - if (directAdsFields != null) { + directAdsFieldsFuture.handle((fieldMapping, throwable) -> { + if (fieldMapping != null) { final CompletableFuture<PlcSubscriptionResponse> delayedResponse = - executeSubscribe(subscriptionRequest); + executeSubscribe(subscriptionRequest, fieldMapping); delayedResponse.handle((plcSubscribeResponse, throwable1) -> { if (plcSubscribeResponse != null) { delayedSubscribe.complete(plcSubscribeResponse); @@ -943,14 +1099,14 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements } } - private CompletableFuture<PlcSubscriptionResponse> executeSubscribe(PlcSubscriptionRequest subscribeRequest) { + private CompletableFuture<PlcSubscriptionResponse> executeSubscribe(PlcSubscriptionRequest subscribeRequest, Map<AdsField, DirectAdsField> resolvedFields) { CompletableFuture<PlcSubscriptionResponse> future = new CompletableFuture<>(); List<AmsTCPPacket> amsTCPPackets = subscribeRequest.getFields().stream() .map(field -> (DefaultPlcSubscriptionField) field) .map(field -> { - AdsDataTypeTableEntry adsDataTypeTableEntry = dataTypeTable.get(((DirectAdsField) field.getPlcField()).getAdsDataTypeName()); - DirectAdsField directAdsField = getDirectAdsFieldForSymbolicName(field); + AdsDataTypeTableEntry adsDataTypeTableEntry = dataTypeTable.get(resolvedFields.get((AdsField) field.getPlcField()).getAdsDataTypeName()); + DirectAdsField directAdsField = getDirectAdsFieldForSymbolicName(field.getPlcField()); return new AmsTCPPacket(new AdsAddDeviceNotificationRequest(configuration.getTargetAmsNetId(), configuration.getTargetAmsPort(), configuration.getSourceAmsNetId(), configuration.getSourceAmsPort(), 0, getInvokeId(), @@ -970,6 +1126,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements transaction.submit(subscribeRecursively( subscribeRequest, subscribeRequest.getFieldNames().iterator(), + resolvedFields, responses, future, amsTCPPackets.iterator(), @@ -977,7 +1134,9 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements return future; } - private Runnable subscribeRecursively(PlcSubscriptionRequest subscriptionRequest, Iterator<String> fieldNames, + private Runnable subscribeRecursively(PlcSubscriptionRequest subscriptionRequest, + Iterator<String> fieldNames, + Map<AdsField, DirectAdsField> resolvedFields, Map<String, ResponseItem<PlcSubscriptionHandle>> responses, CompletableFuture<PlcSubscriptionResponse> future, Iterator<AmsTCPPacket> amsTCPPackets, @@ -995,7 +1154,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements .handle(response -> { if (response.getResult() == ReturnCode.OK) { DefaultPlcSubscriptionField subscriptionField = (DefaultPlcSubscriptionField) subscriptionRequest.getField(fieldName); - AdsDataTypeTableEntry adsDataTypeTableEntry = dataTypeTable.get(((DirectAdsField) subscriptionField.getPlcField()).getAdsDataTypeName()); + AdsDataTypeTableEntry adsDataTypeTableEntry = dataTypeTable.get((resolvedFields.get((AdsField) subscriptionField.getPlcField())).getAdsDataTypeName()); // Collect notification handle from individual response. responses.put(fieldName, new ResponseItem<>( @@ -1025,7 +1184,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements if (hasMorePackets) { RequestTransactionManager.RequestTransaction nextTransaction = tm.startRequest(); nextTransaction.submit(subscribeRecursively( - subscriptionRequest, fieldNames, responses, future, amsTCPPackets, nextTransaction)); + subscriptionRequest, fieldNames, resolvedFields, responses, future, amsTCPPackets, nextTransaction)); } }); }; @@ -1150,8 +1309,8 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements consumers.remove(consumerRegistration); } - protected CompletableFuture<List<DirectAdsField>> getDirectAddresses(List<PlcField> fields) { - CompletableFuture<List<DirectAdsField>> future = new CompletableFuture<>(); + protected CompletableFuture<Map<AdsField, DirectAdsField>> getDirectAddresses(List<PlcField> fields) { + CompletableFuture<Map<AdsField, DirectAdsField>> future = new CompletableFuture<>(); // Get all symbolic fields from the current request. // These potentially need to be resolved to direct addresses, if this has not been done before. @@ -1202,26 +1361,28 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements if (throwable != null) { return future.completeExceptionally(throwable.getCause()); } else { - List<DirectAdsField> directAdsFields = new ArrayList<>(fields.size()); + Map<AdsField, DirectAdsField> directAdsFieldMapping = new HashMap<>(fields.size()); for (PlcField field : fields) { if (field instanceof SymbolicAdsField) { - directAdsFields.add(getDirectAdsFieldForSymbolicName(field)); + directAdsFieldMapping.put((AdsField) field, getDirectAdsFieldForSymbolicName(field)); } else { - directAdsFields.add((DirectAdsField) field); + directAdsFieldMapping.put((AdsField) field, (DirectAdsField) field); } } - return future.complete(directAdsFields); + return future.complete(directAdsFieldMapping); } }); } else { // If all fields were resolved, we can continue instantly. - future.complete(fields.stream().map(plcField -> { - if (plcField instanceof SymbolicAdsField) { - return getDirectAdsFieldForSymbolicName(plcField); + Map<AdsField, DirectAdsField> directAdsFieldMapping = new HashMap<>(fields.size()); + for (PlcField field : fields) { + if (field instanceof SymbolicAdsField) { + directAdsFieldMapping.put((AdsField) field, getDirectAdsFieldForSymbolicName(field)); } else { - return (DirectAdsField) plcField; + directAdsFieldMapping.put((AdsField) field, (DirectAdsField) field); } - }).collect(Collectors.toList())); + } + future.complete(directAdsFieldMapping); } return future; } @@ -1364,9 +1525,16 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements if (!symbolTable.containsKey(symbolicAddress)) { return null; } - AdsSymbolTableEntry adsSymbolTableEntry = symbolTable.get(symbolicAddress); + if(adsSymbolTableEntry == null) { + throw new PlcInvalidFieldException("Couldn't resolve symbolic address: " + symbolicAddress); + } AdsDataTypeTableEntry dataTypeTableEntry = dataTypeTable.get(adsSymbolTableEntry.getDataTypeName()); + if(dataTypeTableEntry == null) { + throw new PlcInvalidFieldException( + "Couldn't resolve datatype: '" + adsSymbolTableEntry.getDataTypeName() + + "' for address: '" + ((SymbolicAdsField) field).getSymbolicAddress() + "'"); + } return new DirectAdsField(adsSymbolTableEntry.getGroup(), adsSymbolTableEntry.getOffset(), dataTypeTableEntry.getDataTypeName(), dataTypeTableEntry.getArrayDimensions()); } @@ -1374,7 +1542,15 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements else { String symbolName = addressParts[0] + "." + addressParts[1]; AdsSymbolTableEntry adsSymbolTableEntry = symbolTable.get(symbolName); + if(adsSymbolTableEntry == null) { + throw new PlcInvalidFieldException("Couldn't resolve symbolic address: " + symbolName); + } AdsDataTypeTableEntry adsDataTypeTableEntry = dataTypeTable.get(adsSymbolTableEntry.getDataTypeName()); + if(adsDataTypeTableEntry == null) { + throw new PlcInvalidFieldException( + "Couldn't resolve datatype: '" + adsSymbolTableEntry.getDataTypeName() + + "' for address: '" + ((SymbolicAdsField) field).getSymbolicAddress() + "'"); + } return resolveDirectAdsFieldForSymbolicNameFromDataType( Arrays.asList(addressParts).subList(2, addressParts.length), adsSymbolTableEntry.getGroup(), adsSymbolTableEntry.getOffset(), adsDataTypeTableEntry); @@ -1384,7 +1560,7 @@ public class AdsProtocolLogic extends Plc4xProtocolBase<AmsTCPPacket> implements protected DirectAdsField resolveDirectAdsFieldForSymbolicNameFromDataType(List<String> remainingAddressParts, long currentGroup, long currentOffset, AdsDataTypeTableEntry adsDataTypeTableEntry) { if (remainingAddressParts.isEmpty()) { // TODO: Implement the Array support - return new DirectAdsField(currentGroup, currentOffset, adsDataTypeTableEntry.getDataTypeName(), null); + return new DirectAdsField(currentGroup, currentOffset, adsDataTypeTableEntry.getDataTypeName(), 1); } // Go through all children looking for a matching one. diff --git a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/readwrite/utils/StaticHelper.java b/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/readwrite/utils/StaticHelper.java deleted file mode 100644 index f0b874735..000000000 --- a/plc4j/drivers/ads/src/main/java/org/apache/plc4x/java/ads/readwrite/utils/StaticHelper.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.ads.readwrite.utils; - -import org.apache.plc4x.java.api.exceptions.PlcRuntimeException; -import org.apache.plc4x.java.api.value.PlcValue; -import org.apache.plc4x.java.spi.generation.ParseException; -import org.apache.plc4x.java.spi.generation.ReadBuffer; -import org.apache.plc4x.java.spi.generation.WriteBuffer; - -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; - -public class StaticHelper { - - public static String parseAmsString(ReadBuffer readBuffer, int stringLength, String encoding) { - try { - if ("UTF-8".equalsIgnoreCase(encoding)) { - List<Byte> bytes = new ArrayList<>(); - for(int i = 0; (i < stringLength) && readBuffer.hasMore(8); i++) { - final byte curByte = readBuffer.readByte(); - if (curByte != 0) { - bytes.add(curByte); - } else { - // Gobble up the remaining data, which is not added to the string. - i++; - for(; (i < stringLength) && readBuffer.hasMore(8); i++) { - readBuffer.readByte(); - } - break; - } - } - // Read the terminating byte. - readBuffer.readByte(); - final byte[] byteArray = new byte[bytes.size()]; - for (int i = 0; i < bytes.size(); i++) { - byteArray[i] = bytes.get(i); - } - return new String(byteArray, StandardCharsets.UTF_8); - } else if ("UTF-16".equalsIgnoreCase(encoding)) { - List<Byte> bytes = new ArrayList<>(); - for(int i = 0; (i < stringLength) && readBuffer.hasMore(16); i++) { - final short curShort = readBuffer.readShort(16); - if (curShort != 0) { - bytes.add((byte) (curShort >>> 8)); - bytes.add((byte) (curShort & 0xFF)); - } else { - // Gobble up the remaining data, which is not added to the string. - i++; - for(; (i < stringLength) && readBuffer.hasMore(16); i++) { - readBuffer.readShort(16); - } - break; - } - } - // Read the terminating byte. - readBuffer.readByte(); - final byte[] byteArray = new byte[bytes.size()]; - for (int i = 0; i < bytes.size(); i++) { - byteArray[i] = bytes.get(i); - } - return new String(byteArray, StandardCharsets.UTF_16); - } else { - throw new PlcRuntimeException("Unsupported string encoding " + encoding); - } - } catch (ParseException e) { - throw new PlcRuntimeException("Error parsing string", e); - } - } - - public static void serializeAmsString(WriteBuffer writeBuffer, PlcValue value, int stringLength, Object encoding) { - // TODO: Need to implement the serialization or we can't write strings - throw new PlcRuntimeException("Not implemented yet"); - } - -} diff --git a/plc4j/drivers/ads/src/test/java/org/apache/plc4x/protocol/ads/ManualAdsDriverTest.java b/plc4j/drivers/ads/src/test/java/org/apache/plc4x/protocol/ads/ManualAdsDriverTest.java index 8f9d25e64..d89a68d95 100644 --- a/plc4j/drivers/ads/src/test/java/org/apache/plc4x/protocol/ads/ManualAdsDriverTest.java +++ b/plc4j/drivers/ads/src/test/java/org/apache/plc4x/protocol/ads/ManualAdsDriverTest.java @@ -69,40 +69,36 @@ public class ManualAdsDriverTest extends ManualTest { public static void main(String[] args) throws Exception { String spsIp = "192.168.23.20"; - ///// - // TODO: adjust this to your ip address String clientIp = "192.168.23.200"; - // - //// String sourceAmsNetId = clientIp + ".1.1"; int sourceAmsPort = 65534; String targetAmsNetId = spsIp + ".1.1"; int targetAmsPort = 851; String connectionString = String.format("ads:tcp://%s?sourceAmsNetId=%s&sourceAmsPort=%d&targetAmsNetId=%s&targetAmsPort=%d", spsIp, sourceAmsNetId, sourceAmsPort, targetAmsNetId, targetAmsPort); ManualAdsDriverTest test = new ManualAdsDriverTest(connectionString); - test.addTestCase("main.hurz_BOOL:BOOL", true); - test.addTestCase("main.hurz_BYTE:BYTE", Arrays.asList(false, false, true, false, true, false, true, false)); - test.addTestCase("main.hurz_WORD:WORD", Arrays.asList(true, false, true, false, false, true, false, true, true, false, true, true, true, false, false, false)); - test.addTestCase("main.hurz_DWORD:DWORD", Arrays.asList(true, true, true, true, true, true, false, false, true, true, false, true, true, true, true, false, true, false, false, false, true, false, false, false, true, false, true, true, true, false, false, false)); - test.addTestCase("main.hurz_SINT:SINT", -42); - test.addTestCase("main.hurz_USINT:USINT", 42); - test.addTestCase("main.hurz_INT:INT", -2424); - test.addTestCase("main.hurz_UINT:UINT", 42424); - test.addTestCase("main.hurz_DINT:DINT", -242442424); - test.addTestCase("main.hurz_UDINT:UDINT", 4242442424L); - test.addTestCase("main.hurz_LINT:LINT", -4242442424242424242L); - test.addTestCase("main.hurz_ULINT:ULINT", 4242442424242424242L); - test.addTestCase("main.hurz_REAL:REAL", 3.14159265359F); - test.addTestCase("main.hurz_LREAL:LREAL", 2.71828182846D); - test.addTestCase("main.hurz_STRING:STRING", "hurz"); - test.addTestCase("main.hurz_WSTRING:WSTRING", "wolf"); - test.addTestCase("main.hurz_TIME:TIME", "PT1.234S"); - test.addTestCase("main.hurz_LTIME:LTIME", "PT24015H23M12.034002044S"); - test.addTestCase("main.hurz_DATE:DATE", "1978-03-28"); - test.addTestCase("main.hurz_TIME_OF_DAY:TIME_OF_DAY", "15:36:30.123"); - test.addTestCase("main.hurz_TOD:TOD", "16:17:18.123"); - test.addTestCase("main.hurz_DATE_AND_TIME:DATE_AND_TIME", "1996-05-06T15:36:30"); - test.addTestCase("main.hurz_DT:DT", "1972-03-29T00:00"); + test.addTestCase("MAIN.hurz_BOOL", true); + test.addTestCase("MAIN.hurz_BYTE", Arrays.asList(false, false, true, false, true, false, true, false)); + test.addTestCase("MAIN.hurz_WORD", Arrays.asList(true, false, true, false, false, true, false, true, true, false, true, true, true, false, false, false)); + test.addTestCase("MAIN.hurz_DWORD", Arrays.asList(true, true, true, true, true, true, false, false, true, true, false, true, true, true, true, false, true, false, false, false, true, false, false, false, true, false, true, true, true, false, false, false)); + test.addTestCase("MAIN.hurz_SINT", -42); + test.addTestCase("MAIN.hurz_USINT", 42); + test.addTestCase("MAIN.hurz_INT", -2424); + test.addTestCase("MAIN.hurz_UINT", 42424); + test.addTestCase("MAIN.hurz_DINT", -242442424); + test.addTestCase("MAIN.hurz_UDINT", 4242442424L); + test.addTestCase("MAIN.hurz_LINT", -4242442424242424242L); + test.addTestCase("MAIN.hurz_ULINT", 4242442424242424242L); + test.addTestCase("MAIN.hurz_REAL", 3.14159265359F); + test.addTestCase("MAIN.hurz_LREAL", 2.71828182846D); + test.addTestCase("MAIN.hurz_STRING", "hurz"); + test.addTestCase("MAIN.hurz_WSTRING", "wolf"); + test.addTestCase("MAIN.hurz_TIME", "PT1.234S"); + test.addTestCase("MAIN.hurz_LTIME", "PT24015H23M12.034002044S"); + test.addTestCase("MAIN.hurz_DATE", "1978-03-28"); + test.addTestCase("MAIN.hurz_TIME_OF_DAY", "15:36:30.123"); + test.addTestCase("MAIN.hurz_TOD", "16:17:18.123"); + test.addTestCase("MAIN.hurz_DATE_AND_TIME", "1996-05-06T15:36:30"); + test.addTestCase("MAIN.hurz_DT", "1972-03-29T00:00"); test.run(); } diff --git a/plc4j/drivers/canopen/src/main/java/org/apache/plc4x/java/canopen/readwrite/utils/StaticHelper.java b/plc4j/drivers/canopen/src/main/java/org/apache/plc4x/java/canopen/readwrite/utils/StaticHelper.java index 5aff2986d..87b016139 100644 --- a/plc4j/drivers/canopen/src/main/java/org/apache/plc4x/java/canopen/readwrite/utils/StaticHelper.java +++ b/plc4j/drivers/canopen/src/main/java/org/apache/plc4x/java/canopen/readwrite/utils/StaticHelper.java @@ -48,7 +48,7 @@ public class StaticHelper { // NOOP - a placeholder to let mspec compile } - public static Object parseString(ReadBuffer io, int length, String charset) { + public static Object parseString(ReadBuffer io, int length, String charset) throws ParseException { return io.readString(8 * length, charset); } diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/utils/StaticHelper.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/utils/StaticHelper.java index 054e1c7b8..660aa7a4f 100644 --- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/utils/StaticHelper.java +++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/utils/StaticHelper.java @@ -1930,7 +1930,7 @@ public class StaticHelper { throw new NotImplementedException("Serializing DATE_AND_TIME not implemented"); } - public static String parseS7Char(ReadBuffer io, String encoding) { + public static String parseS7Char(ReadBuffer io, String encoding) throws ParseException { if ("UTF-8".equalsIgnoreCase(encoding)) { return io.readString(8, encoding); } else if ("UTF-16".equalsIgnoreCase(encoding)) { diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java index 79ccaec5b..663a43c78 100644 --- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java +++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java @@ -128,9 +128,9 @@ public interface ReadBuffer extends ByteOrderAware, PositionAware { return readBigDecimal("", bitLength); } - String readString(String logicalName, int bitLength, String encoding, WithReaderArgs... readerArgs); + String readString(String logicalName, int bitLength, String encoding, WithReaderArgs... readerArgs) throws ParseException; - default String readString(int bitLength, String encoding) { + default String readString(int bitLength, String encoding) throws ParseException { return readString("", bitLength, encoding); } diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferByteBased.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferByteBased.java index 8c90ac6e8..6afe32f14 100644 --- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferByteBased.java +++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferByteBased.java @@ -26,6 +26,7 @@ import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.Objects; public class ReadBufferByteBased implements ReadBuffer { @@ -321,7 +322,7 @@ public class ReadBufferByteBased implements ReadBuffer { if(sign) { fraction = (short) (fraction | 0xF800); } - if ((exponent >= 1) && (exponent <= 15)) { + if ((exponent >= 1) && (exponent < 15)) { return (float) (0.01 * fraction * Math.pow(2, exponent)); } if (exponent == 0) { @@ -388,17 +389,65 @@ public class ReadBufferByteBased implements ReadBuffer { } @Override - public String readString(String logicalName, int bitLength, String encoding, WithReaderArgs... readerArgs) { - byte[] strBytes = new byte[bitLength / 8]; - for (int i = 0; (i < (bitLength / 8)) && hasMore(8); i++) { - try { - strBytes[i] = readByte(logicalName); - } catch (Exception e) { - throw new PlcRuntimeException(e); + public String readString(String logicalName, int bitLength, String encoding, WithReaderArgs... readerArgs) throws ParseException { + encoding = encoding.replaceAll("[^a-zA-Z0-9]", ""); + switch (encoding.toUpperCase()) { + case "UTF8": { + byte[] strBytes = new byte[bitLength / 8]; + int realLength = 0; + boolean finishedReading = false; + for (int i = 0; (i < (bitLength / 8)) && hasMore(8); i++) { + try { + byte b = readByte(logicalName); + if (b == 0x00) { + finishedReading = true; + } else if (!finishedReading) { + strBytes[i] = b; + realLength++; + } + } catch (Exception e) { + throw new PlcRuntimeException(e); + } + } + return new String(strBytes, StandardCharsets.UTF_8).substring(0, realLength); } + case "UTF16": + case "UTF16LE": + case "UTF16BE": { + byte[] strBytes = new byte[bitLength / 8]; + int realLength = 0; + boolean finishedReading = false; + for (int i = 0; (i < (bitLength / 16)) && hasMore(16); i++) { + try { + byte b1 = readByte(logicalName); + byte b2 = readByte(logicalName); + if ((b1 == 0x00) && (b2 == 0x00)) { + finishedReading = true; + } else if (!finishedReading){ + strBytes[(i * 2)] = b1; + strBytes[(i * 2) + 1] = b2; + realLength++; + } + } catch (Exception e) { + throw new PlcRuntimeException(e); + } + } + Charset charset; + switch (encoding) { + case "UTF16LE": + charset = StandardCharsets.UTF_16LE; + break; + case "UTF16BE": + charset = StandardCharsets.UTF_16BE; + break; + default: + charset = StandardCharsets.UTF_16; + } + return new String(strBytes, charset).substring(0, realLength); + } + default: + throw new ParseException("Unsupported encoding: " + encoding); } - //replaceAll function removes and leading ' char or hypens. - return new String(strBytes, Charset.forName(encoding.replaceAll("[^a-zA-Z0-9]", ""))); } diff --git a/plc4j/spi/src/test/java/org/apache/plc4x/java/spi/generation/ReadBufferTest.java b/plc4j/spi/src/test/java/org/apache/plc4x/java/spi/generation/ReadBufferTest.java index 757a0b30d..aeb6d60a4 100644 --- a/plc4j/spi/src/test/java/org/apache/plc4x/java/spi/generation/ReadBufferTest.java +++ b/plc4j/spi/src/test/java/org/apache/plc4x/java/spi/generation/ReadBufferTest.java @@ -30,7 +30,7 @@ class ReadBufferTest { * Test which makes sure that PLC4X-256 is not happening. */ @Test - void readString() { + void readString() throws ParseException { String value = new String("abcdef"); final ReadBuffer buffer = new ReadBufferByteBased(value.getBytes(StandardCharsets.UTF_8)); String answer = buffer.readString("", value.length() * 8, "UTF-8"); diff --git a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java b/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java index e74b5ed9c..5f70844b9 100644 --- a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java +++ b/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java @@ -137,7 +137,7 @@ public class StaticHelper { throw new NotImplementedException("Serializing STRING not implemented"); } - public static String parseS7Char(ReadBuffer io, Object encoding) { + public static String parseS7Char(ReadBuffer io, Object encoding) throws ParseException { // Read the full size of the string. return io.readString(8, (String) encoding); } diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/manual/ManualTest.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/manual/ManualTest.java index b5ab8eb8a..92e4733c3 100644 --- a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/manual/ManualTest.java +++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/manual/ManualTest.java @@ -91,7 +91,7 @@ public abstract class ManualTest { for (TestCase testCase : shuffledTestcases) { sb.append(testCase.address).append(", "); } - System.out.println(" using order: " + sb.toString()); + System.out.println(" using order: " + sb); final PlcReadRequest.Builder builder = plcConnection.readRequestBuilder(); for (TestCase testCase : shuffledTestcases) { @@ -107,17 +107,20 @@ public abstract class ManualTest { Assertions.assertEquals(shuffledTestcases.size(), readResponse.getFieldNames().size()); for (TestCase testCase : shuffledTestcases) { String fieldName = testCase.address; - Assertions.assertEquals(PlcResponseCode.OK, readResponse.getResponseCode(fieldName)); - Assertions.assertNotNull(readResponse.getPlcValue(fieldName)); + Assertions.assertEquals(PlcResponseCode.OK, readResponse.getResponseCode(fieldName), + "Field: " + fieldName); + Assertions.assertNotNull(readResponse.getPlcValue(fieldName), "Field: " + fieldName); if (readResponse.getPlcValue(fieldName) instanceof PlcList) { PlcList plcList = (PlcList) readResponse.getPlcValue(fieldName); List<Object> expectedValues = (List<Object>) testCase.expectedReadValue; for (int j = 0; j < expectedValues.size(); j++) { - Assertions.assertEquals(expectedValues.get(j), plcList.getIndex(j).getObject()); + Assertions.assertEquals(expectedValues.get(j), plcList.getIndex(j).getObject(), + "Field: " + fieldName); } } else { Assertions.assertEquals( - testCase.expectedReadValue.toString(), readResponse.getPlcValue(fieldName).getObject().toString()); + testCase.expectedReadValue.toString(), readResponse.getPlcValue(fieldName).getObject().toString(), + "Field: " + fieldName); } } } diff --git a/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/KnxManufacturer.cs b/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/KnxManufacturer.cs index ae91c3575..59306feb1 100644 --- a/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/KnxManufacturer.cs +++ b/plc4net/drivers/knxnetip/src/drivers/knxnetip/readwrite/model/KnxManufacturer.cs @@ -623,8 +623,9 @@ namespace org.apache.plc4net.drivers.knxnetip.readwrite.model M_GUANGDONG_KANWAY = 596, M_PHOENIX_CONTACT_2 = 597, M_RAMIREZ_ENGINEERING_GMBH = 598, - M_ABB___RESERVED = 599, - M_BUSCH_JAEGER_ELEKTRO___RESERVED = 600, + M_ZHONGSHAN_TAIYANG_IMPANDEXP__CO_LTD = 599, + M_ABB___RESERVED = 600, + M_BUSCH_JAEGER_ELEKTRO___RESERVED = 601, } public static class KnxManufacturerInfo @@ -2299,8 +2300,8 @@ namespace org.apache.plc4net.drivers.knxnetip.readwrite.model case KnxManufacturer.M_RAMIREZ_ENGINEERING_GMBH: { /* '598' */ return 656; } - case KnxManufacturer.M_ABB___RESERVED: { /* '599' */ - return 43954; + case KnxManufacturer.M_ZHONGSHAN_TAIYANG_IMPANDEXP__CO_LTD: { /* '599' */ + return 657; } case KnxManufacturer.M_BUSCH_JAEGER_ELEKTRO: { /* '6' */ return 7; @@ -2308,7 +2309,10 @@ namespace org.apache.plc4net.drivers.knxnetip.readwrite.model case KnxManufacturer.M_TECHEM: { /* '60' */ return 99; } - case KnxManufacturer.M_BUSCH_JAEGER_ELEKTRO___RESERVED: { /* '600' */ + case KnxManufacturer.M_ABB___RESERVED: { /* '600' */ + return 43954; + } + case KnxManufacturer.M_BUSCH_JAEGER_ELEKTRO___RESERVED: { /* '601' */ return 43959; } case KnxManufacturer.M_SCHNEIDER_ELECTRIC_INDUSTRIES_SAS: { /* '61' */ @@ -4112,8 +4116,8 @@ namespace org.apache.plc4net.drivers.knxnetip.readwrite.model case KnxManufacturer.M_RAMIREZ_ENGINEERING_GMBH: { /* '598' */ return "RAMIREZ Engineering GmbH"; } - case KnxManufacturer.M_ABB___RESERVED: { /* '599' */ - return "ABB - reserved"; + case KnxManufacturer.M_ZHONGSHAN_TAIYANG_IMPANDEXP__CO_LTD: { /* '599' */ + return "Zhongshan Taiyang IMP&EXP. CO LTD"; } case KnxManufacturer.M_BUSCH_JAEGER_ELEKTRO: { /* '6' */ return "Busch-Jaeger Elektro"; @@ -4121,7 +4125,10 @@ namespace org.apache.plc4net.drivers.knxnetip.readwrite.model case KnxManufacturer.M_TECHEM: { /* '60' */ return "Techem"; } - case KnxManufacturer.M_BUSCH_JAEGER_ELEKTRO___RESERVED: { /* '600' */ + case KnxManufacturer.M_ABB___RESERVED: { /* '600' */ + return "ABB - reserved"; + } + case KnxManufacturer.M_BUSCH_JAEGER_ELEKTRO___RESERVED: { /* '601' */ return "Busch-Jaeger Elektro - reserved"; } case KnxManufacturer.M_SCHNEIDER_ELECTRIC_INDUSTRIES_SAS: { /* '61' */ diff --git a/protocols/ads/src/main/resources/protocols/ads/ads.mspec b/protocols/ads/src/main/resources/protocols/ads/ads.mspec index d1ce4bee6..284835ac0 100644 --- a/protocols/ads/src/main/resources/protocols/ads/ads.mspec +++ b/protocols/ads/src/main/resources/protocols/ads/ads.mspec @@ -458,15 +458,15 @@ [simple string 8 value] ] ['WCHAR' STRING - [simple string 16 value encoding='"UTF-16"'] + [simple string 16 value encoding='"UTF-16LE"'] ] ['STRING' STRING - // TODO: Fix this length - [manual vstring value 'STATIC_CALL("parseAmsString", readBuffer, stringLength, _type.encoding)' 'STATIC_CALL("serializeAmsString", writeBuffer, _value, stringLength, _type.encoding)' 'stringLength + 1'] + [simple vstring 'stringLength * 8' value ] + [reserved uint 8 '0x00'] ] ['WSTRING' STRING - // TODO: Fix this length - [manual vstring value 'STATIC_CALL("parseAmsString", readBuffer, stringLength, _type.encoding)' 'STATIC_CALL("serializeAmsString", writeBuffer, _value, stringLength, _type.encoding)' '(stringLength * 2) + 2' encoding='"UTF-16"'] + [simple vstring 'stringLength * 8 * 2' value encoding='"UTF-16LE"'] + [reserved uint 16 '0x0000' ] ] // -----------------------------------------