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/05 11:33:24 UTC
[plc4x] branch feature/native_opua_client updated: Add read logic
for DINT datatype.
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 fd85e5d Add read logic for DINT datatype.
fd85e5d is described below
commit fd85e5ddb8b44b94e35cb121266b9e3d39425e7e
Author: hutcheb <be...@gmail.com>
AuthorDate: Tue Jan 5 06:32:09 2021 -0500
Add read logic for DINT datatype.
Next I'll generalize it to other data types.
---
.../java/opcua/protocol/OpcuaProtocolLogic.java | 134 +++++++-
protocols/opcua/src/main/xslt/opc-types.xsl | 344 +++++++--------------
2 files changed, 244 insertions(+), 234 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 1e5e233..6e7aba7 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
@@ -59,6 +59,7 @@ import org.apache.plc4x.java.spi.messages.DefaultPlcWriteRequest;
import org.apache.plc4x.java.spi.messages.DefaultPlcWriteResponse;
import org.apache.plc4x.java.spi.messages.utils.ResponseItem;
import org.apache.plc4x.java.spi.transaction.RequestTransactionManager;
+import org.apache.plc4x.java.spi.values.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -112,6 +113,9 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
private String endpoint;
private AtomicInteger transactionIdentifierGenerator = new AtomicInteger(1);
+ private AtomicInteger requestHandleGenerator = new AtomicInteger(1);
+ private AtomicInteger tokenId = new AtomicInteger(1);
+ private AtomicInteger channelId = new AtomicInteger(1);
@Override
public void setConfiguration(OpcuaConfiguration configuration) {
@@ -216,8 +220,8 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
public void onConnectCreateSessionRequest(ConversationContext<OpcuaAPU> context, OpcuaOpenResponse opcuaOpenResponse) throws PlcConnectionException {
OpenSecureChannelResponse openSecureChannelResponse = (OpenSecureChannelResponse) opcuaOpenResponse.getMessage();
- Integer tokenId = (int) openSecureChannelResponse.getSecurityToken().getTokenId();
- Integer channelId = (int) openSecureChannelResponse.getSecurityToken().getChannelId();
+ tokenId.set((int) openSecureChannelResponse.getSecurityToken().getTokenId());
+ channelId.set((int) openSecureChannelResponse.getSecurityToken().getChannelId());
int transactionId = transactionIdentifierGenerator.getAndIncrement();
if(transactionIdentifierGenerator.get() == 0xFFFF) {
@@ -275,8 +279,8 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
0L);
OpcuaMessageRequest messageRequest = new OpcuaMessageRequest(CHUNK,
- channelId,
- tokenId,
+ channelId.get(),
+ tokenId.get(),
nextSequenceNumber,
nextRequestId,
createSessionRequest);
@@ -300,8 +304,8 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
CreateSessionResponse createSessionResponse = (CreateSessionResponse) opcuaMessageResponse.getMessage();
authenticationToken = (NodeIdByteString) createSessionResponse.getAuthenticationToken();
- Integer tokenId = (int) opcuaMessageResponse.getSecureTokenId();
- Integer channelId = (int) opcuaMessageResponse.getSecureChannelId();
+ tokenId.set((int) opcuaMessageResponse.getSecureTokenId());
+ channelId.set((int) opcuaMessageResponse.getSecureChannelId());
int transactionId = transactionIdentifierGenerator.getAndIncrement();
if(transactionIdentifierGenerator.get() == 0xFFFF) {
@@ -316,9 +320,14 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
throw new PlcConnectionException("Sequence number isn't as expected, we might have missed a packet. - " + transactionId + " != " + nextSequenceNumber);
}
+ int requestHandle = requestHandleGenerator.getAndIncrement();
+ if(requestHandleGenerator.get() == 0xFFFF) {
+ requestHandleGenerator.set(1);
+ }
+
RequestHeader requestHeader = new RequestHeader(authenticationToken,
getCurrentDateTime(),
- 1L,
+ requestHandle,
0L,
NULL_STRING,
10000L,
@@ -360,8 +369,8 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
clientSignature);
OpcuaMessageRequest activateMessageRequest = new OpcuaMessageRequest(CHUNK,
- channelId,
- tokenId,
+ channelId.get(),
+ tokenId.get(),
nextSequenceNumber,
nextRequestId,
activateSessionRequest);
@@ -373,9 +382,116 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
.handle(opcuaActivateResponse -> {
LOGGER.debug("Got Activate Session Response Connection Response");
+ ActivateSessionResponse activateMessageResponse = (ActivateSessionResponse) opcuaActivateResponse.getMessage();
+
+ long returnedRequestHandle = activateMessageResponse.getResponseHeader().getRequestHandle();
+ if (!(requestHandle == returnedRequestHandle)) {
+ LOGGER.error("Request handle isn't as expected, we might have missed a packet. - " + requestHandle + " != " + returnedRequestHandle);
+ }
+
+ // Send an event that connection setup is complete.
+ context.fireConnected();
});
}
+ @Override
+ public CompletableFuture<PlcReadResponse> read(PlcReadRequest readRequest) {
+ LOGGER.info("Reading Value");
+ CompletableFuture<PlcReadResponse> future = new CompletableFuture<>();
+ DefaultPlcReadRequest request = (DefaultPlcReadRequest) readRequest;
+
+ if(request.getFieldNames().size() == 1) {
+ String fieldName = request.getFieldNames().iterator().next();
+ OpcuaField field = (OpcuaField) request.getField(fieldName);
+
+ int requestHandle = requestHandleGenerator.getAndIncrement();
+ // If we've reached the max value for a 16 bit transaction identifier, reset back to 1
+ if(requestHandleGenerator.get() == 0xFFFF) {
+ requestHandleGenerator.set(1);
+ }
+
+ RequestHeader requestHeader = new RequestHeader(authenticationToken,
+ getCurrentDateTime(),
+ requestHandle,
+ 0L,
+ NULL_STRING,
+ 10000L,
+ NULL_EXTENSION_OBJECT);
+
+ ReadValueId[] readValueArray = new ReadValueId[1];
+
+ NodeIdString nodeId = new NodeIdString(NodeIdType.nodeIdTypeString, new StringNodeId(field.getNamespace(), new PascalString(field.getIdentifier().length(), field.getIdentifier())));
+
+ readValueArray[0] = new ReadValueId(nodeId,
+ 0xD,
+ NULL_STRING,
+ new QualifiedName(0, NULL_STRING));
+
+ ReadRequest opcuaReadRequest = new ReadRequest((byte) 1,
+ (byte) 0,
+ requestHeader,
+ 0.0d,
+ TimestampsToReturn.timestampsToReturnNeither,
+ readValueArray.length,
+ readValueArray);
+
+ int transactionIdentifier = transactionIdentifierGenerator.getAndIncrement();
+ // If we've reached the max value for a 16 bit transaction identifier, reset back to 1
+ if(transactionIdentifierGenerator.get() == 0xFFFF) {
+ transactionIdentifierGenerator.set(1);
+ }
+
+ OpcuaMessageRequest readMessageRequest = new OpcuaMessageRequest(CHUNK,
+ channelId.get(),
+ tokenId.get(),
+ transactionIdentifier,
+ transactionIdentifier,
+ opcuaReadRequest);
+
+ RequestTransactionManager.RequestTransaction transaction = tm.startRequest();
+ transaction.submit(() -> context.sendRequest(new OpcuaAPU(readMessageRequest))
+ .expectResponse(OpcuaAPU.class, REQUEST_TIMEOUT)
+ .onTimeout(future::completeExceptionally)
+ .onError((p, e) -> future.completeExceptionally(e))
+ .check(p -> p.getMessage() instanceof OpcuaMessageResponse)
+ .unwrap(p -> (OpcuaMessageResponse) p.getMessage())
+ .handle(opcuaResponse -> {
+ // Try to decode the response data based on the corresponding request.
+ ReadResponse readResponse = (ReadResponse) opcuaResponse.getMessage();
+
+ //TODO;- Fix this
+ DataValue[] results = readResponse.getResults();
+ Integer value = null;
+ if (results.length > 0) {
+ Variant variant = results[0].getValue();
+ LOGGER.info("Repsponse Include Variant of type " + variant.getClass().toString());
+ if (variant instanceof VariantInt32) {
+ value = ((VariantInt32) variant).getValue()[0];
+ }
+ }
+
+ PlcValue plcValue = new PlcDINT(value);
+ // Prepare the response.
+ PlcReadResponse response = new DefaultPlcReadResponse(request,
+ Collections.singletonMap(fieldName, new ResponseItem<>(PlcResponseCode.OK, plcValue)));
+
+ // Pass the response back to the application.
+ future.complete(response);
+
+ // Finish the request-transaction.
+ transaction.endRequest();
+ }));
+ } else {
+ future.completeExceptionally(new PlcRuntimeException("Modbus only supports single filed requests"));
+ }
+ return future;
+ }
+
+ @Override
+ protected void decode(ConversationContext<OpcuaAPU> context, OpcuaAPU msg) throws Exception {
+ super.decode(context, msg);
+ }
+
private long getCurrentDateTime() {
return (System.currentTimeMillis() * 10000) + epochOffset;
diff --git a/protocols/opcua/src/main/xslt/opc-types.xsl b/protocols/opcua/src/main/xslt/opc-types.xsl
index f3e54cf..4a74ae2 100644
--- a/protocols/opcua/src/main/xslt/opc-types.xsl
+++ b/protocols/opcua/src/main/xslt/opc-types.xsl
@@ -139,237 +139,131 @@
]
[type 'DataValue'
- <xsl:apply-templates select="/opc:TypeDictionary/opc:StructuredType[@Name='DataValue']"/>
+ //A value with an associated timestamp, and quality..
+ [simple bit 'reserved2']
+ [simple bit 'reserved1']
+ [simple bit 'serverPicosecondsSpecified']
+ [simple bit 'sourcePicosecondsSpecified']
+ [simple bit 'serverTimestampSpecified']
+ [simple bit 'sourceTimestampSpecified']
+ [simple bit 'statusCodeSpecified']
+ [simple bit 'valueSpecified']
+ [optional Variant 'value' 'valueSpecified']
+ [optional StatusCode 'statusCode' 'statusCodeSpecified']
+ [optional int 64 'sourceTimestamp' 'sourceTimestampSpecified']
+ [optional uint 16 'sourcePicoseconds' 'sourcePicosecondsSpecified']
+ [optional int 64 'serverTimestamp' 'serverTimestampSpecified']
+ [optional uint 16 'serverPicoseconds' 'serverPicosecondsSpecified']
]
[discriminatedType 'Variant'
+ [discriminator bit 'arrayLengthSpecified']
+ [simple bit 'arrayDimensionsSpecified']
[discriminator uint 6 'VariantType']
- [typeSwitch 'VariantType'
- ['1' VariantBoolean
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array bit 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
- ]
- ['2' VariantSByte
-
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array int 8 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
- ]
- ['3' VariantByte
-
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array uint 8 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
- ]
- ['4' VariantInt16
-
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array int 16 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
- ]
- ['5' VariantUInt16
-
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array uint 16 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
- ]
- ['6' VariantInt32
-
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array int 32 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
- ]
- ['7' VariantUInt32
-
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array uint 32 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
- ]
- ['8' VariantInt64
-
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array int 64 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
- ]
- ['9' VariantUInt64
-
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array uint 64 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
- ]
- ['10' VariantFloat
-
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array float 8.23 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
- ]
- ['11' VariantDouble
-
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array float 11.52 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
- ]
- ['12' VariantString
-
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array PascalString 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
- ]
- ['13' VariantDateTime
-
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array int 64 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
- ]
- ['14' VariantGuid
-
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array string '-1' 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
- ]
- ['15' VariantByteString
-
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array PascalString 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
- ]
- ['16' VariantXmlElement
-
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array XmlElement 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
- ]
- ['17' VariantNodeId
-
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array NodeId 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
- ]
- ['18' VariantExpandedNodeId
-
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array ExpandedNodeId 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
- ]
- ['19' VariantStatusCode
-
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array StatusCode 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
- ]
- ['20' VariantQualifiedName
-
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array QualifiedName 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
- ]
- ['21' VariantLocalizedText
-
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array LocalizedText 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
- ]
- ['22' VariantExtensionObject
-
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array ExtensionObject 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
- ]
- ['23' VariantDataValue
-
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array DataValue 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
- ]
- ['24' VariantVariant
-
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array Variant 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
- ]
- ['25' VariantDiagnosticInfo
-
- [simple bit 'ArrayDimensionsSpecified']
- [simple bit 'ArrayLengthSpecified']
- [simple int 32 'arrayLength']
- [array DiagnosticInfo 'value' count 'arrayLength']
- [simple int 32 'noOfArrayDimensions']
- [array bit 'arrayDimensions' count 'noOfArrayDimensions']
+ [typeSwitch 'VariantType','arrayLengthSpecified'
+ ['1' VariantBoolean [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array bit 'value' count 'arrayLength == null ? 1 : arrayLength']
+ ]
+ ['2' VariantSByte [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array int 8 'value' count 'arrayLength == null ? 1 : arrayLength']
+ ]
+ ['3' VariantByte [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array uint 8 'value' count 'arrayLength == null ? 1 : arrayLength']
+ ]
+ ['4' VariantInt16 [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array int 16 'value' count 'arrayLength == null ? 1 : arrayLength']
+ ]
+ ['5' VariantUInt16 [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array uint 16 'value' count 'arrayLength == null ? 1 : arrayLength']
+ ]
+ ['6' VariantInt32 [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array int 32 'value' count 'arrayLength == null ? 1 : arrayLength']
+ ]
+ ['7' VariantUInt32 [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array uint 32 'value' count 'arrayLength == null ? 1 : arrayLength']
+ ]
+ ['8' VariantInt64 [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array int 64 'value' count 'arrayLength == null ? 1 : arrayLength']
+ ]
+ ['9' VariantUInt64 [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array uint 64 'value' count 'arrayLength == null ? 1 : arrayLength']
+ ]
+ ['10' VariantFloat [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array float 8.23 'value' count 'arrayLength == null ? 1 : arrayLength']
+ ]
+ ['11' VariantDouble [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array float 11.52 'value' count 'arrayLength == null ? 1 : arrayLength']
+ ]
+ ['12' VariantString [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array PascalString 'value' count 'arrayLength == null ? 1 : arrayLength']
+ ]
+ ['13' VariantDateTime [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array int 64 'value' count 'arrayLength == null ? 1 : arrayLength']
+ ]
+ ['14' VariantGuid [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array string '-1' 'value' count 'arrayLength == null ? 1 : arrayLength']
+ ]
+ ['15' VariantByteString [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array PascalString 'value' count 'arrayLength == null ? 1 : arrayLength']
+ ]
+ ['16' VariantXmlElement [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array XmlElement 'value' count 'arrayLength == null ? 1 : arrayLength']
+ ]
+ ['17' VariantNodeId [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array NodeId 'value' count 'arrayLength == null ? 1 : arrayLength']
+ ]
+ ['18' VariantExpandedNodeId [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array ExpandedNodeId 'value' count 'arrayLength == null ? 1 : arrayLength']
+ ]
+ ['19' VariantStatusCode [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array StatusCode 'value' count 'arrayLength == null ? 1 : arrayLength']
+ ]
+ ['20' VariantQualifiedName [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array QualifiedName 'value' count 'arrayLength == null ? 1 : arrayLength']
+ ]
+ ['21' VariantLocalizedText [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array LocalizedText 'value' count 'arrayLength == null ? 1 : arrayLength']
+ ]
+ ['22' VariantExtensionObject [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array ExtensionObject 'value' count 'arrayLength == null ? 1 : arrayLength']
+ ]
+ ['23' VariantDataValue [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array DataValue 'value' count 'arrayLength == null ? 1 : arrayLength']
+ ]
+ ['24' VariantVariant [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array Variant 'value' count 'arrayLength == null ? 1 : arrayLength']
+ ]
+ ['25' VariantDiagnosticInfo [bit 'arrayLengthSpecified']
+ [optional int 32 'arrayLength' 'arrayLengthSpecified']
+ [array DiagnosticInfo 'value' count 'arrayLength == null ? 1 : arrayLength']
]
]
+ [optional int 32 'noOfArrayDimensions' 'arrayDimensionsSpecified']
+ [array bit 'arrayDimensions' count 'noOfArrayDimensions == null ? 0 : noOfArrayDimensions']
]
[discriminatedType 'NodeId'