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/08 10:31:36 UTC

[plc4x] branch feature/native_opua_client updated: Add enum types and close request logic

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 597deaf  Add enum types and close request logic
597deaf is described below

commit 597deaf080806c775ca40189f6f29e24aa0eccf9
Author: hutcheb <be...@gmail.com>
AuthorDate: Fri Jan 8 05:30:57 2021 -0500

    Add enum types and close request logic
---
 .../java/opcua/protocol/OpcuaProtocolLogic.java    | 197 +++++++++++++++++++--
 protocols/opcua/pom.xml                            |  62 ++++++-
 .../apache/plc4x/protocol/opcua/OpcuaProtocol.java |   2 +-
 .../src/main/resources/protocols/opcua/opcua.mspec |  55 +++---
 protocols/opcua/src/main/xslt/opc-types.xsl        |  56 ++++--
 5 files changed, 307 insertions(+), 65 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 6e7aba7..db8c5d7 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
@@ -24,9 +24,7 @@ import io.netty.buffer.Unpooled;
 import org.apache.commons.lang3.RandomStringUtils;
 import org.apache.plc4x.java.api.PlcConnection;
 import org.apache.plc4x.java.api.authentication.PlcAuthentication;
-import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
-import org.apache.plc4x.java.api.exceptions.PlcProtocolException;
-import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
+import org.apache.plc4x.java.api.exceptions.*;
 import org.apache.plc4x.java.api.messages.PlcReadRequest;
 import org.apache.plc4x.java.api.messages.PlcReadResponse;
 import org.apache.plc4x.java.api.messages.PlcResponse;
@@ -60,11 +58,13 @@ 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.eclipse.milo.opcua.stack.core.types.builtin.DateTime;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.UnsupportedEncodingException;
 import java.time.Duration;
+import java.math.BigInteger;
 import java.util.*;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -82,7 +82,8 @@ import static org.apache.plc4x.java.spi.configuration.ConfigurationFactory.confi
 public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements HasConfiguration<OpcuaConfiguration> {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(OpcuaProtocolLogic.class);
-    public static final Duration REQUEST_TIMEOUT = Duration.ofMillis(10000);
+    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_RECEIVE_BUFFER_SIZE = 65535;
@@ -125,7 +126,49 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
 
     @Override
     public void close(ConversationContext<OpcuaAPU> context) {
-        // Nothing to do here ...
+        int transactionId = transactionIdentifierGenerator.getAndIncrement();
+        if(transactionIdentifierGenerator.get() == 0xFFFF) {
+            transactionIdentifierGenerator.set(1);
+        }
+
+        int requestHandle = requestHandleGenerator.getAndIncrement();
+        if(requestHandleGenerator.get() == 0xFFFF) {
+            requestHandleGenerator.set(1);
+        }
+
+        ExpandedNodeId expandedNodeId = new ExpandedNodeIdFourByte(false,           //Namespace Uri Specified
+            false,            //Server Index Specified
+            NULL_STRING,                      //Namespace Uri
+            1L,                     //Server Index
+            new FourByteNodeId((short) 0, 473));    //Identifier for OpenSecureChannel
+
+        RequestHeader requestHeader = new RequestHeader(authenticationToken,
+            getCurrentDateTime(),
+            requestHandle,                                         //RequestHandle
+            0L,
+            NULL_STRING,
+            5000L,
+            NULL_EXTENSION_OBJECT);
+
+        CloseSessionRequest closeSessionRequest = new CloseSessionRequest((byte) 1,
+            (byte) 0,
+            requestHeader,
+            true);
+
+        OpcuaMessageRequest messageRequest = new OpcuaMessageRequest(CHUNK,
+            channelId.get(),
+            tokenId.get(),
+            transactionId,
+            transactionId,
+            closeSessionRequest);
+
+        context.sendRequest(new OpcuaAPU(messageRequest))
+            .expectResponse(OpcuaAPU.class, REQUEST_TIMEOUT)
+            .check(p -> p.getMessage() instanceof OpcuaMessageResponse)
+            .unwrap(p -> (OpcuaMessageResponse) p.getMessage())
+            .handle(opcuaMessageResponse -> {
+                LOGGER.debug("Got Close Session Response Connection Response");
+            });
     }
 
     @Override
@@ -182,7 +225,7 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
             0L,                                         //RequestHandle
             0L,
             NULL_STRING,
-            10000L,
+            REQUEST_TIMEOUT_LONG,
             NULL_EXTENSION_OBJECT);
 
         OpenSecureChannelRequest openSecureChannelRequest = new OpenSecureChannelRequest((byte) 1,
@@ -241,7 +284,7 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
             0L,
             0L,
             NULL_STRING,
-            10000L,
+            REQUEST_TIMEOUT_LONG,
             NULL_EXTENSION_OBJECT);
 
         LocalizedText applicationName = new LocalizedText((short) 0,
@@ -330,7 +373,7 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
             requestHandle,
             0L,
             NULL_STRING,
-            10000L,
+            REQUEST_TIMEOUT_LONG,
             NULL_EXTENSION_OBJECT);
 
         SignatureData clientSignature = new SignatureData(NULL_STRING, NULL_STRING);
