You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by hu...@apache.org on 2021/01/13 10:34:10 UTC
[plc4x] branch feature/native_opua_client updated: Updated
datatypes that can be read
This is an automated email from the ASF dual-hosted git repository.
hutcheb pushed a commit to branch feature/native_opua_client
in repository https://gitbox.apache.org/repos/asf/plc4x.git
The following commit(s) were added to refs/heads/feature/native_opua_client by this push:
new a65ed1c Updated datatypes that can be read
a65ed1c is described below
commit a65ed1c4c5b7476ae8b762935a773ef150cb809f
Author: hutcheb <be...@gmail.com>
AuthorDate: Wed Jan 13 04:19:44 2021 -0500
Updated datatypes that can be read
There is some support for all 25 Variant types however there are some
that jutst get passed through as Strings.
---
.../java/opcua/protocol/OpcuaProtocolLogic.java | 106 ++++++++++++++++-----
.../plc4x/java/opcua/OpcuaPlcDriverTest.java | 23 ++++-
protocols/opcua/src/main/xslt/opc-types.xsl | 74 ++++++++++++--
3 files changed, 170 insertions(+), 33 deletions(-)
diff --git a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaProtocolLogic.java b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaProtocolLogic.java
index 9d7f8de..de891f8 100644
--- a/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaProtocolLogic.java
+++ b/plc4j/drivers/opcua/src/main/java/org/apache/plc4x/java/opcua/protocol/OpcuaProtocolLogic.java
@@ -62,11 +62,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
-import java.time.Duration;
+import java.time.*;
import java.math.BigInteger;
-import java.time.Instant;
-import java.time.LocalDateTime;
-import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
@@ -88,12 +85,14 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
private static final Logger LOGGER = LoggerFactory.getLogger(OpcuaProtocolLogic.class);
public static final Duration REQUEST_TIMEOUT = Duration.ofMillis(1000000);
public static final long REQUEST_TIMEOUT_LONG = 10000L;
- private static final String CHUNK = "F";
- private static final int VERSION = 0;
+
+ private static final int DEFAULT_CONNECTION_LIFETIME = 36000000;
+ private static final int DEFAULT_MAX_CHUNK_COUNT = 64;
+ private static final int DEFAULT_MAX_MESSAGE_SIZE = 2097152;
private static final int DEFAULT_RECEIVE_BUFFER_SIZE = 65535;
private static final int DEFAULT_SEND_BUFFER_SIZE = 65535;
- private static final int DEFAULT_MAX_MESSAGE_SIZE = 2097152;
- private static final int DEFAULT_MAX_CHUNK_COUNT = 64;
+ private static final int VERSION = 0;
+
private NodeId authenticationToken = new NodeIdTwoByte(NodeIdType.nodeIdTypeTwoByte, new TwoByteNodeId((short) 0));
private static final PascalString NULL_STRING = new PascalString(-1,null);
private static ExpandedNodeId NULL_EXPANDED_NODEID = new ExpandedNodeIdTwoByte(false,
@@ -106,14 +105,15 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
null, //Body Length
null); // Body
private static final long epochOffset = 116444736000000000L; //Offset between OPC UA epoch time and linux epoch time.
- private static final int DEFAULT_CONNECTION_LIFETIME = 36000000;
+
+ private static final String CHUNK = "F";
private static final String nameSpaceSecurityPolicyNone = "http://opcfoundation.org/UA/SecurityPolicy#None";
private static final String applicationUri = "urn:apache:plc4x:client";
private static final String productUri = "urn:apache:plc4x:client";
private static final String applicationText = "OPCUA client for the Apache PLC4X:PLC4J project";
- private String sessionName = "UaSession:" + applicationText + ":" + RandomStringUtils.random(20, true, true);
- private String clientNonce = RandomStringUtils.random(40, true, true);
+ private final String sessionName = "UaSession:" + applicationText + ":" + RandomStringUtils.random(20, true, true);
+ private final String clientNonce = RandomStringUtils.random(40, true, true);
private RequestTransactionManager tm;
private String endpoint;
@@ -361,8 +361,6 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
noOfDiscoveryUrls,
discoveryUrls);
- clientNonce = RandomStringUtils.random(40, true, true);
-
CreateSessionRequest createSessionRequest = new CreateSessionRequest((byte) 1,
(byte) 0,
requestHeader,
@@ -683,13 +681,30 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
int length = array.length;
LocalDateTime[] tmpValue = new LocalDateTime[length];
for (int i = 0; i < length; i++) {
- tmpValue[i] = LocalDateTime.ofInstant(Instant.ofEpochMilli(array[i]), ZoneId.systemDefault());
+ tmpValue[i] = LocalDateTime.ofInstant(Instant.ofEpochMilli(getDateTime(array[i])), ZoneOffset.UTC);
}
value = IEC61131ValueHandler.of(tmpValue);
} else if (variant instanceof VariantGuid) {
- int length = ((VariantGuid) variant).getValue().length;
- String[] stringArray = ((VariantGuid) variant).getValue();
- value = IEC61131ValueHandler.of(stringArray);
+ GuidValue[] array = ((VariantGuid) variant).getValue();
+ int length = array.length;
+ String[] tmpValue = new String[length];
+ for (int i = 0; i < length; i++) {
+ //These two data section aren't little endian like the rest.
+ byte[] data4Bytes = array[i].getData4();
+ int data4 = 0;
+ for (int k = 0; k < data4Bytes.length; k++)
+ {
+ data4 = (data4 << 8) + (data4Bytes[k] & 0xff);
+ }
+ byte[] data5Bytes = array[i].getData5();
+ long data5 = 0;
+ for (int k = 0; k < data5Bytes.length; k++)
+ {
+ data5 = (data5 << 8) + (data5Bytes[k] & 0xff);
+ }
+ tmpValue[i] = Long.toHexString(array[i].getData1()) + "-" + Integer.toHexString(array[i].getData2()) + "-" + Integer.toHexString(array[i].getData3()) + "-" + Integer.toHexString(data4) + "-" + Long.toHexString(data5);
+ }
+ value = IEC61131ValueHandler.of(tmpValue);
} else if (variant instanceof VariantXmlElement) {
int length = ((VariantXmlElement) variant).getValue().length;
PascalString[] stringArray = ((VariantXmlElement) variant).getValue();
@@ -698,15 +713,60 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
tmpValue[i] = stringArray[i].getStringValue();
}
value = IEC61131ValueHandler.of(tmpValue);
- } else if (variant instanceof VariantByteString) {
- //TODO:- Looking into returning structures.
- ByteStringArray[] array = ((VariantByteString) variant).getValue();
- int length = array.length;
- Short[] tmpValue = new Short[length];
+ } else if (variant instanceof VariantLocalizedText) {
+ int length = ((VariantLocalizedText) variant).getValue().length;
+ LocalizedText[] stringArray = ((VariantLocalizedText) variant).getValue();
+ String[] tmpValue = new String[length];
+ for (int i = 0; i < length; i++) {
+ tmpValue[i] = "";
+ tmpValue[i] += stringArray[i].getLocaleSpecified() ? stringArray[i].getLocale().getStringValue() + "|" : "";
+ tmpValue[i] += stringArray[i].getTextSpecified() ? stringArray[i].getText().getStringValue() : "";
+ }
+ value = IEC61131ValueHandler.of(tmpValue);
+ } else if (variant instanceof VariantQualifiedName) {
+ int length = ((VariantQualifiedName) variant).getValue().length;
+ QualifiedName[] stringArray = ((VariantQualifiedName) variant).getValue();
+ String[] tmpValue = new String[length];
for (int i = 0; i < length; i++) {
- tmpValue[i] = array[i].getValue();
+ tmpValue[i] = "ns=" + stringArray[i].getNamespaceIndex() + ";s=" + stringArray[i].getName().getStringValue();
}
value = IEC61131ValueHandler.of(tmpValue);
+ } else if (variant instanceof VariantExtensionObject) {
+ int length = ((VariantExtensionObject) variant).getValue().length;
+ ExtensionObject[] stringArray = ((VariantExtensionObject) variant).getValue();
+ String[] tmpValue = new String[length];
+ for (int i = 0; i < length; i++) {
+ tmpValue[i] = stringArray[i].toString();
+ }
+ value = IEC61131ValueHandler.of(tmpValue);
+ } else if (variant instanceof VariantNodeId) {
+ int length = ((VariantNodeId) variant).getValue().length;
+ NodeId[] stringArray = ((VariantNodeId) variant).getValue();
+ String[] tmpValue = new String[length];
+ for (int i = 0; i < length; i++) {
+ tmpValue[i] = stringArray[i].toString();
+ }
+ value = IEC61131ValueHandler.of(tmpValue);
+ }else if (variant instanceof VariantStatusCode) {
+ int length = ((VariantStatusCode) variant).getValue().length;
+ StatusCode[] stringArray = ((VariantStatusCode) variant).getValue();
+ String[] tmpValue = new String[length];
+ for (int i = 0; i < length; i++) {
+ tmpValue[i] = stringArray[i].toString();
+ }
+ value = IEC61131ValueHandler.of(tmpValue);
+ } else if (variant instanceof VariantByteString) {
+ PlcList plcList = new PlcList();
+ ByteStringArray[] array = ((VariantByteString) variant).getValue();
+ for (int k = 0; k < array.length; k++) {
+ int length = array[k].getValue().length;
+ Short[] tmpValue = new Short[length];
+ for (int i = 0; i < length; i++) {
+ tmpValue[i] = array[k].getValue()[i];
+ }
+ plcList.add(IEC61131ValueHandler.of(tmpValue));
+ }
+ value = plcList;
} else {
responseCode = PlcResponseCode.UNSUPPORTED;
LOGGER.error("Data type - " + variant.getClass() + " is not supported ");
diff --git a/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/OpcuaPlcDriverTest.java b/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/OpcuaPlcDriverTest.java
index 3f676a6..e41954d 100644
--- a/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/OpcuaPlcDriverTest.java
+++ b/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/OpcuaPlcDriverTest.java
@@ -65,7 +65,7 @@ public class OpcuaPlcDriverTest {
private static final String DATE_TIME_READ_WRITE = "ns=2;s=HelloWorld/ScalarTypes/DateTime";
private static final String DURATION_READ_WRITE = "ns=2;s=HelloWorld/ScalarTypes/Duration";
private static final String GUID_READ_WRITE = "ns=2;s=HelloWorld/ScalarTypes/Guid";
- private static final String LOCALISED_READ_WRITE = "ns=2;s=HelloWorld/ScalarTypes/LocalizedText";
+ private static final String LOCALIZED_READ_WRITE = "ns=2;s=HelloWorld/ScalarTypes/LocalizedText";
private static final String NODE_ID_READ_WRITE = "ns=2;s=HelloWorld/ScalarTypes/NodeId";
private static final String QUALIFIED_NAM_READ_WRITE = "ns=2;s=HelloWorld/ScalarTypes/QualifiedName";
private static final String UTC_TIME_READ_WRITE = "ns=2;s=HelloWorld/ScalarTypes/UtcTime";
@@ -87,6 +87,7 @@ public class OpcuaPlcDriverTest {
private static final String UINT16_ARRAY_IDENTIFIER = "ns=2;s=HelloWorld/ArrayTypes/UInt16Array";
private static final String UINT32_ARRAY_IDENTIFIER = "ns=2;s=HelloWorld/ArrayTypes/UInt32Array";
private static final String UINT64_ARRAY_IDENTIFIER = "ns=2;s=HelloWorld/ArrayTypes/UInt64Array";
+ private static final String DATE_TIME_ARRAY_IDENTIFIER = "ns=2;s=HelloWorld/ArrayTypes/DateTimeArray";
// Address of local milo server
@@ -194,6 +195,16 @@ public class OpcuaPlcDriverTest {
builder.addItem("UInt32", UINT32_IDENTIFIER_READ_WRITE);
builder.addItem("UInt64", UINT64_IDENTIFIER_READ_WRITE);
builder.addItem("UInteger", UINTEGER_IDENTIFIER_READ_WRITE);
+ builder.addItem("ByteString", BYTE_STRING_IDENTIFIER_READ_WRITE);
+ builder.addItem("DateTime", DATE_TIME_READ_WRITE);
+ builder.addItem("Duration", DURATION_READ_WRITE);
+ builder.addItem("GUID", GUID_READ_WRITE);
+ builder.addItem("XmlElement", XML_ELEMENT_READ_WRITE);
+ builder.addItem("Variant", VARIANT_READ_WRITE);
+ builder.addItem("LocalizedText", LOCALIZED_READ_WRITE);
+ builder.addItem("QualifiedName", QUALIFIED_NAM_READ_WRITE);
+ builder.addItem("NodeId", NODE_ID_READ_WRITE);
+ builder.addItem("UtcTime", UTC_TIME_READ_WRITE);
builder.addItem("BoolArray", BOOL_ARRAY_IDENTIFIER);
builder.addItem("ByteStringArray", BYTE_STRING_ARRAY_IDENTIFIER);
@@ -208,6 +219,7 @@ public class OpcuaPlcDriverTest {
builder.addItem("UInt16Array", UINT16_ARRAY_IDENTIFIER);
builder.addItem("UInt32Array", UINT32_ARRAY_IDENTIFIER);
builder.addItem("UInt64Array", UINT64_ARRAY_IDENTIFIER);
+ builder.addItem("DateTimeArray", DATE_TIME_ARRAY_IDENTIFIER);
builder.addItem("DoesNotExists", DOES_NOT_EXIST_IDENTIFIER_READ_WRITE);
@@ -227,6 +239,14 @@ public class OpcuaPlcDriverTest {
assert response.getResponseCode("UInt32").equals(PlcResponseCode.OK);
assert response.getResponseCode("UInt64").equals(PlcResponseCode.OK);
assert response.getResponseCode("UInteger").equals(PlcResponseCode.OK);
+ assert response.getResponseCode("ByteString").equals(PlcResponseCode.OK);
+ assert response.getResponseCode("DateTime").equals(PlcResponseCode.OK);
+ assert response.getResponseCode("Duration").equals(PlcResponseCode.OK);
+ assert response.getResponseCode("GUID").equals(PlcResponseCode.OK);
+ assert response.getResponseCode("XmlElement").equals(PlcResponseCode.OK);
+ assert response.getResponseCode("Variant").equals(PlcResponseCode.OK);
+ assert response.getResponseCode("LocalizedText").equals(PlcResponseCode.OK);
+ assert response.getResponseCode("QualifiedName").equals(PlcResponseCode.OK);
assert response.getResponseCode("BoolArray").equals(PlcResponseCode.OK);
assert response.getResponseCode("ByteArray").equals(PlcResponseCode.OK);
@@ -240,6 +260,7 @@ public class OpcuaPlcDriverTest {
assert response.getResponseCode("UInt16Array").equals(PlcResponseCode.OK);
assert response.getResponseCode("UInt32Array").equals(PlcResponseCode.OK);
assert response.getResponseCode("UInt64Array").equals(PlcResponseCode.OK);
+ assert response.getResponseCode("DateTimeArray").equals(PlcResponseCode.OK);
assert response.getResponseCode("DoesNotExists").equals(PlcResponseCode.NOT_FOUND);
diff --git a/protocols/opcua/src/main/xslt/opc-types.xsl b/protocols/opcua/src/main/xslt/opc-types.xsl
index 43d5015..e3f2ac8 100644
--- a/protocols/opcua/src/main/xslt/opc-types.xsl
+++ b/protocols/opcua/src/main/xslt/opc-types.xsl
@@ -54,17 +54,25 @@
<xsl:apply-templates select="$file/node:UANodeSet/node:UADataType[@BrowseName='OpenSecureChannelResponse']"/>
<xsl:apply-templates select="$file/node:UANodeSet/node:UADataType[@BrowseName='CreateSessionRequest']"/>
<xsl:apply-templates select="$file/node:UANodeSet/node:UADataType[@BrowseName='CreateSessionResponse']"/>
+ <xsl:apply-templates select="$file/node:UANodeSet/node:UADataType[@BrowseName='CreateSubscriptionRequest']"/>
+ <xsl:apply-templates select="$file/node:UANodeSet/node:UADataType[@BrowseName='CreateSubscriptionResponse']"/>
+ <xsl:apply-templates select="$file/node:UANodeSet/node:UADataType[@BrowseName='CreateMonitoredItemsRequest']"/>
+ <xsl:apply-templates select="$file/node:UANodeSet/node:UADataType[@BrowseName='CreateMonitoredItemsRequest']"/>
+ <xsl:apply-templates select="$file/node:UANodeSet/node:UADataType[@BrowseName='DeleteSubscriptionsRequest']"/>
<xsl:apply-templates select="$file/node:UANodeSet/node:UADataType[@BrowseName='ActivateSessionRequest']"/>
<xsl:apply-templates select="$file/node:UANodeSet/node:UADataType[@BrowseName='ActivateSessionResponse']"/>
<xsl:apply-templates select="$file/node:UANodeSet/node:UADataType[@BrowseName='ReadRequest']"/>
<xsl:apply-templates select="$file/node:UANodeSet/node:UADataType[@BrowseName='ReadResponse']"/>
<xsl:apply-templates select="$file/node:UANodeSet/node:UADataType[@BrowseName='WriteRequest']"/>
<xsl:apply-templates select="$file/node:UANodeSet/node:UADataType[@BrowseName='WriteResponse']"/>
- ['473' CloseSessionRequest
- [simple RequestHeader 'requestHeader']
- [reserved uint 7 '0x00']
- [simple bit 'deleteSubscriptions']
- ]
+ <xsl:apply-templates select="$file/node:UANodeSet/node:UADataType[@BrowseName='BrowseRequest']"/>
+ <xsl:apply-templates select="$file/node:UANodeSet/node:UADataType[@BrowseName='BrowseResponse']"/>
+
+ ['473' CloseSessionRequest
+ [simple RequestHeader 'requestHeader']
+ [reserved uint 7 '0x00']
+ [simple bit 'deleteSubscriptions']
+ ]
<xsl:apply-templates select="$file/node:UANodeSet/node:UADataType[@BrowseName='CloseSessionResponse']"/>
<xsl:apply-templates select="$file/node:UANodeSet/node:UADataType[@BrowseName='CloseSecureChannelRequest']"/>
<xsl:apply-templates select="$file/node:UANodeSet/node:UADataType[@BrowseName='CloseSecureChannelResponse']"/>
@@ -87,6 +95,46 @@
<xsl:apply-templates select="/opc:TypeDictionary/opc:StructuredType[@Name='ChannelSecurityToken']"/>
]
+[type 'MonitoredItemCreateRequest'
+ <xsl:apply-templates select="/opc:TypeDictionary/opc:StructuredType[@Name='MonitoredItemCreateRequest']"/>
+]
+
+[type 'BrowseResult'
+ <xsl:apply-templates select="/opc:TypeDictionary/opc:StructuredType[@Name='BrowseResult']"/>
+]
+
+[type 'ViewDescription'
+ <xsl:apply-templates select="/opc:TypeDictionary/opc:StructuredType[@Name='ViewDescription']"/>
+]
+
+[type 'BrowseDescription'
+ <xsl:apply-templates select="/opc:TypeDictionary/opc:StructuredType[@Name='BrowseDescription']"/>
+]
+
+[type 'ReferenceDescription'
+ <xsl:apply-templates select="/opc:TypeDictionary/opc:StructuredType[@Name='ReferenceDescription']"/>
+]
+
+[enum int 32 'MonitoringMode'
+ <xsl:apply-templates select="/opc:TypeDictionary/opc:EnumeratedType[@Name='MonitoringMode']"/>
+]
+
+[type 'MonitoringParameters'
+ <xsl:apply-templates select="/opc:TypeDictionary/opc:StructuredType[@Name='MonitoringParameters']"/>
+]
+
+[enum int 32 'BrowseDirection'
+ <xsl:apply-templates select="/opc:TypeDictionary/opc:EnumeratedType[@Name='BrowseDirection']"/>
+]
+
+[type 'ReferenceDescription'
+ <xsl:apply-templates select="/opc:TypeDictionary/opc:StructuredType[@Name='ReferenceDescription']"/>
+]
+
+[enum int 32 'NodeClass'
+<xsl:apply-templates select="/opc:TypeDictionary/opc:EnumeratedType[@Name='NodeClass']"/>
+]
+
[type 'DiagnosticInfo'
[simple bit 'symbolicIdSpecified']
[simple bit 'namespaceURISpecified']
@@ -170,6 +218,14 @@
[array uint 8 'value' count 'arrayLength']
]
+[type 'GuidValue'
+ [simple uint 32 'data1']
+ [simple uint 16 'data2']
+ [simple uint 16 'data3']
+ [array int 8 'data4' count '2']
+ [array int 8 'data5' count '6']
+]
+
[discriminatedType 'Variant'
[discriminator bit 'arrayLengthSpecified']
[simple bit 'arrayDimensionsSpecified']
@@ -229,7 +285,7 @@
]
['14' VariantGuid [bit 'arrayLengthSpecified']
[optional int 32 'arrayLength' 'arrayLengthSpecified']
- [array string '-1' 'value' count 'arrayLength == null ? 1 : arrayLength']
+ [array GuidValue 'value' count 'arrayLength == null ? 1 : arrayLength']
]
['15' VariantByteString [bit 'arrayLengthSpecified']
[optional int 32 'arrayLength' 'arrayLengthSpecified']
@@ -423,7 +479,7 @@
<xsl:choose>
<xsl:when test="not(@BrowseName='Vector') and not(substring(@BrowseName,1,1) = '<') and not(number(substring(@BrowseName,1,1)))">
[type '<xsl:value-of select='@BrowseName'/>'
- <xsl:apply-templates select="$originaldoc/opc:TypeDictionary/opc:StructuredType[@Name=$browseName]"/>]
+ <xsl:apply-templates select="$originaldoc/opc:TypeDictionary/opc:StructuredType[@Name=$browseName]"/>]
</xsl:when>
</xsl:choose>
</xsl:when>
@@ -516,9 +572,9 @@
<xsl:choose>
<xsl:when test="@LengthField">[array <xsl:value-of select="$dataType"/> '<xsl:value-of select="$lowerCaseName"/>' count '<xsl:value-of select="$lowerCaseLengthField"/>']
- </xsl:when>
+ </xsl:when>
<xsl:otherwise>[<xsl:value-of select="$mspecType"/><xsl:text> </xsl:text><xsl:value-of select="$dataType"/> '<xsl:value-of select="$lowerCaseName"/>']
- </xsl:otherwise>
+ </xsl:otherwise>
</xsl:choose>
</xsl:template>