@@ -415,7 +458,7 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
                 requestHandle,
                 0L,
                 NULL_STRING,
-                10000L,
+                REQUEST_TIMEOUT_LONG,
                 NULL_EXTENSION_OBJECT);
 
             ReadValueId[] readValueArray = new ReadValueId[1];
@@ -459,21 +502,137 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
                     // 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;
+                    PlcValue value = null;
+                    PlcResponseCode responseCode = PlcResponseCode.OK;
                     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];
+                        if (results[0].getStatusCode() == null) {
+                            Variant variant = results[0].getValue();
+                            LOGGER.info("Repsponse includes Variant of type " + variant.getClass().toString());
+                            if (variant instanceof VariantBoolean) {
+                                boolean[] array = ((VariantBoolean) variant).getValue();
+                                int length = array.length;
+                                Boolean[] tmpValue = new Boolean[length];
+                                for (int i = 0; i < length; i++) {
+                                    tmpValue[i] = array[i];
+                                }
+                                value = IEC61131ValueHandler.of(tmpValue);
+                            } else if (variant instanceof VariantSByte) {
+                                byte[] array = ((VariantSByte) variant).getValue();
+                                int length = array.length;
+                                Byte[] tmpValue = new Byte[length];
+                                for (int i = 0; i < length; i++) {
+                                    tmpValue[i] = array[i];
+                                }
+                                value = IEC61131ValueHandler.of(tmpValue);
+                            } else if (variant instanceof VariantByte) {
+                                short[] array = ((VariantByte) variant).getValue();
+                                int length = array.length;
+                                Short[] tmpValue = new Short[length];
+                                for (int i = 0; i < length; i++) {
+                                    tmpValue[i] = array[i];
+                                }
+                                value = IEC61131ValueHandler.of(tmpValue);
+                            } else if (variant instanceof VariantInt16) {
+                                short[] array = ((VariantInt16) variant).getValue();
+                                int length = array.length;
+                                Short[] tmpValue = new Short[length];
+                                for (int i = 0; i < length; i++) {
+                                    tmpValue[i] = array[i];
+                                }
+                                value = IEC61131ValueHandler.of(tmpValue);
+                            } else if (variant instanceof VariantUInt16) {
+                                int[] array = ((VariantUInt16) variant).getValue();
+                                int length = array.length;
+                                Integer[] tmpValue = new Integer[length];
+                                for (int i = 0; i < length; i++) {
+                                    tmpValue[i] = array[i];
+                                }
+                                value = IEC61131ValueHandler.of(tmpValue);
+                            } else if (variant instanceof VariantInt32) {
+                                int[] array = ((VariantInt32) variant).getValue();
+                                int length = array.length;
+                                Integer[] tmpValue = new Integer[length];
+                                for (int i = 0; i < length; i++) {
+                                    tmpValue[i] = array[i];
+                                }
+                                value = IEC61131ValueHandler.of(tmpValue);
+                            } else if (variant instanceof VariantUInt32) {
+                                long[] array = ((VariantUInt32) variant).getValue();
+                                int length = array.length;
+                                Long[] tmpValue = new Long[length];
+                                for (int i = 0; i < length; i++) {
+                                    tmpValue[i] = array[i];
+                                }
+                                value = IEC61131ValueHandler.of(tmpValue);
+                            } else if (variant instanceof VariantInt64) {
+                                long[] array = ((VariantInt64) variant).getValue();
+                                int length = array.length;
+                                Long[] tmpValue = new Long[length];
+                                for (int i = 0; i < length; i++) {
+                                    tmpValue[i] = array[i];
+                                }
+                                value = IEC61131ValueHandler.of(tmpValue);
+                            } else if (variant instanceof VariantUInt64) {
+                                value = IEC61131ValueHandler.of(((VariantUInt64) variant).getValue());
+                            } else if (variant instanceof VariantFloat) {
+                                float[] array = ((VariantFloat) variant).getValue();
+                                int length = array.length;
+                                Float[] tmpValue = new Float[length];
+                                for (int i = 0; i < length; i++) {
+                                    tmpValue[i] = array[i];
+                                }
+                                value = IEC61131ValueHandler.of(tmpValue);
+                            } else if (variant instanceof VariantDouble) {
+                                double[] array = ((VariantDouble) variant).getValue();
+                                int length = array.length;
+                                Double[] tmpValue = new Double[length];
+                                for (int i = 0; i < length; i++) {
+                                    tmpValue[i] = array[i];
+                                }
+                                value = IEC61131ValueHandler.of(tmpValue);
+                            } else if (variant instanceof VariantString) {
+                                int length = ((VariantString) variant).getValue().length;
+                                PascalString[] stringArray = ((VariantString) variant).getValue();
+                                String[] tmpValue = new String[length];
+                                for (int i = 0; i < length; i++) {
+                                    tmpValue[i] = stringArray[i].getStringValue();
+                                }
+                                value = IEC61131ValueHandler.of(tmpValue);
+                            } else if (variant instanceof VariantDateTime) {
+                                long[] array = ((VariantDateTime) variant).getValue();
+                                int length = array.length;
+                                DateTime[] tmpValue = new DateTime[length];
+                                for (int i = 0; i < length; i++) {
+                                    tmpValue[i] = new DateTime(array[i]);
+                                }
+                                value = IEC61131ValueHandler.of(tmpValue);
+                            } else if (variant instanceof VariantGuid) {
+                                int length = ((VariantGuid) variant).getValue().length;
+                                String[] stringArray = ((VariantGuid) variant).getValue();
+                                value = IEC61131ValueHandler.of(stringArray);
+                            } else if (variant instanceof VariantXmlElement) {
+                                int length = ((VariantXmlElement) variant).getValue().length;
+                                PascalString[] stringArray = ((VariantXmlElement) variant).getValue();
+                                String[] tmpValue = new String[length];
+                                for (int i = 0; i < length; i++) {
+                                    tmpValue[i] = stringArray[i].getStringValue();
+                                }
+                                value = IEC61131ValueHandler.of(tmpValue);
+                            } else {
+                                responseCode = PlcResponseCode.UNSUPPORTED;
+                                LOGGER.error("Data type - " +  variant.getClass() + " is not supported ");
+                            }
+                        } else {
+                            responseCode = PlcResponseCode.UNSUPPORTED;
+                            LOGGER.error("Error while reading value from OPC UA server error code:- " + results[0].getStatusCode().toString());
                         }
+
                     }
 
-                    PlcValue plcValue = new PlcDINT(value);
                     // Prepare the response.
                     PlcReadResponse response = new DefaultPlcReadResponse(request,
-                        Collections.singletonMap(fieldName, new ResponseItem<>(PlcResponseCode.OK, plcValue)));
+                        Collections.singletonMap(fieldName, new ResponseItem<>(responseCode, value)));
 
                     // Pass the response back to the application.
                     future.complete(response);
@@ -496,4 +655,8 @@ public class OpcuaProtocolLogic extends Plc4xProtocolBase<OpcuaAPU> implements H
     private long getCurrentDateTime() {
         return (System.currentTimeMillis() * 10000) + epochOffset;
     }
+
+    private long getDateTime(long dateTime) {
+        return (dateTime - epochOffset) / 10000;
+    }
 }
diff --git a/protocols/opcua/pom.xml b/protocols/opcua/pom.xml
index aeb3acb..8b24b88 100644
--- a/protocols/opcua/pom.xml
+++ b/protocols/opcua/pom.xml
@@ -49,11 +49,31 @@
                   <url>https://opcfoundation.org/UA/schemas/1.04/Opc.Ua.Types.bsd</url>
                   <unpack>false</unpack>
                   <outputDirectory>${project.build.directory}/downloads</outputDirectory>
-                  <outputFileName>opc-datatypes.xml</outputFileName>
+                  <outputFileName>Opc.Ua.Types.bsd</outputFileName>
                 </configuration>
               </execution>
             </executions>
           </plugin>
+        <!-- Fetch the master-data which will be used to translate manufacturer ids to readable names -->
+        <plugin>
+          <groupId>com.googlecode.maven-download-plugin</groupId>
+          <artifactId>download-maven-plugin</artifactId>
+          <executions>
+            <execution>
+              <id>fetch-opc-statuscodes</id>
+              <phase>generate-resources</phase>
+              <goals>
+                <goal>wget</goal>
+              </goals>
+              <configuration>
+                <url>https://opcfoundation.org/UA/schemas/1.04/StatusCode.csv</url>
+                <unpack>false</unpack>
+                <outputDirectory>${project.build.directory}/downloads</outputDirectory>
+                <outputFileName>StatusCode.csv</outputFileName>
+              </configuration>
+            </execution>
+          </executions>
+        </plugin>
           <plugin>
             <groupId>com.googlecode.maven-download-plugin</groupId>
             <artifactId>download-maven-plugin</artifactId>
@@ -68,7 +88,26 @@
                   <url>https://opcfoundation.org/UA/schemas/1.04/Opc.Ua.NodeSet2.Services.xml</url>
                   <unpack>false</unpack>
                   <outputDirectory>${project.build.directory}/downloads</outputDirectory>
-                  <outputFileName>opc-discriminators.xml</outputFileName>
+                  <outputFileName>Opc.Ua.NodeSet2.Services.xml</outputFileName>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+          <plugin>
+            <groupId>com.googlecode.maven-download-plugin</groupId>
+            <artifactId>download-maven-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>fetch-opc-services-enum</id>
+                <phase>generate-resources</phase>
+                <goals>
+                  <goal>wget</goal>
+                </goals>
+                <configuration>
+                  <url>https://opcfoundation.org/UA/schemas/1.04/Opc.Ua.NodeIds.Services.csv</url>
+                  <unpack>false</unpack>
+                  <outputDirectory>${project.build.directory}/downloads</outputDirectory>
+                  <outputFileName>Opc.Ua.NodeIds.Services.csv</outputFileName>
                 </configuration>
               </execution>
             </executions>
@@ -89,7 +128,7 @@
               <transformationSets>
                 <transformationSet>
                   <dir>${project.build.directory}/downloads</dir>
-                  <includes>opc-datatypes.xml</includes>
+                  <includes>Opc.Ua.Types.bsd</includes>
                   <stylesheet>src/main/xslt/opc-types.xsl</stylesheet>
                   <outputDir>${project.build.outputDirectory}/protocols/opcua</outputDir>
                   <fileMappers>
@@ -100,7 +139,15 @@
                   <parameters>
                     <parameter>
                       <name>services</name>
-                      <value>${project.build.directory}/downloads/opc-discriminators.xml</value>
+                      <value>${project.build.directory}/downloads/Opc.Ua.NodeSet2.Services.xml</value>
+                    </parameter>
+                    <parameter>
+                      <name>servicesEnum</name>
+                      <value>${project.build.directory}/downloads/Opc.Ua.NodeIds.Services.csv</value>
+                    </parameter>
+                    <parameter>
+                      <name>statusCodes</name>
+                      <value>${project.build.directory}/downloads/StatusCode.csv</value>
                     </parameter>
                   </parameters>                  
                   <outputProperties>
@@ -112,6 +159,13 @@
                 </transformationSet>
               </transformationSets>
             </configuration>
+            <dependencies>
+              <dependency>
+                <groupId>net.sf.saxon</groupId>
+                <artifactId>saxon</artifactId>
+                <version>8.7</version>
+              </dependency>
+            </dependencies>
           </plugin>
       </plugins>
   </build>
diff --git a/protocols/opcua/src/main/java/org/apache/plc4x/protocol/opcua/OpcuaProtocol.java b/protocols/opcua/src/main/java/org/apache/plc4x/protocol/opcua/OpcuaProtocol.java
index dbafedd..1985acc 100644
--- a/protocols/opcua/src/main/java/org/apache/plc4x/protocol/opcua/OpcuaProtocol.java
+++ b/protocols/opcua/src/main/java/org/apache/plc4x/protocol/opcua/OpcuaProtocol.java
@@ -47,7 +47,7 @@ public class OpcuaProtocol implements Protocol {
             new LinkedHashMap<>(new MessageFormatParser().parse(schemaInputStream));
 
         InputStream masterDataInputStream = OpcuaProtocol.class.getResourceAsStream(
-            "/protocols/opcua/opc-datatypes.mspec");
+            "/protocols/opcua/Opc.Ua.Types.mspec");
         if(masterDataInputStream == null) {
             throw new GenerationException("Error loading message-format schema for protocol '" + getName() + "'");
         }
diff --git a/protocols/opcua/src/main/resources/protocols/opcua/opcua.mspec b/protocols/opcua/src/main/resources/protocols/opcua/opcua.mspec
index c50a140..e2c8743 100644
--- a/protocols/opcua/src/main/resources/protocols/opcua/opcua.mspec
+++ b/protocols/opcua/src/main/resources/protocols/opcua/opcua.mspec
@@ -105,38 +105,33 @@
 ]
 
 
-[enum string '-1' 'OpcuaDataType'
-    ['IEC61131_NULL' NULL ]
-    ['IEC61131_BOOL' BOOL ]
-    ['IEC61131_BYTE' BYTE ]
-    ['IEC61131_WORD' WORD ]
-    ['IEC61131_DWORD' DWORD ]
-    ['IEC61131_LWORD' LWORD ]
-    ['IEC61131_SINT' SINT ]
-    ['IEC61131_INT' INT ]
-    ['IEC61131_DINT' DINT ]
-    ['IEC61131_LINT' LINT ]
-    ['IEC61131_USINT' USINT ]
-    ['IEC61131_UINT' UINT ]
-    ['IEC61131_UDINT' UDINT ]
-    ['IEC61131_ULINT' ULINT ]
-    ['IEC61131_REAL' REAL ]
-    ['IEC61131_LREAL' LREAL ]
-    ['IEC61131_TIME' TIME ]
-    ['IEC61131_LTIME' LTIME ]
-    ['IEC61131_DATE' DATE ]
-    ['IEC61131_LDATE' LDATE ]
-    ['IEC61131_TIME_OF_DAY' TIME_OF_DAY ]
-    ['IEC61131_LTIME_OF_DAY' LTIME_OF_DAY ]
-    ['IEC61131_DATE_AND_TIME' DATE_AND_TIME ]
-    ['IEC61131_LDATE_AND_TIME' LDATE_AND_TIME ]
-    ['IEC61131_CHAR' CHAR ]
-    ['IEC61131_WCHAR' WCHAR ]
-    ['IEC61131_STRING' STRING ]
-    ['IEC61131_WSTRING' WSTRING ]
+[enum string '-1' 'OpcuaDataType' [uint 8 'variantType']
+    ['IEC61131_NULL' NULL ['0']]
+    ['IEC61131_BOOL' BOOL ['1']]
+    ['IEC61131_BYTE' BYTE ['3']]
+    ['IEC61131_SINT' SINT ['2']]
+    ['IEC61131_INT' INT ['4']]
+    ['IEC61131_DINT' DINT ['6']]
+    ['IEC61131_LINT' LINT ['8']]
+    ['IEC61131_USINT' USINT ['3']]
+    ['IEC61131_UINT' UINT ['5']]
+    ['IEC61131_UDINT' UDINT ['7']]
+    ['IEC61131_ULINT' ULINT ['9']]
+    ['IEC61131_REAL' REAL ['10']]
+    ['IEC61131_LREAL' LREAL ['11']]
+    ['IEC61131_TIME' TIME ['1']]
+    ['IEC61131_LTIME' LTIME ['1']]
+    ['IEC61131_DATE' DATE ['1']]
+    ['IEC61131_LDATE' LDATE ['1']]
+    ['IEC61131_TIME_OF_DAY' TIME_OF_DAY ['1']]
+    ['IEC61131_LTIME_OF_DAY' LTIME_OF_DAY ['1']]
+    ['IEC61131_DATE_AND_TIME' DATE_AND_TIME ['13']]
+    ['IEC61131_LDATE_AND_TIME' LDATE_AND_TIME ['1']]
+    ['IEC61131_CHAR' CHAR ['1']]
+    ['IEC61131_WCHAR' WCHAR ['1']]
+    ['IEC61131_STRING' STRING ['12']]
 ]
 
-
 [enum string '-1' 'OpcuaIdentifierType'
     ['s' STRING_IDENTIFIER]
     ['i' NUMBER_IDENTIFIER]
diff --git a/protocols/opcua/src/main/xslt/opc-types.xsl b/protocols/opcua/src/main/xslt/opc-types.xsl
index 4a74ae2..7402f87 100644
--- a/protocols/opcua/src/main/xslt/opc-types.xsl
+++ b/protocols/opcua/src/main/xslt/opc-types.xsl
@@ -17,7 +17,7 @@
   specific language governing permissions and limitations
   under the License.
 -->
-<xsl:stylesheet version="1.0"
+<xsl:stylesheet version="2.0"
                 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                 xmlns:opc="http://opcfoundation.org/BinarySchema/"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -32,9 +32,14 @@
     />
 
     <xsl:param name="services"></xsl:param>
+    <xsl:param name="statusCodes"></xsl:param>
+    <xsl:param name="servicesEnum"></xsl:param>
 
+    <xsl:variable name="originaldoc" select="/"/>
 
     <xsl:param name="file" select="document($services)"/>
+    <xsl:param name="statusCodeFile" select="unparsed-text($statusCodes)"/>
+    <xsl:param name="servicesEnumFile" select="unparsed-text($servicesEnum)"/>
 
     <xsl:variable name="lowercase" select="'abcdefghijklmnopqrstuvwxyz'"/>
     <xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
@@ -55,7 +60,11 @@
         <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']"/>
-        <xsl:apply-templates select="$file/node:UANodeSet/node:UADataType[@BrowseName='CloseSessionRequest']"/>
+        ['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']"/>
@@ -223,7 +232,7 @@
         ]
         ['16' VariantXmlElement [bit 'arrayLengthSpecified']
             [optional int 32 'arrayLength' 'arrayLengthSpecified']
-            [array XmlElement 'value' count 'arrayLength == null ? 1 : arrayLength']
+            [array PascalString 'value' count 'arrayLength == null ? 1 : arrayLength']
         ]
         ['17' VariantNodeId [bit 'arrayLengthSpecified']
             [optional int 32 'arrayLength' 'arrayLengthSpecified']
@@ -393,7 +402,8 @@
     <xsl:apply-templates select="/opc:TypeDictionary/opc:StructuredType[@Name='WriteValue']"/>
 ]
 
-
+        <xsl:call-template name="statusCodeParsing"/>
+        <xsl:call-template name="servicesEnumParsing"/>
 
     </xsl:template>
 
@@ -402,12 +412,11 @@
             <xsl:value-of select='@BrowseName'/>
         </xsl:variable>
         <xsl:choose>
-            <xsl:when test="/opc:TypeDictionary/opc:StructuredType[@Name=$browseName]">
+            <xsl:when test="$originaldoc/opc:TypeDictionary/opc:StructuredType[@Name=$browseName]">
                 <xsl:choose>
                     <xsl:when test="not(@BrowseName='Vector') and not(substring(@BrowseName,1,1) = '&lt;') and not(number(substring(@BrowseName,1,1)))">
-                [type '<xsl:value-of select='@BrowseName'/>'
-                    <xsl:apply-templates select="/opc:TypeDictionary/opc:StructuredType[@Name=$browseName]"/>
-                ]
+    [type '<xsl:value-of select='@BrowseName'/>'
+                    <xsl:apply-templates select="$originaldoc/opc:TypeDictionary/opc:StructuredType[@Name=$browseName]"/>]
                     </xsl:when>
                 </xsl:choose>
             </xsl:when>
@@ -419,13 +428,12 @@
             <xsl:value-of select='@BrowseName'/>
         </xsl:variable>
         <xsl:choose>
-            <xsl:when test="/opc:TypeDictionary/opc:StructuredType[@Name=$browseName]">
+            <xsl:when test="$originaldoc/opc:TypeDictionary/opc:StructuredType[@Name=$browseName]">
                 <xsl:choose>
                     <xsl:when test="not(Definition) and not(@BrowseName = 'Duration') and not(number(substring(@BrowseName,1,1))) and not(@IsAbstract) and number(substring(@NodeId,3)) &gt; 29">
-                    ['<xsl:value-of select="number(substring(@NodeId,3)) + 2"/><xsl:text>' </xsl:text><xsl:value-of select='@BrowseName'/><xsl:text>
+    ['<xsl:value-of select="number(substring(@NodeId,3)) + 2"/><xsl:text>' </xsl:text><xsl:value-of select='@BrowseName'/><xsl:text>
                 </xsl:text>
-                        <xsl:apply-templates select="/opc:TypeDictionary/opc:StructuredType[@Name=$browseName]"/>
-                        ]
+                        <xsl:apply-templates select="$originaldoc/opc:TypeDictionary/opc:StructuredType[@Name=$browseName]"/>]
                     </xsl:when>
                 </xsl:choose>
             </xsl:when>
@@ -503,7 +511,7 @@
             <xsl:when test="@LengthField">[array <xsl:value-of select="$dataType"/>  '<xsl:value-of select="$lowerCaseName"/>' count '<xsl:value-of select="$lowerCaseLengthField"/>']
             </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>
 
@@ -556,4 +564,26 @@
         </xsl:choose>
     </xsl:template>
 
+    <xsl:template name="statusCodeParsing" >
+        <xsl:variable name="tokenizedLine" select="tokenize($statusCodeFile, '\r\n|\r|\n')" />
+[enum int 32 'OpcuaStatusCodes'
+<xsl:for-each select="$tokenizedLine">
+    <xsl:variable select="tokenize(., ',')" name="values" />    ['<xsl:value-of select="$values[2]"/>'  <xsl:value-of select="$values[1]"/>]
+</xsl:for-each>
+]
+</xsl:template>
+
+    <xsl:template name="servicesEnumParsing" >
+        <xsl:variable name="tokenizedLine" select="tokenize($servicesEnumFile, '\r\n|\r|\n')" />
+[enum int 32 'OpcuaNodeIdServices'
+        <xsl:for-each select="$tokenizedLine">
+            <xsl:variable select="tokenize(., ',')" name="values" />
+            <xsl:choose>
+                <xsl:when test="$values[2]">['<xsl:value-of select="$values[2]"/>'  <xsl:value-of select="$values[1]"/>]
+    </xsl:when>
+            </xsl:choose>
+        </xsl:for-each>
+]
+    </xsl:template>
+
 </xsl:stylesheet>