add tools from distri, assign data sources
This commit is contained in:
parent
7586087ecc
commit
607f7af7f8
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
||||
*~
|
||||
*.o
|
||||
|
24
Makefile
24
Makefile
@ -1,21 +1,29 @@
|
||||
CC = gcc
|
||||
CFLAGS = -std=c99 -I ./ -I ./include -DUA_NO_AMALGAMATION # put pre-processor settings (-I, -D, etc) here
|
||||
LDFLAGS = # put linker settings here
|
||||
LIBS = ./lib/libopen62541-static.a
|
||||
|
||||
.PHONY: all
|
||||
all: myServer server_method server_folders myTestModelServer
|
||||
|
||||
myServer: myServer.o ./lib/libopen62541-static.a
|
||||
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^
|
||||
myServer: myServer.o
|
||||
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^ $(LIBS)
|
||||
|
||||
server_method: server_method.o ./lib/libopen62541-static.a
|
||||
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^
|
||||
server_method: server_method.o
|
||||
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^ $(LIBS)
|
||||
|
||||
server_folders: server_folders.o ./lib/libopen62541-static.a
|
||||
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^
|
||||
server_folders: server_folders.o
|
||||
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^ $(LIBS)
|
||||
|
||||
myTestModelServer: myTestModelServer.o TestModel.o ./lib/libopen62541-static.a
|
||||
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^
|
||||
TestModel.c: testmodel.xml
|
||||
./tools/pyUANamespace/generate_open62541CCode.py tools/schema/namespace0/Opc.Ua.NodeSet2.xml $^ TestModel
|
||||
|
||||
TestModel.h: TestModel.c
|
||||
|
||||
myTestModelServer.o: myTestModelServer.c TestModel.h
|
||||
|
||||
myTestModelServer: myTestModelServer.o TestModel.o
|
||||
$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^ $(LIBS)
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
84
TestModel.c
84
TestModel.c
@ -30456,6 +30456,47 @@ UA_Server_addObjectNode(server, nodeId, parentNodeId, parentReferenceNodeId, nod
|
||||
UA_Server_addReference(server, UA_NODEID_NUMERIC(2, 5001), UA_NODEID_NUMERIC(0, 40), UA_EXPANDEDNODEID_NUMERIC(0, 58), true);
|
||||
} while(0);
|
||||
|
||||
do {
|
||||
// Referencing node found and declared as parent: ns=2;i=1002/1:TemperatureSensorType using i=47/HasComponent
|
||||
// Node: opcua_node_object_t(ns=2;i=5006), 1:DeviceData
|
||||
UA_ObjectAttributes attr;
|
||||
UA_ObjectAttributes_init(&attr);
|
||||
attr.displayName = UA_LOCALIZEDTEXT("", "DeviceData");
|
||||
attr.description = UA_LOCALIZEDTEXT("", "");
|
||||
UA_NodeId nodeId = UA_NODEID_NUMERIC(2, 5006);
|
||||
UA_NodeId typeDefinition = UA_NODEID_NULL;
|
||||
UA_NodeId parentNodeId = UA_NODEID_NUMERIC(2, 1002);
|
||||
UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, 47);
|
||||
UA_QualifiedName nodeName = UA_QUALIFIEDNAME(1, "DeviceData");
|
||||
UA_Server_addObjectNode(server, nodeId, parentNodeId, parentReferenceNodeId, nodeName
|
||||
, typeDefinition
|
||||
, attr, NULL, NULL);
|
||||
// This node has the following references that can be created:
|
||||
UA_Server_addReference(server, UA_NODEID_NUMERIC(2, 5006), UA_NODEID_NUMERIC(0, 40), UA_EXPANDEDNODEID_NUMERIC(0, 58), true);
|
||||
} while(0);
|
||||
|
||||
do {
|
||||
// Referencing node found and declared as parent: ns=2;i=5006/1:DeviceData using i=47/HasComponent
|
||||
// Node: opcua_node_variable_t(ns=2;i=6005), 1:UpTime
|
||||
UA_VariableAttributes attr;
|
||||
UA_VariableAttributes_init(&attr);
|
||||
attr.displayName = UA_LOCALIZEDTEXT("", "UpTime");
|
||||
attr.description = UA_LOCALIZEDTEXT("", "");
|
||||
UA_UInt32 opcua_node_variable_t_ns_2_i_6005_variant_DataContents = (UA_UInt32) 0;
|
||||
UA_Variant_setScalar( &attr.value, &opcua_node_variable_t_ns_2_i_6005_variant_DataContents, &UA_TYPES[UA_TYPES_UINT32]);
|
||||
UA_UInt32_deleteMembers(&opcua_node_variable_t_ns_2_i_6005_variant_DataContents);
|
||||
UA_NodeId nodeId = UA_NODEID_NUMERIC(2, 6005);
|
||||
UA_NodeId typeDefinition = UA_NODEID_NULL;
|
||||
UA_NodeId parentNodeId = UA_NODEID_NUMERIC(2, 5006);
|
||||
UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, 47);
|
||||
UA_QualifiedName nodeName = UA_QUALIFIEDNAME(1, "UpTime");
|
||||
UA_Server_addVariableNode(server, nodeId, parentNodeId, parentReferenceNodeId, nodeName
|
||||
, typeDefinition
|
||||
, attr, NULL, NULL);
|
||||
// This node has the following references that can be created:
|
||||
UA_Server_addReference(server, UA_NODEID_NUMERIC(2, 6005), UA_NODEID_NUMERIC(0, 40), UA_EXPANDEDNODEID_NUMERIC(0, 63), true);
|
||||
} while(0);
|
||||
|
||||
do {
|
||||
// Referencing node found and declared as parent: ns=2;i=1002/1:TemperatureSensorType using i=47/HasComponent
|
||||
// Node: opcua_node_object_t(ns=2;i=5002), 1:Measurement
|
||||
@ -31222,6 +31263,8 @@ UA_Server_addReference(server, UA_NODEID_NUMERIC(0, 7612), UA_NODEID_NUMERIC(0,
|
||||
UA_Server_addReference(server, UA_NODEID_NUMERIC(0, 12078), UA_NODEID_NUMERIC(0, 37), UA_EXPANDEDNODEID_NUMERIC(0, 78), true);
|
||||
UA_Server_addReference(server, UA_NODEID_NUMERIC(0, 7614), UA_NODEID_NUMERIC(0, 37), UA_EXPANDEDNODEID_NUMERIC(0, 78), true);
|
||||
UA_Server_addReference(server, UA_NODEID_NUMERIC(2, 5001), UA_NODEID_NUMERIC(0, 37), UA_EXPANDEDNODEID_NUMERIC(0, 78), true);
|
||||
UA_Server_addReference(server, UA_NODEID_NUMERIC(2, 5006), UA_NODEID_NUMERIC(0, 37), UA_EXPANDEDNODEID_NUMERIC(0, 78), true);
|
||||
UA_Server_addReference(server, UA_NODEID_NUMERIC(2, 6005), UA_NODEID_NUMERIC(0, 37), UA_EXPANDEDNODEID_NUMERIC(0, 78), true);
|
||||
UA_Server_addReference(server, UA_NODEID_NUMERIC(2, 5002), UA_NODEID_NUMERIC(0, 37), UA_EXPANDEDNODEID_NUMERIC(0, 78), true);
|
||||
UA_Server_addReference(server, UA_NODEID_NUMERIC(2, 6002), UA_NODEID_NUMERIC(0, 37), UA_EXPANDEDNODEID_NUMERIC(0, 78), true);
|
||||
UA_Server_addReference(server, UA_NODEID_NUMERIC(2, 6001), UA_NODEID_NUMERIC(0, 37), UA_EXPANDEDNODEID_NUMERIC(0, 78), true);
|
||||
@ -31287,6 +31330,47 @@ UA_Server_addObjectNode(server, nodeId, parentNodeId, parentReferenceNodeId, nod
|
||||
UA_Server_addReference(server, UA_NODEID_NUMERIC(2, 5003), UA_NODEID_NUMERIC(0, 40), UA_EXPANDEDNODEID_NUMERIC(0, 58), true);
|
||||
} while(0);
|
||||
|
||||
do {
|
||||
// Referencing node found and declared as parent: ns=2;i=5004/1:TemperatureSensor using i=47/HasComponent
|
||||
// Node: opcua_node_object_t(ns=2;i=5007), 1:DeviceData
|
||||
UA_ObjectAttributes attr;
|
||||
UA_ObjectAttributes_init(&attr);
|
||||
attr.displayName = UA_LOCALIZEDTEXT("", "DeviceData");
|
||||
attr.description = UA_LOCALIZEDTEXT("", "");
|
||||
UA_NodeId nodeId = UA_NODEID_NUMERIC(2, 5007);
|
||||
UA_NodeId typeDefinition = UA_NODEID_NULL;
|
||||
UA_NodeId parentNodeId = UA_NODEID_NUMERIC(2, 5004);
|
||||
UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, 47);
|
||||
UA_QualifiedName nodeName = UA_QUALIFIEDNAME(1, "DeviceData");
|
||||
UA_Server_addObjectNode(server, nodeId, parentNodeId, parentReferenceNodeId, nodeName
|
||||
, typeDefinition
|
||||
, attr, NULL, NULL);
|
||||
// This node has the following references that can be created:
|
||||
UA_Server_addReference(server, UA_NODEID_NUMERIC(2, 5007), UA_NODEID_NUMERIC(0, 40), UA_EXPANDEDNODEID_NUMERIC(0, 58), true);
|
||||
} while(0);
|
||||
|
||||
do {
|
||||
// Referencing node found and declared as parent: ns=2;i=5007/1:DeviceData using i=47/HasComponent
|
||||
// Node: opcua_node_variable_t(ns=2;i=6006), 1:UpTime
|
||||
UA_VariableAttributes attr;
|
||||
UA_VariableAttributes_init(&attr);
|
||||
attr.displayName = UA_LOCALIZEDTEXT("", "UpTime");
|
||||
attr.description = UA_LOCALIZEDTEXT("", "");
|
||||
UA_UInt32 opcua_node_variable_t_ns_2_i_6006_variant_DataContents = (UA_UInt32) 0;
|
||||
UA_Variant_setScalar( &attr.value, &opcua_node_variable_t_ns_2_i_6006_variant_DataContents, &UA_TYPES[UA_TYPES_UINT32]);
|
||||
UA_UInt32_deleteMembers(&opcua_node_variable_t_ns_2_i_6006_variant_DataContents);
|
||||
UA_NodeId nodeId = UA_NODEID_NUMERIC(2, 6006);
|
||||
UA_NodeId typeDefinition = UA_NODEID_NULL;
|
||||
UA_NodeId parentNodeId = UA_NODEID_NUMERIC(2, 5007);
|
||||
UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, 47);
|
||||
UA_QualifiedName nodeName = UA_QUALIFIEDNAME(1, "UpTime");
|
||||
UA_Server_addVariableNode(server, nodeId, parentNodeId, parentReferenceNodeId, nodeName
|
||||
, typeDefinition
|
||||
, attr, NULL, NULL);
|
||||
// This node has the following references that can be created:
|
||||
UA_Server_addReference(server, UA_NODEID_NUMERIC(2, 6006), UA_NODEID_NUMERIC(0, 40), UA_EXPANDEDNODEID_NUMERIC(0, 63), true);
|
||||
} while(0);
|
||||
|
||||
do {
|
||||
// Referencing node found and declared as parent: ns=2;i=5004/1:TemperatureSensor using i=47/HasComponent
|
||||
// Node: opcua_node_object_t(ns=2;i=5005), 1:Measurement
|
||||
|
@ -5,6 +5,8 @@
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include <ua_types.h>
|
||||
#include <ua_server.h>
|
||||
@ -18,11 +20,36 @@
|
||||
UA_Logger logger = Logger_Stdout;
|
||||
UA_Boolean running = true;
|
||||
|
||||
|
||||
/*
|
||||
* shared data
|
||||
*/
|
||||
uint32_t upTime = 0;
|
||||
double measuredTemperature = 0;
|
||||
|
||||
static void stopHandler(int sign) {
|
||||
UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER, "received ctrl-c");
|
||||
running = false;
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
readInteger(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
|
||||
const UA_NumericRange *range, UA_DataValue *dataValue) {
|
||||
dataValue->hasValue = true;
|
||||
UA_Variant_setScalarCopy(&dataValue->value, handle, &UA_TYPES[UA_TYPES_INT32]);
|
||||
return UA_STATUSCODE_GOOD;
|
||||
}
|
||||
|
||||
static UA_StatusCode
|
||||
readDouble(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
|
||||
const UA_NumericRange *range, UA_DataValue *dataValue) {
|
||||
dataValue->hasValue = true;
|
||||
UA_Variant_setScalarCopy(&dataValue->value, handle, &UA_TYPES[UA_TYPES_DOUBLE]);
|
||||
return UA_STATUSCODE_GOOD;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
signal(SIGINT, stopHandler); /* catches ctrl-c */
|
||||
|
||||
@ -36,11 +63,42 @@ int main(int argc, char** argv) {
|
||||
/* create nodes from nodeset */
|
||||
TestModel(server);
|
||||
|
||||
/* start server */
|
||||
UA_DataSource uptimeDataSource = (UA_DataSource) {
|
||||
.handle = &upTime, .read = readInteger, .write = 0};
|
||||
UA_Server_setVariableNode_dataSource(server, UA_NODEID_NUMERIC(2, 6006),
|
||||
uptimeDataSource);
|
||||
|
||||
|
||||
UA_DataSource measuredTemperatureDataSource = (UA_DataSource) {
|
||||
.handle = &measuredTemperature, .read = readDouble, .write = 0};
|
||||
UA_Server_setVariableNode_dataSource(server, UA_NODEID_NUMERIC(2, 6004),
|
||||
measuredTemperatureDataSource);
|
||||
|
||||
/*
|
||||
UA_StatusCode retval = UA_Server_run(server, &running); //UA_blocks until running=false
|
||||
*/
|
||||
|
||||
|
||||
UA_StatusCode retval = UA_Server_run_startup(server);
|
||||
if (retval == UA_STATUSCODE_GOOD) {
|
||||
|
||||
while (running == true) {
|
||||
upTime = time(0);
|
||||
measuredTemperature += 0.25;
|
||||
|
||||
uint16_t canWait = 0;
|
||||
|
||||
canWait = UA_Server_run_iterate(server, 0);
|
||||
// UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "canWait: %i", canWait);
|
||||
|
||||
struct timeval timeout = { .tv_sec = 0, .tv_usec = canWait * 1000 };
|
||||
select(0, 0, 0, 0, &timeout);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ctrl-c received -> clean up */
|
||||
UA_Server_delete(server);
|
||||
nl.deleteMembers(&nl);
|
||||
return (int)retval;
|
||||
// return (int)retval;
|
||||
}
|
||||
|
0
testmodel.tt2pro
Normal file → Executable file
0
testmodel.tt2pro
Normal file → Executable file
BIN
testmodel.ua
Normal file → Executable file
BIN
testmodel.ua
Normal file → Executable file
Binary file not shown.
43
testmodel.xml
Normal file → Executable file
43
testmodel.xml
Normal file → Executable file
@ -3,6 +3,7 @@
|
||||
<Uri>http://krohnegroup.com/TestModel/</Uri>
|
||||
</NamespaceUris>
|
||||
<Aliases>
|
||||
<Alias Alias="UInt32">i=7</Alias>
|
||||
<Alias Alias="Double">i=11</Alias>
|
||||
<Alias Alias="String">i=12</Alias>
|
||||
<Alias Alias="Organizes">i=35</Alias>
|
||||
@ -14,13 +15,14 @@
|
||||
</Aliases>
|
||||
<Extensions>
|
||||
<Extension>
|
||||
<ModelInfo Tool="UaModeler" Hash="ngSlXA/wXFdk+KET7IyQOQ==" Version="1.4.3"/>
|
||||
<ModelInfo Tool="UaModeler" Hash="2VjgZydlSX7P08Hasg03fQ==" Version="1.4.3"/>
|
||||
</Extension>
|
||||
</Extensions>
|
||||
<UAObjectType NodeId="ns=1;i=1002" BrowseName="1:TemperatureSensorType">
|
||||
<DisplayName>TemperatureSensorType</DisplayName>
|
||||
<References>
|
||||
<Reference ReferenceType="HasComponent">ns=1;i=5001</Reference>
|
||||
<Reference ReferenceType="HasComponent">ns=1;i=5006</Reference>
|
||||
<Reference ReferenceType="HasComponent">ns=1;i=5002</Reference>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=58</Reference>
|
||||
</References>
|
||||
@ -43,6 +45,26 @@
|
||||
<Reference ReferenceType="HasProperty" IsForward="false">ns=1;i=6002</Reference>
|
||||
</References>
|
||||
</UAVariable>
|
||||
<UAObject ParentNodeId="ns=1;i=1002" NodeId="ns=1;i=5006" BrowseName="1:DeviceData">
|
||||
<DisplayName>DeviceData</DisplayName>
|
||||
<References>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=58</Reference>
|
||||
<Reference ReferenceType="HasComponent" IsForward="false">ns=1;i=1002</Reference>
|
||||
<Reference ReferenceType="HasModellingRule">i=78</Reference>
|
||||
<Reference ReferenceType="HasComponent">ns=1;i=6005</Reference>
|
||||
</References>
|
||||
</UAObject>
|
||||
<UAVariable DataType="UInt32" ParentNodeId="ns=1;i=5006" NodeId="ns=1;i=6005" BrowseName="1:UpTime" UserAccessLevel="3" AccessLevel="3">
|
||||
<DisplayName>UpTime</DisplayName>
|
||||
<References>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=63</Reference>
|
||||
<Reference ReferenceType="HasModellingRule">i=78</Reference>
|
||||
<Reference ReferenceType="HasComponent" IsForward="false">ns=1;i=5006</Reference>
|
||||
</References>
|
||||
<Value>
|
||||
<uax:UInt32>0</uax:UInt32>
|
||||
</Value>
|
||||
</UAVariable>
|
||||
<UAObject ParentNodeId="ns=1;i=1002" NodeId="ns=1;i=5002" BrowseName="1:Measurement">
|
||||
<DisplayName>Measurement</DisplayName>
|
||||
<References>
|
||||
@ -68,6 +90,7 @@
|
||||
<DisplayName>TemperatureSensor</DisplayName>
|
||||
<References>
|
||||
<Reference ReferenceType="HasComponent">ns=1;i=5003</Reference>
|
||||
<Reference ReferenceType="HasComponent">ns=1;i=5007</Reference>
|
||||
<Reference ReferenceType="HasComponent">ns=1;i=5005</Reference>
|
||||
<Reference ReferenceType="Organizes" IsForward="false">i=85</Reference>
|
||||
<Reference ReferenceType="HasTypeDefinition">ns=1;i=1002</Reference>
|
||||
@ -89,6 +112,24 @@
|
||||
<Reference ReferenceType="HasProperty" IsForward="false">ns=1;i=6004</Reference>
|
||||
</References>
|
||||
</UAVariable>
|
||||
<UAObject ParentNodeId="ns=1;i=5004" NodeId="ns=1;i=5007" BrowseName="1:DeviceData">
|
||||
<DisplayName>DeviceData</DisplayName>
|
||||
<References>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=58</Reference>
|
||||
<Reference ReferenceType="HasComponent" IsForward="false">ns=1;i=5004</Reference>
|
||||
<Reference ReferenceType="HasComponent">ns=1;i=6006</Reference>
|
||||
</References>
|
||||
</UAObject>
|
||||
<UAVariable DataType="UInt32" ParentNodeId="ns=1;i=5007" NodeId="ns=1;i=6006" BrowseName="1:UpTime" UserAccessLevel="3" AccessLevel="3">
|
||||
<DisplayName>UpTime</DisplayName>
|
||||
<References>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=63</Reference>
|
||||
<Reference ReferenceType="HasComponent" IsForward="false">ns=1;i=5007</Reference>
|
||||
</References>
|
||||
<Value>
|
||||
<uax:UInt32>0</uax:UInt32>
|
||||
</Value>
|
||||
</UAVariable>
|
||||
<UAObject ParentNodeId="ns=1;i=5004" NodeId="ns=1;i=5005" BrowseName="1:Measurement">
|
||||
<DisplayName>Measurement</DisplayName>
|
||||
<References>
|
||||
|
29
tools/pyUANamespace/NodeID_AssumeExternal.txt
Normal file
29
tools/pyUANamespace/NodeID_AssumeExternal.txt
Normal file
@ -0,0 +1,29 @@
|
||||
i=2253
|
||||
i=2254
|
||||
i=2255
|
||||
i=2256
|
||||
i=2257
|
||||
i=2258
|
||||
i=2259
|
||||
i=2260
|
||||
i=2261
|
||||
i=2262
|
||||
i=2263
|
||||
i=2264
|
||||
i=2265
|
||||
i=2266
|
||||
i=2267
|
||||
i=2271
|
||||
i=2274
|
||||
i=2292
|
||||
i=2294
|
||||
i=2735
|
||||
i=2992
|
||||
i=2993
|
||||
i=2994
|
||||
i=2268
|
||||
i=274
|
||||
i=295
|
||||
i=296
|
||||
i=11715
|
||||
i=11492
|
0
tools/pyUANamespace/NodeID_Blacklist.txt
Normal file
0
tools/pyUANamespace/NodeID_Blacklist.txt
Normal file
1514
tools/pyUANamespace/NodeID_Blacklist_FullNS0.txt
Normal file
1514
tools/pyUANamespace/NodeID_Blacklist_FullNS0.txt
Normal file
File diff suppressed because it is too large
Load Diff
150
tools/pyUANamespace/README.md
Normal file
150
tools/pyUANamespace/README.md
Normal file
@ -0,0 +1,150 @@
|
||||
pyUANamespace
|
||||
=============
|
||||
|
||||
pyUANamespace is a collection of python 2 scripts that can parse OPC UA XML Namespace definition files and transform them into a class representation. This facilitates both reprinting the namespace in a different non-XML format (such as C-Code or DOT) and analysis of the namespace structure.
|
||||
|
||||
|
||||
|
||||
### Documentation
|
||||
|
||||
The pyUANamespace implementation has been contributed by a research project of the chair for Process Control Systems Engineering of the TU Dresden. It was not strictly speaking created as a C generator, but could be easily modified to fullfill this role for open62541.
|
||||
|
||||
## Functionality in open62541
|
||||
|
||||
In open62541, the linked python namespace generated by the pyUANamespace classes are used to print C-Code that will automatically initialize a server. Apart from parsing XML, most classes also have a printOpen62541Header() or printOpen62541Header_Subtype() function that can reprint the node as C Code compatible with the project.
|
||||
|
||||
This function has been wrapped into the generate_open62541CCode.py program, which implements the compiler and option checking relevant to this task. The program is called as follows:
|
||||
|
||||
```bash
|
||||
$ python generate_open62541CCode.py /path/to/NodeSet.xml /path/to/outputfile.c
|
||||
```
|
||||
|
||||
Several options have been made available to further facilitate header generation. Calling the script without arguments will produce a usage helper listing all available options.
|
||||
|
||||
# Overwriting NodeSet definitions
|
||||
|
||||
Most notably, any number of XML files can be passed. The latest XML definition of a node found is used.
|
||||
|
||||
```bash
|
||||
$ python generate_open62541CCode.py /path/to/NodeSet0.xml /path/to/OverwriteNodeSet0.xml /path/to/outputfile.c
|
||||
```
|
||||
|
||||
# Blacklisting Nodes
|
||||
|
||||
If a set of nodes is not to be contained in the namespace, they can be specified as a blacklist file containing one nodeId per line in the following format:
|
||||
|
||||
```
|
||||
ns=1;id=2323
|
||||
id=11122;
|
||||
```
|
||||
|
||||
This file can be passed to the compiler, which will remove these nodes prior to linking the namespace.
|
||||
|
||||
```bash
|
||||
$ python generate_open62541CCode.py -b blacklist.txt /path/to/NodeSet.xml /path/to/outputfile.c
|
||||
```
|
||||
|
||||
In this particular example, nodes `ns=1;id=2323` and `ns=0;id=11122` will be removed from the namespace (which may invalidate other nodes referring to them).
|
||||
|
||||
# Ignoring Nodes
|
||||
|
||||
Blacklisting removes nodes, which means that any other nodes referring to these nodes will contain invalid references. If a namespace should be generated that can use all datatypes, objectstypes, etc., but should only print specific nodes into the C Header, a set of nodes can be ignored. This will cause the compiler to use them in the linked namespace where other nodes can use them (e.g. in buildEncodingRules()), but they will not appear as part of the header file.
|
||||
|
||||
Ignorelists have the same format as blacklists and are passed to the compiler like so:.
|
||||
|
||||
```bash
|
||||
$ python generate_open62541CCode.py -i ignorelist.txt /path/to/NodeSet.xml /path/to/outputfile.c
|
||||
```
|
||||
|
||||
Given the blacklist example, the nodes `ns=1;id=2323` and `ns=0;id=11122` will not be part of the header, but other nodes may attempt to create references to them or use them as dataTypes.
|
||||
|
||||
# Supressing attributes
|
||||
|
||||
Most of OPC UA Namespaces depend heavily on strings. These can bloat up memory usage in applications where memory is a critical resource. The compiler can be instructed to suppress allocation for certain attributes, which will be initialized to sensible defaults or NULL pointers where applicable.
|
||||
|
||||
```bash
|
||||
$ python generate_open62541CCode.py -s browsename -s displayname -s nodeid /path/to/NodeSet.xml /path/to/outputfile.c
|
||||
```
|
||||
|
||||
Currently, the following base attributes of nodes can be suppressed:
|
||||
- browseName
|
||||
- displayName
|
||||
- description
|
||||
- nodeId
|
||||
- writeMask
|
||||
- userWriteMask
|
||||
|
||||
Further attributes may be added at a later point depending on demand.
|
||||
|
||||
## Core functionality
|
||||
|
||||
OPC UA node types, base data types and references are described in ua_node_types.py and ua_builtin_types.py. These classes are primarily intended to act as part of an AST to parse OPC UA Namespace description files. They implement a hierarchic/rekursive parsing of XML DOM objects, supplementing their respective properties from the XML description.
|
||||
|
||||
A manager class called ua_namespace is included in the respective source file. This class does _not_ correspond to a OPC UA Namespace. It is an aggregator and manager for nodes and references which may belong to any number of namespaces. This class includes extensive parsing/validation to ensure that a complete and consistent namespace is generated.
|
||||
|
||||
## Namespace compilation internals
|
||||
|
||||
Compiling a namespace consists of the following steps:
|
||||
- Read one or more XML definitions
|
||||
- Link references to actual nodes (also includes references to dataTypes, etc.)
|
||||
- Sanitize/Remove any nodes and references that could not be properly parsed
|
||||
- Derive encoding rules for datatypes
|
||||
- Parse/Allocate variable values according to their dataType definitions
|
||||
|
||||
|
||||
Reading and parsing XML files is handled by ua_namespace.parseXML(/path/to/file.xml). It is the first part of a multipass compiler that will create all nodes contained in the XML description.
|
||||
|
||||
During the reading of XML files, nodes will attempt to parse any attributes they own, but not refer to any other nodes. References will be kept as XML descriptions. Any number of XML files can be read in this phase. __NOTE__: In the open62541 (this) implementation, duplicate nodes (same NodeId) are allowed. The last definition encountered will be kept. This allows overwriting specific nodes of a much larger XML file to with implementation specific nodes.
|
||||
|
||||
The next phase of the compilation is to link all references. The phase is called by ua_namespace.linkOpenPointers(). All references will attempt to locate their target() node in the namespace and point to it.
|
||||
|
||||
During the sanitation phase called by ua_namespace.sanitize(), nodes check themselves for invalid attributes. Most notably any references that could not be resolved to a node will be removed from the nodes.
|
||||
|
||||
When calling ua_namespace.buildEncodingRules(), dataType nodes are examined to determine if and how the can be encoded as a serialization of OPC UA builtin types as well as their aliases.
|
||||
|
||||
The following fragment of a variable value can illustrate the necessity for determining encoding rules:
|
||||
```xml
|
||||
<Argument>
|
||||
<Name>ServerHandles</Name>
|
||||
<DataType>
|
||||
<Identifier>i=7</Identifier>
|
||||
</DataType>
|
||||
<ValueRank>1</ValueRank>
|
||||
<ArrayDimensions />
|
||||
<Description p5:nil="true" xmlns:p5="http://www.w3.org/2001/XMLSchema-instance" />
|
||||
</Argument>
|
||||
```
|
||||
The tags body, TypeId, Identifier, and Argument are aliases for builtin encodings or structures thereof. Without knowing which type they represent, an appropriate value class (and with that a parser) cannot be created. pyUANamespace will resolve this specific case by determining the encoding as follows:
|
||||
```
|
||||
LastMethodOutputArguments : Argument -> i=296
|
||||
+ [['Name', ['String']], ['DataType', ['NodeId']], ['ValueRank', ['Int32']], ['ArrayDimensions', ['UInt32']], ['Description', ['LocalizedText']]] (already analyzed)
|
||||
|
||||
```
|
||||
|
||||
DataTypes that cannot be encoded as a definite serial object (e.g. by having a member of NumericType, but not a specific one), will have their isEncodable() attribute disabled. All dataTypes that complete this node can be used to effectively determine the size and serialization properties of any variables.
|
||||
|
||||
Having encoding rules means that data can now be parsed when a <Value> tag is encountered in a description. Calling ua_namespace.allocateVariables() will do just that for any variable node that holds XML Values.
|
||||
|
||||
The result of this compilation is a completely linked and instantiated OPC UA namespace.
|
||||
|
||||
An example compiler can be built as follows:
|
||||
```python
|
||||
class testing:
|
||||
def __init__(self):
|
||||
self.namespace = opcua_namespace("testing")
|
||||
|
||||
log(self, "Phase 1: Reading XML file nodessets")
|
||||
self.namespace.parseXML("Opc.Ua.NodeSet2.xml")
|
||||
self.namespace.parseXML("DeviceNodesSet.xml")
|
||||
self.namespace.parseXML("MyNodesSet.xml")
|
||||
|
||||
log(self, "Phase 2: Linking address space references and datatypes")
|
||||
self.namespace.linkOpenPointers()
|
||||
self.namespace.sanitize()
|
||||
|
||||
log(self, "Phase 3: Comprehending DataType encoding rules")
|
||||
self.namespace.buildEncodingRules()
|
||||
|
||||
log(self, "Phase 4: Allocating variable value data")
|
||||
self.namespace.allocateVariables()
|
||||
```
|
203
tools/pyUANamespace/generate_open62541CCode.py
Executable file
203
tools/pyUANamespace/generate_open62541CCode.py
Executable file
@ -0,0 +1,203 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
###
|
||||
### Author: Chris Iatrou (ichrispa@core-vector.net)
|
||||
### Version: rev 13
|
||||
###
|
||||
### This program was created for educational purposes and has been
|
||||
### contributed to the open62541 project by the author. All licensing
|
||||
### terms for this source is inherited by the terms and conditions
|
||||
### specified for by the open62541 project (see the projects readme
|
||||
### file for more information on the LGPL terms and restrictions).
|
||||
###
|
||||
### This program is not meant to be used in a production environment. The
|
||||
### author is not liable for any complications arising due to the use of
|
||||
### this program.
|
||||
###
|
||||
|
||||
from __future__ import print_function
|
||||
from sys import argv, exit
|
||||
from os import path
|
||||
from ua_namespace import *
|
||||
from logger import *
|
||||
from open62541_XMLPreprocessor import open62541_XMLPreprocessor
|
||||
|
||||
def usage():
|
||||
print("Script usage:")
|
||||
print("generate_open62541CCode [-i <ignorefile> | -b <blacklistfile>] <namespace XML> [namespace.xml[ namespace.xml[...]]] <output file>\n")
|
||||
print("generate_open62541CCode will first read all XML files passed on the command line, then ")
|
||||
print("link and check the namespace. All nodes that fullfill the basic requirements will then be")
|
||||
print("printed as C-Code intended to be included in the open62541 OPC-UA Server that will")
|
||||
print("initialize the corresponding name space.\n")
|
||||
print("Manditory Arguments:")
|
||||
print("<namespace XML> At least one Namespace XML file must be passed.")
|
||||
print("<output file> The basename for the <output file>.c and <output file>.h files to be generated.")
|
||||
print(" This will also be the function name used in the header and c-file.\n\n")
|
||||
print("Additional Arguments:")
|
||||
print(""" -i <ignoreFile> Loads a list of NodeIDs stored in ignoreFile (one NodeID per line)
|
||||
The compiler will assume that these Nodes have been created externally
|
||||
and not generate any code for them. They will however be linked to
|
||||
from other nodes.""")
|
||||
print(""" -b <blacklistFile> Loads a list of NodeIDs stored in blacklistFile (one NodeID per line)
|
||||
Any of the nodeIds encountered in this file will be removed from the namespace
|
||||
prior to compilation. Any references to these nodes will also be removed""")
|
||||
print(""" -s <attribute> Suppresses the generation of some node attributes. Currently supported
|
||||
options are 'description', 'browseName', 'displayName', 'writeMask', 'userWriteMask'
|
||||
and 'nodeid'.""")
|
||||
print(""" namespaceXML Any number of namespace descriptions in XML format. Note that the
|
||||
last description of a node encountered will be used and all prior definitions
|
||||
are discarded.""")
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Check if the parameters given correspond to actual files
|
||||
infiles = []
|
||||
ouffile = ""
|
||||
ignoreFiles = []
|
||||
blacklistFiles = []
|
||||
supressGenerationOfAttribute=[]
|
||||
|
||||
GLOBAL_LOG_LEVEL = LOG_LEVEL_DEBUG
|
||||
|
||||
arg_isIgnore = False
|
||||
arg_isBlacklist = False
|
||||
arg_isSupress = False
|
||||
if len(argv) < 2:
|
||||
usage()
|
||||
exit(1)
|
||||
for filename in argv[1:-1]:
|
||||
if arg_isIgnore:
|
||||
arg_isIgnore = False
|
||||
if path.exists(filename):
|
||||
ignoreFiles.append(filename)
|
||||
else:
|
||||
log(None, "File " + str(filename) + " does not exist.", LOG_LEVEL_ERROR)
|
||||
usage()
|
||||
exit(1)
|
||||
elif arg_isBlacklist:
|
||||
arg_isBlacklist = False
|
||||
if path.exists(filename):
|
||||
blacklistFiles.append(filename)
|
||||
else:
|
||||
log(None, "File " + str(filename) + " does not exist.", LOG_LEVEL_ERROR)
|
||||
usage()
|
||||
exit(1)
|
||||
elif arg_isSupress:
|
||||
arg_isSupress = False
|
||||
supressGenerationOfAttribute.append(filename.lower())
|
||||
else:
|
||||
if path.exists(filename):
|
||||
infiles.append(filename)
|
||||
elif filename.lower() == "-i" or filename.lower() == "--ignore" :
|
||||
arg_isIgnore = True
|
||||
elif filename.lower() == "-b" or filename.lower() == "--blacklist" :
|
||||
arg_isBlacklist = True
|
||||
elif filename.lower() == "-s" or filename.lower() == "--suppress" :
|
||||
arg_isSupress = True
|
||||
else:
|
||||
log(None, "File " + str(filename) + " does not exist.", LOG_LEVEL_ERROR)
|
||||
usage()
|
||||
exit(1)
|
||||
|
||||
# Creating the header is tendious. We can skip the entire process if
|
||||
# the header exists.
|
||||
#if path.exists(argv[-1]+".c") or path.exists(argv[-1]+".h"):
|
||||
# log(None, "File " + str(argv[-1]) + " does already exists.", LOG_LEVEL_INFO)
|
||||
# log(None, "Header generation will be skipped. Delete the header and rerun this script if necessary.", LOG_LEVEL_INFO)
|
||||
# exit(0)
|
||||
|
||||
# Open the output file
|
||||
outfileh = open(argv[-1]+".h", r"w+")
|
||||
outfilec = open(argv[-1]+".c", r"w+")
|
||||
|
||||
# Create a new namespace
|
||||
# Note that the name is actually completely symbolic, it has no other
|
||||
# function but to distinguish this specific class.
|
||||
# A namespace class acts as a container for nodes. The nodes may belong
|
||||
# to any number of different OPC-UA namespaces.
|
||||
ns = opcua_namespace("open62541")
|
||||
|
||||
# Clean up the XML files by removing duplicate namespaces and unwanted prefixes
|
||||
preProc = open62541_XMLPreprocessor()
|
||||
for xmlfile in infiles:
|
||||
log(None, "Preprocessing " + str(xmlfile), LOG_LEVEL_INFO)
|
||||
preProc.addDocument(xmlfile)
|
||||
preProc.preprocessAll()
|
||||
|
||||
for xmlfile in preProc.getPreProcessedFiles():
|
||||
log(None, "Parsing " + str(xmlfile), LOG_LEVEL_INFO)
|
||||
ns.parseXML(xmlfile)
|
||||
|
||||
# We need to notify the open62541 server of the namespaces used to be able to use i.e. ns=3
|
||||
namespaceArrayNames = preProc.getUsedNamespaceArrayNames()
|
||||
for key in namespaceArrayNames:
|
||||
ns.addNamespace(key, namespaceArrayNames[key])
|
||||
|
||||
# Remove any temp files - they are not needed after the AST is created
|
||||
# Removed for debugging
|
||||
preProc.removePreprocessedFiles()
|
||||
|
||||
# Remove blacklisted nodes from the namespace
|
||||
# Doing this now ensures that unlinkable pointers will be cleanly removed
|
||||
# during sanitation.
|
||||
for blacklist in blacklistFiles:
|
||||
bl = open(blacklist, "r")
|
||||
for line in bl.readlines():
|
||||
line = line.replace(" ","")
|
||||
id = line.replace("\n","")
|
||||
if ns.getNodeByIDString(id) == None:
|
||||
log(None, "Can't blacklist node, namespace does currently not contain a node with id " + str(id), LOG_LEVEL_WARN)
|
||||
else:
|
||||
ns.removeNodeById(line)
|
||||
bl.close()
|
||||
|
||||
# Link the references in the namespace
|
||||
log(None, "Linking namespace nodes and references", LOG_LEVEL_INFO)
|
||||
ns.linkOpenPointers()
|
||||
|
||||
# Remove nodes that are not printable or contain parsing errors, such as
|
||||
# unresolvable or no references or invalid NodeIDs
|
||||
ns.sanitize()
|
||||
|
||||
# Parse Datatypes in order to find out what the XML keyed values actually
|
||||
# represent.
|
||||
# Ex. <rpm>123</rpm> is not encodable
|
||||
# only after parsing the datatypes, it is known that
|
||||
# rpm is encoded as a double
|
||||
log(None, "Building datatype encoding rules", LOG_LEVEL_INFO)
|
||||
ns.buildEncodingRules()
|
||||
|
||||
# Allocate/Parse the data values. In order to do this, we must have run
|
||||
# buidEncodingRules.
|
||||
log(None, "Allocating variables", LOG_LEVEL_INFO)
|
||||
ns.allocateVariables()
|
||||
|
||||
# Users may have manually defined some nodes in their code already (such as serverStatus).
|
||||
# To prevent those nodes from being reprinted, we will simply mark them as already
|
||||
# converted to C-Code. That way, they will still be reffered to by other nodes, but
|
||||
# they will not be created themselves.
|
||||
ignoreNodes = []
|
||||
for ignore in ignoreFiles:
|
||||
ig = open(ignore, "r")
|
||||
for line in ig.readlines():
|
||||
line = line.replace(" ","")
|
||||
id = line.replace("\n","")
|
||||
if ns.getNodeByIDString(id) == None:
|
||||
log(None, "Can't ignore node, Namespace does currently not contain a node with id " + str(id), LOG_LEVEL_WARN)
|
||||
else:
|
||||
ignoreNodes.append(ns.getNodeByIDString(id))
|
||||
ig.close()
|
||||
|
||||
# Create the C Code
|
||||
log(None, "Generating Header", LOG_LEVEL_INFO)
|
||||
# Returns a tuple of (["Header","lines"],["Code","lines","generated"])
|
||||
generatedCode=ns.printOpen62541Header(ignoreNodes, supressGenerationOfAttribute, outfilename=path.basename(argv[-1]))
|
||||
for line in generatedCode[0]:
|
||||
outfileh.write(line+"\n")
|
||||
for line in generatedCode[1]:
|
||||
outfilec.write(line+"\n")
|
||||
|
||||
outfilec.close()
|
||||
outfileh.close()
|
||||
|
||||
exit(0)
|
46
tools/pyUANamespace/logger.py
Normal file
46
tools/pyUANamespace/logger.py
Normal file
@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
###
|
||||
### Author: Chris Iatrou (ichrispa@core-vector.net)
|
||||
### Version: rev 13
|
||||
###
|
||||
### This program was created for educational purposes and has been
|
||||
### contributed to the open62541 project by the author. All licensing
|
||||
### terms for this source is inherited by the terms and conditions
|
||||
### specified for by the open62541 project (see the projects readme
|
||||
### file for more information on the LGPL terms and restrictions).
|
||||
###
|
||||
### This program is not meant to be used in a production environment. The
|
||||
### author is not liable for any complications arising due to the use of
|
||||
### this program.
|
||||
###
|
||||
|
||||
from __future__ import print_function
|
||||
import inspect
|
||||
|
||||
###
|
||||
### Tidy logging helpers
|
||||
###
|
||||
|
||||
LOG_LEVEL_DEBUG = 4
|
||||
LOG_LEVEL_INFO = 2
|
||||
LOG_LEVEL_WARN = 1
|
||||
LOG_LEVEL_ERROR = 0
|
||||
LOG_LEVEL_SILENT = -1
|
||||
|
||||
# Change the following to filter logging output
|
||||
GLOBAL_LOG_LEVEL = LOG_LEVEL_SILENT
|
||||
|
||||
def log(callee, logstr, level=LOG_LEVEL_DEBUG):
|
||||
prefixes = { LOG_LEVEL_DEBUG : "DBG: ",
|
||||
LOG_LEVEL_INFO : "INF: ",
|
||||
LOG_LEVEL_WARN : "WRN: ",
|
||||
LOG_LEVEL_ERROR : "ERR: ",
|
||||
LOG_LEVEL_SILENT: ""
|
||||
}
|
||||
if level <= GLOBAL_LOG_LEVEL:
|
||||
if prefixes.has_key(level):
|
||||
print(str(prefixes[level]) + callee.__class__.__name__ + "." + inspect.stack()[1][3] + "(): " + logstr)
|
||||
else:
|
||||
print(callee.__class__.__name__ + "." + inspect.stack()[1][3] + "(): " + logstr)
|
BIN
tools/pyUANamespace/logger.pyc
Normal file
BIN
tools/pyUANamespace/logger.pyc
Normal file
Binary file not shown.
303
tools/pyUANamespace/open62541_MacroHelper.py
Normal file
303
tools/pyUANamespace/open62541_MacroHelper.py
Normal file
@ -0,0 +1,303 @@
|
||||
#!/usr/bin/env/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
###
|
||||
### Author: Chris Iatrou (ichrispa@core-vector.net)
|
||||
### Version: rev 13
|
||||
###
|
||||
### This program was created for educational purposes and has been
|
||||
### contributed to the open62541 project by the author. All licensing
|
||||
### terms for this source is inherited by the terms and conditions
|
||||
### specified for by the open62541 project (see the projects readme
|
||||
### file for more information on the LGPL terms and restrictions).
|
||||
###
|
||||
### This program is not meant to be used in a production environment. The
|
||||
### author is not liable for any complications arising due to the use of
|
||||
### this program.
|
||||
###
|
||||
|
||||
from logger import *
|
||||
from ua_constants import *
|
||||
import string
|
||||
|
||||
__unique_item_id = 0
|
||||
|
||||
defined_typealiases = []
|
||||
|
||||
class open62541_MacroHelper():
|
||||
def __init__(self, supressGenerationOfAttribute=[]):
|
||||
self.supressGenerationOfAttribute = supressGenerationOfAttribute
|
||||
|
||||
def getCreateExpandedNodeIDMacro(self, node):
|
||||
if node.id().i != None:
|
||||
return "UA_EXPANDEDNODEID_NUMERIC(" + str(node.id().ns) + ", " + str(node.id().i) + ")"
|
||||
elif node.id().s != None:
|
||||
return "UA_EXPANDEDNODEID_STRING(" + str(node.id().ns) + ", " + node.id().s + ")"
|
||||
elif node.id().b != None:
|
||||
log(self, "NodeID Generation macro for bytestrings has not been implemented.")
|
||||
return ""
|
||||
elif node.id().g != None:
|
||||
log(self, "NodeID Generation macro for guids has not been implemented.")
|
||||
return ""
|
||||
else:
|
||||
return ""
|
||||
|
||||
def substitutePunctuationCharacters(self, input):
|
||||
''' substitutePunctuationCharacters
|
||||
|
||||
Replace punctuation characters in input. Part of this class because it is used by
|
||||
ua_namespace on occasion.
|
||||
|
||||
returns: C-printable string representation of input
|
||||
'''
|
||||
# No punctuation characters <>!$
|
||||
illegal_chars = list(string.punctuation)
|
||||
# underscore is allowed
|
||||
illegal_chars.remove('_')
|
||||
|
||||
illegal = "".join(illegal_chars)
|
||||
substitution = ""
|
||||
# Map all punctuation characters to underscore
|
||||
for illegal_char in illegal_chars:
|
||||
substitution = substitution + '_'
|
||||
|
||||
return input.translate(string.maketrans(illegal, substitution), illegal)
|
||||
|
||||
def getNodeIdDefineString(self, node):
|
||||
code = []
|
||||
extrNs = node.browseName().split(":")
|
||||
symbolic_name = ""
|
||||
# strip all characters that would be illegal in C-Code
|
||||
if len(extrNs) > 1:
|
||||
nodename = extrNs[1]
|
||||
else:
|
||||
nodename = extrNs[0]
|
||||
|
||||
symbolic_name = self.substitutePunctuationCharacters(nodename)
|
||||
if symbolic_name != nodename :
|
||||
log(self, "Subsituted characters in browsename for nodeid " + str(node.id().i) + " while generating C-Code ", LOG_LEVEL_WARN)
|
||||
|
||||
if symbolic_name in defined_typealiases:
|
||||
log(self, "Typealias definition of " + str(node.id().i) + " is non unique!", LOG_LEVEL_WARN)
|
||||
extendedN = 1
|
||||
while (symbolic_name+"_"+str(extendedN) in defined_typealiases):
|
||||
log(self, "Typealias definition of " + str(node.id().i) + " is non unique!", LOG_LEVEL_WARN)
|
||||
extendedN+=1
|
||||
symbolic_name = symbolic_name+"_"+str(extendedN)
|
||||
|
||||
defined_typealiases.append(symbolic_name)
|
||||
|
||||
code.append("#define UA_NS" + str(node.id().ns) + "ID_" + symbolic_name.upper() + " " + str(node.id().i))
|
||||
return code
|
||||
|
||||
def getCreateNodeIDMacro(self, node):
|
||||
if node.id().i != None:
|
||||
return "UA_NODEID_NUMERIC(" + str(node.id().ns) + ", " + str(node.id().i) + ")"
|
||||
elif node.id().s != None:
|
||||
return "UA_NODEID_STRING(" + str(node.id().ns) + ", " + node.id().s + ")"
|
||||
elif node.id().b != None:
|
||||
log(self, "NodeID Generation macro for bytestrings has not been implemented.")
|
||||
return ""
|
||||
elif node.id().g != None:
|
||||
log(self, "NodeID Generation macro for guids has not been implemented.")
|
||||
return ""
|
||||
else:
|
||||
return ""
|
||||
|
||||
def getCreateStandaloneReference(self, sourcenode, reference):
|
||||
code = []
|
||||
|
||||
if reference.isForward():
|
||||
code.append("UA_Server_addReference(server, " + self.getCreateNodeIDMacro(sourcenode) + ", " + self.getCreateNodeIDMacro(reference.referenceType()) + ", " + self.getCreateExpandedNodeIDMacro(reference.target()) + ", true);")
|
||||
else:
|
||||
code.append("UA_Server_addReference(server, " + self.getCreateNodeIDMacro(sourcenode) + ", " + self.getCreateNodeIDMacro(reference.referenceType()) + ", " + self.getCreateExpandedNodeIDMacro(reference.target()) + ", false);")
|
||||
return code
|
||||
|
||||
def getCreateNodeNoBootstrap(self, node, parentNode, parentReference, unprintedNodes):
|
||||
code = []
|
||||
code.append("// Node: " + str(node) + ", " + str(node.browseName()))
|
||||
|
||||
if node.nodeClass() == NODE_CLASS_OBJECT:
|
||||
nodetype = "Object"
|
||||
elif node.nodeClass() == NODE_CLASS_VARIABLE:
|
||||
nodetype = "Variable"
|
||||
elif node.nodeClass() == NODE_CLASS_METHOD:
|
||||
nodetype = "Method"
|
||||
elif node.nodeClass() == NODE_CLASS_OBJECTTYPE:
|
||||
nodetype = "ObjectType"
|
||||
elif node.nodeClass() == NODE_CLASS_REFERENCETYPE:
|
||||
nodetype = "ReferenceType"
|
||||
elif node.nodeClass() == NODE_CLASS_VARIABLETYPE:
|
||||
nodetype = "VariableType"
|
||||
elif node.nodeClass() == NODE_CLASS_DATATYPE:
|
||||
nodetype = "DataType"
|
||||
elif node.nodeClass() == NODE_CLASS_VIEW:
|
||||
nodetype = "View"
|
||||
else:
|
||||
code.append("/* undefined nodeclass */")
|
||||
return code;
|
||||
|
||||
# If this is a method, construct in/outargs for addMethod
|
||||
#inputArguments.arrayDimensionsSize = 0;
|
||||
#inputArguments.arrayDimensions = NULL;
|
||||
#inputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
|
||||
|
||||
# Node ordering should have made sure that arguments, if they exist, have not been printed yet
|
||||
if node.nodeClass() == NODE_CLASS_METHOD:
|
||||
inArgVal = []
|
||||
outArgVal = []
|
||||
code.append("UA_Argument *inputArguments = NULL;")
|
||||
code.append("UA_Argument *outputArguments = NULL;")
|
||||
for r in node.getReferences():
|
||||
if r.target() != None and r.target().nodeClass() == NODE_CLASS_VARIABLE and r.target().browseName() == 'InputArguments':
|
||||
while r.target() in unprintedNodes:
|
||||
unprintedNodes.remove(r.target())
|
||||
if r.target().value() != None:
|
||||
inArgVal = r.target().value().value
|
||||
elif r.target() != None and r.target().nodeClass() == NODE_CLASS_VARIABLE and r.target().browseName() == 'OutputArguments':
|
||||
while r.target() in unprintedNodes:
|
||||
unprintedNodes.remove(r.target())
|
||||
if r.target().value() != None:
|
||||
outArgVal = r.target().value().value
|
||||
if len(inArgVal)>0:
|
||||
code.append("")
|
||||
code.append("inputArguments = (UA_Argument *) malloc(sizeof(UA_Argument) * " + str(len(inArgVal)) + ");")
|
||||
code.append("int inputArgumentCnt;")
|
||||
code.append("for (inputArgumentCnt=0; inputArgumentCnt<" + str(len(inArgVal)) + "; inputArgumentCnt++) UA_Argument_init(&inputArguments[inputArgumentCnt]); ")
|
||||
argumentCnt = 0
|
||||
for inArg in inArgVal:
|
||||
if inArg.getValueFieldByAlias("Description") != None:
|
||||
code.append("inputArguments[" + str(argumentCnt) + "].description = UA_LOCALIZEDTEXT(\"" + str(inArg.getValueFieldByAlias("Description")[0]) + "\",\"" + str(inArg.getValueFieldByAlias("Description")[1]) + "\");")
|
||||
if inArg.getValueFieldByAlias("Name") != None:
|
||||
code.append("inputArguments[" + str(argumentCnt) + "].name = UA_STRING(\"" + str(inArg.getValueFieldByAlias("Name")) + "\");")
|
||||
if inArg.getValueFieldByAlias("ValueRank") != None:
|
||||
code.append("inputArguments[" + str(argumentCnt) + "].valueRank = " + str(inArg.getValueFieldByAlias("ValueRank")) + ";")
|
||||
if inArg.getValueFieldByAlias("DataType") != None:
|
||||
code.append("inputArguments[" + str(argumentCnt) + "].dataType = " + str(self.getCreateNodeIDMacro(inArg.getValueFieldByAlias("DataType"))) + ";")
|
||||
#if inArg.getValueFieldByAlias("ArrayDimensions") != None:
|
||||
# code.append("inputArguments[" + str(argumentCnt) + "].arrayDimensions = " + str(inArg.getValueFieldByAlias("ArrayDimensions")) + ";")
|
||||
argumentCnt += 1
|
||||
if len(outArgVal)>0:
|
||||
code.append("")
|
||||
code.append("outputArguments = (UA_Argument *) malloc(sizeof(UA_Argument) * " + str(len(outArgVal)) + ");")
|
||||
code.append("int outputArgumentCnt;")
|
||||
code.append("for (outputArgumentCnt=0; outputArgumentCnt<" + str(len(outArgVal)) + "; outputArgumentCnt++) UA_Argument_init(&outputArguments[outputArgumentCnt]); ")
|
||||
argumentCnt = 0
|
||||
for outArg in outArgVal:
|
||||
if outArg.getValueFieldByAlias("Description") != None:
|
||||
code.append("outputArguments[" + str(argumentCnt) + "].description = UA_LOCALIZEDTEXT(\"" + str(outArg.getValueFieldByAlias("Description")[0]) + "\",\"" + str(outArg.getValueFieldByAlias("Description")[1]) + "\");")
|
||||
if outArg.getValueFieldByAlias("Name") != None:
|
||||
code.append("outputArguments[" + str(argumentCnt) + "].name = UA_STRING(\"" + str(outArg.getValueFieldByAlias("Name")) + "\");")
|
||||
if outArg.getValueFieldByAlias("ValueRank") != None:
|
||||
code.append("outputArguments[" + str(argumentCnt) + "].valueRank = " + str(outArg.getValueFieldByAlias("ValueRank")) + ";")
|
||||
if outArg.getValueFieldByAlias("DataType") != None:
|
||||
code.append("outputArguments[" + str(argumentCnt) + "].dataType = " + str(self.getCreateNodeIDMacro(outArg.getValueFieldByAlias("DataType"))) + ";")
|
||||
#if outArg.getValueFieldByAlias("ArrayDimensions") != None:
|
||||
# code.append("outputArguments[" + str(argumentCnt) + "].arrayDimensions = " + str(outArg.getValueFieldByAlias("ArrayDimensions")) + ";")
|
||||
argumentCnt += 1
|
||||
|
||||
# print the attributes struct
|
||||
code.append("UA_%sAttributes attr;" % nodetype)
|
||||
code.append("UA_%sAttributes_init(&attr);" % nodetype);
|
||||
code.append("attr.displayName = UA_LOCALIZEDTEXT(\"\", \"" + str(node.displayName()) + "\");")
|
||||
code.append("attr.description = UA_LOCALIZEDTEXT(\"\", \"" + str(node.description()) + "\");")
|
||||
|
||||
if nodetype in ["Variable", "VariableType"]:
|
||||
code = code + node.printOpen62541CCode_SubtypeEarly(bootstrapping = False)
|
||||
elif nodetype == "Method":
|
||||
if node.executable():
|
||||
code.append("attr.executable = true;")
|
||||
if node.userExecutable():
|
||||
code.append("attr.userExecutable = true;")
|
||||
|
||||
code.append("UA_NodeId nodeId = " + str(self.getCreateNodeIDMacro(node)) + ";")
|
||||
if nodetype in ["Object", "Variable"]:
|
||||
code.append("UA_NodeId typeDefinition = UA_NODEID_NULL;") # todo instantiation of object and variable types
|
||||
code.append("UA_NodeId parentNodeId = " + str(self.getCreateNodeIDMacro(parentNode)) + ";")
|
||||
code.append("UA_NodeId parentReferenceNodeId = " + str(self.getCreateNodeIDMacro(parentReference.referenceType())) + ";")
|
||||
extrNs = node.browseName().split(":")
|
||||
if len(extrNs) > 1:
|
||||
code.append("UA_QualifiedName nodeName = UA_QUALIFIEDNAME(" + str(extrNs[0]) + ", \"" + extrNs[1] + "\");")
|
||||
else:
|
||||
code.append("UA_QualifiedName nodeName = UA_QUALIFIEDNAME(0, \"" + str(node.browseName()) + "\");")
|
||||
|
||||
# In case of a MethodNode: Add in|outArg struct generation here. Mandates that namespace reordering was done using
|
||||
# Djikstra (check that arguments have not been printed). (@ichrispa)
|
||||
code.append("UA_Server_add%sNode(server, nodeId, parentNodeId, parentReferenceNodeId, nodeName" % nodetype)
|
||||
|
||||
if nodetype in ["Object", "Variable"]:
|
||||
code.append(" , typeDefinition")
|
||||
if nodetype != "Method":
|
||||
code.append(" , attr, NULL, NULL);")
|
||||
else:
|
||||
code.append(" , attr, (UA_MethodCallback) NULL, NULL, " + str(len(inArgVal)) + ", inputArguments, " + str(len(outArgVal)) + ", outputArguments, NULL);")
|
||||
return code
|
||||
|
||||
def getCreateNodeBootstrap(self, node):
|
||||
nodetype = ""
|
||||
code = []
|
||||
|
||||
code.append("// Node: " + str(node) + ", " + str(node.browseName()))
|
||||
|
||||
if node.nodeClass() == NODE_CLASS_OBJECT:
|
||||
nodetype = "Object"
|
||||
elif node.nodeClass() == NODE_CLASS_VARIABLE:
|
||||
nodetype = "Variable"
|
||||
elif node.nodeClass() == NODE_CLASS_METHOD:
|
||||
nodetype = "Method"
|
||||
elif node.nodeClass() == NODE_CLASS_OBJECTTYPE:
|
||||
nodetype = "ObjectType"
|
||||
elif node.nodeClass() == NODE_CLASS_REFERENCETYPE:
|
||||
nodetype = "ReferenceType"
|
||||
elif node.nodeClass() == NODE_CLASS_VARIABLETYPE:
|
||||
nodetype = "VariableType"
|
||||
elif node.nodeClass() == NODE_CLASS_DATATYPE:
|
||||
nodetype = "DataType"
|
||||
elif node.nodeClass() == NODE_CLASS_VIEW:
|
||||
nodetype = "View"
|
||||
else:
|
||||
code.append("/* undefined nodeclass */")
|
||||
return;
|
||||
|
||||
code.append("UA_" + nodetype + "Node *" + node.getCodePrintableID() + " = UA_NodeStore_new" + nodetype + "Node();")
|
||||
if not "browsename" in self.supressGenerationOfAttribute:
|
||||
extrNs = node.browseName().split(":")
|
||||
if len(extrNs) > 1:
|
||||
code.append(node.getCodePrintableID() + "->browseName = UA_QUALIFIEDNAME_ALLOC(" + str(extrNs[0]) + ", \"" + extrNs[1] + "\");")
|
||||
else:
|
||||
code.append(node.getCodePrintableID() + "->browseName = UA_QUALIFIEDNAME_ALLOC(0, \"" + node.browseName() + "\");")
|
||||
if not "displayname" in self.supressGenerationOfAttribute:
|
||||
code.append(node.getCodePrintableID() + "->displayName = UA_LOCALIZEDTEXT_ALLOC(\"en_US\", \"" + node.displayName() + "\");")
|
||||
if not "description" in self.supressGenerationOfAttribute:
|
||||
code.append(node.getCodePrintableID() + "->description = UA_LOCALIZEDTEXT_ALLOC(\"en_US\", \"" + node.description() + "\");")
|
||||
|
||||
if not "writemask" in self.supressGenerationOfAttribute:
|
||||
if node.__node_writeMask__ != 0:
|
||||
code.append(node.getCodePrintableID() + "->writeMask = (UA_Int32) " + str(node.__node_writeMask__) + ";")
|
||||
if not "userwritemask" in self.supressGenerationOfAttribute:
|
||||
if node.__node_userWriteMask__ != 0:
|
||||
code.append(node.getCodePrintableID() + "->userWriteMask = (UA_Int32) " + str(node.__node_userWriteMask__) + ";")
|
||||
if not "nodeid" in self.supressGenerationOfAttribute:
|
||||
if node.id().ns != 0:
|
||||
code.append(node.getCodePrintableID() + "->nodeId.namespaceIndex = " + str(node.id().ns) + ";")
|
||||
if node.id().i != None:
|
||||
code.append(node.getCodePrintableID() + "->nodeId.identifier.numeric = " + str(node.id().i) + ";")
|
||||
elif node.id().b != None:
|
||||
code.append(node.getCodePrintableID() + "->nodeId.identifierType = UA_NODEIDTYPE_BYTESTRING;")
|
||||
log(self, "ByteString IDs for nodes has not been implemented yet.", LOG_LEVEL_ERROR)
|
||||
return []
|
||||
elif node.id().g != None:
|
||||
#<jpfr> the string is sth like { .length = 111, .data = <ptr> }
|
||||
#<jpfr> there you _may_ alloc the <ptr> on the heap
|
||||
#<jpfr> for the guid, just set it to {.data1 = 111, .data2 = 2222, ....
|
||||
code.append(node.getCodePrintableID() + "->nodeId.identifierType = UA_NODEIDTYPE_GUID;")
|
||||
log(self, "GUIDs for nodes has not been implemented yet.", LOG_LEVEL_ERROR)
|
||||
return []
|
||||
elif node.id().s != None:
|
||||
code.append(node.getCodePrintableID() + "->nodeId.identifierType = UA_NODEIDTYPE_STRING;")
|
||||
code.append(node.getCodePrintableID() + "->nodeId.identifier.numeric = UA_STRING_ALLOC(\"" + str(node.id().i) + "\");")
|
||||
else:
|
||||
log(self, "Node ID is not numeric, bytestring, guid or string. I do not know how to create c code for that...", LOG_LEVEL_ERROR)
|
||||
return []
|
||||
|
||||
return code
|
BIN
tools/pyUANamespace/open62541_MacroHelper.pyc
Normal file
BIN
tools/pyUANamespace/open62541_MacroHelper.pyc
Normal file
Binary file not shown.
390
tools/pyUANamespace/open62541_XMLPreprocessor.py
Normal file
390
tools/pyUANamespace/open62541_XMLPreprocessor.py
Normal file
@ -0,0 +1,390 @@
|
||||
#!/usr/bin/env/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
###
|
||||
### Author: Chris Iatrou (ichrispa@core-vector.net)
|
||||
###
|
||||
### This program was created for educational purposes and has been
|
||||
### contributed to the open62541 project by the author. All licensing
|
||||
### terms for this source is inherited by the terms and conditions
|
||||
### specified for by the open62541 project (see the projects readme
|
||||
### file for more information on the LGPL terms and restrictions).
|
||||
###
|
||||
### This program is not meant to be used in a production environment. The
|
||||
### author is not liable for any complications arising due to the use of
|
||||
### this program.
|
||||
###
|
||||
|
||||
from logger import *
|
||||
from ua_constants import *
|
||||
import tempfile
|
||||
import xml.dom.minidom as dom
|
||||
import os
|
||||
import string
|
||||
from collections import Counter
|
||||
|
||||
from ua_namespace import opcua_node_id_t
|
||||
|
||||
class preProcessDocument:
|
||||
originXML = '' # Original XML passed to the preprocessor
|
||||
targetXML = () # tuple of (fileHandle, fileName)
|
||||
nodeset = '' # Parsed DOM XML object
|
||||
parseOK = False;
|
||||
containedNodes = [] # contains tuples of (opcua_node_id_t, xmlelement)
|
||||
referencedNodes = [] # contains tuples of (opcua_node_id_t, xmlelement)
|
||||
namespaceOrder = [] # contains xmlns:sX attributed as tuples (int ns, string name)
|
||||
namespaceQualifiers = [] # contains all xmlns:XYZ qualifiers that might prefix value aliases (like "<uax:Int32>")
|
||||
referencedNamesSpaceUris = [] # contains <NamespaceUris> URI elements
|
||||
|
||||
def __init__(self, originXML):
|
||||
self.originXML = originXML
|
||||
self.targetXML = tempfile.mkstemp(prefix=os.path.basename(originXML)+"_preProcessed-" ,suffix=".xml")
|
||||
self.parseOK = True
|
||||
self.containedNodes = []
|
||||
self.referencedNodes = []
|
||||
self.namespaceOrder = []
|
||||
self.referencedNamesSpaceUris = []
|
||||
self.namespaceQualifiers = []
|
||||
try:
|
||||
self.nodeset = dom.parse(originXML)
|
||||
if len(self.nodeset.getElementsByTagName("UANodeSet")) == 0 or len(self.nodeset.getElementsByTagName("UANodeSet")) > 1:
|
||||
log(self, "Document " + self.targetXML[1] + " contains no or more then 1 nodeset", LOG_LEVEL_ERROR)
|
||||
self.parseOK = False
|
||||
except:
|
||||
self.parseOK = False
|
||||
log(self, "Adding new document to be preprocessed " + os.path.basename(originXML) + " as " + self.targetXML[1], LOG_LEVEL_DEBUG)
|
||||
|
||||
def clean(self):
|
||||
#os.close(self.targetXML[0]) Don't -> done to flush() after finalize()
|
||||
os.remove(self.targetXML[1])
|
||||
|
||||
def getTargetXMLName(self):
|
||||
if (self.parseOK):
|
||||
return self.targetXML[1]
|
||||
return None
|
||||
|
||||
def extractNamespaceURIs(self):
|
||||
""" extractNamespaceURIs
|
||||
|
||||
minidom gobbles up <NamespaceUris></NamespaceUris> elements, without a decent
|
||||
way to reliably access this dom2 <uri></uri> elements (only attribute xmlns= are
|
||||
accessible using minidom). We need them for dereferencing though... This
|
||||
function attempts to do just that.
|
||||
|
||||
returns: Nothing
|
||||
"""
|
||||
infile = open(self.originXML)
|
||||
foundURIs = False
|
||||
nsline = ""
|
||||
line = infile.readline()
|
||||
for line in infile:
|
||||
if "<namespaceuris>" in line.lower():
|
||||
foundURIs = True
|
||||
elif "</namespaceuris>" in line.lower():
|
||||
foundURIs = False
|
||||
nsline = nsline + line
|
||||
break
|
||||
if foundURIs:
|
||||
nsline = nsline + line
|
||||
|
||||
if len(nsline) > 0:
|
||||
ns = dom.parseString(nsline).getElementsByTagName("NamespaceUris")
|
||||
for uri in ns[0].childNodes:
|
||||
if uri.nodeType != uri.ELEMENT_NODE:
|
||||
continue
|
||||
self.referencedNamesSpaceUris.append(uri.firstChild.data)
|
||||
|
||||
infile.close()
|
||||
|
||||
def analyze(self):
|
||||
""" analyze()
|
||||
|
||||
analyze will gather information about the nodes and references contained in a XML File
|
||||
to facilitate later preprocessing stages that adresss XML dependency issues
|
||||
|
||||
returns: No return value
|
||||
"""
|
||||
nodeIds = []
|
||||
ns = self.nodeset.getElementsByTagName("UANodeSet")
|
||||
|
||||
# We need to find out what the namespace calls itself and other referenced, as numeric id's are pretty
|
||||
# useless sans linked nodes. There is two information sources...
|
||||
self.extractNamespaceURIs() # From <URI>...</URI> definitions
|
||||
|
||||
for key in ns[0].attributes.keys(): # from xmlns:sX attributes
|
||||
if "xmlns:" in key: # Any key: we will be removing these qualifiers from Values later
|
||||
self.namespaceQualifiers.append(key.replace("xmlns:",""))
|
||||
if "xmlns:s" in key: # get a numeric nsId and modelname/uri
|
||||
self.namespaceOrder.append((int(key.replace("xmlns:s","")), ns[0].getAttribute(key)))
|
||||
|
||||
# Get all nodeIds contained in this XML
|
||||
for nd in ns[0].childNodes:
|
||||
if nd.nodeType != nd.ELEMENT_NODE:
|
||||
continue
|
||||
if nd.hasAttribute(u'NodeId'):
|
||||
self.containedNodes.append( (opcua_node_id_t(nd.getAttribute(u'NodeId')), nd) )
|
||||
refs = nd.getElementsByTagName(u'References')[0]
|
||||
for ref in refs.childNodes:
|
||||
if ref.nodeType == ref.ELEMENT_NODE:
|
||||
self.referencedNodes.append( (opcua_node_id_t(ref.firstChild.data), ref) )
|
||||
|
||||
log(self, "Nodes: " + str(len(self.containedNodes)) + " References: " + str(len(self.referencedNodes)), LOG_LEVEL_DEBUG)
|
||||
|
||||
def getNamespaceId(self):
|
||||
""" namespaceId()
|
||||
|
||||
Counts the namespace IDs in all nodes of this XML and picks the most used
|
||||
namespace as the numeric identifier of this data model.
|
||||
|
||||
returns: Integer ID of the most propable/most used namespace in this XML
|
||||
"""
|
||||
max = 0;
|
||||
namespaceIdGuessed = 0;
|
||||
idDict = {}
|
||||
|
||||
for ndid in self.containedNodes:
|
||||
if not idDict.has_key(ndid[0].ns):
|
||||
idDict[ndid[0].ns] = 1
|
||||
else:
|
||||
idDict[ndid[0].ns] = idDict[ndid[0].ns] + 1
|
||||
|
||||
for entry in idDict:
|
||||
if idDict[entry] > max:
|
||||
max = idDict[entry]
|
||||
namespaceIdGuessed = entry
|
||||
log(self, "XML Contents are propably in namespace " + str(entry) + " (used by " + str(idDict[entry]) + " Nodes)", LOG_LEVEL_DEBUG)
|
||||
return namespaceIdGuessed
|
||||
|
||||
def getReferencedNamespaceUri(self, nsId):
|
||||
""" getReferencedNamespaceUri
|
||||
|
||||
returns an URL that hopefully corresponds to the nsId that was used to reference this model
|
||||
|
||||
return: URI string corresponding to nsId
|
||||
"""
|
||||
# Might be the more reliable method: Get the URI from the xmlns attributes (they have numers)
|
||||
if len(self.namespaceOrder) > 0:
|
||||
for el in self.namespaceOrder:
|
||||
if el[0] == nsId:
|
||||
return el[1]
|
||||
|
||||
# Fallback:
|
||||
# Some models do not have xmlns:sX attributes, but still <URI>s (usually when they only reference NS0)
|
||||
if len(self.referencedNamesSpaceUris) > 0 and len(self.referencedNamesSpaceUris) >= nsId-1:
|
||||
return self.referencedNamesSpaceUris[nsId-1]
|
||||
|
||||
#Nope, not found.
|
||||
return ""
|
||||
|
||||
def getNamespaceDependencies(self):
|
||||
deps = []
|
||||
for ndid in self.referencedNodes:
|
||||
if not ndid[0].ns in deps:
|
||||
deps.append(ndid[0].ns)
|
||||
return deps
|
||||
|
||||
def finalize(self):
|
||||
outfile = self.targetXML[0]
|
||||
outline = self.nodeset.toxml()
|
||||
for qualifier in self.namespaceQualifiers:
|
||||
rq = qualifier+":"
|
||||
outline = outline.replace(rq.decode('UTF-8'), "")
|
||||
os.write(outfile, outline.encode('UTF-8'))
|
||||
os.close(outfile)
|
||||
|
||||
def reassignReferencedNamespaceId(self, currentNsId, newNsId):
|
||||
""" reassignReferencedNamespaceId
|
||||
|
||||
Iterates over all references in this document, find references to currentNsId and changes them to newNsId.
|
||||
NodeIds themselves are not altered.
|
||||
|
||||
returns: nothing
|
||||
"""
|
||||
for refNd in self.referencedNodes:
|
||||
if refNd[0].ns == currentNsId:
|
||||
refNd[1].firstChild.data = refNd[1].firstChild.data.replace("ns="+str(currentNsId), "ns="+str(newNsId))
|
||||
refNd[0].ns = newNsId
|
||||
refNd[0].toString()
|
||||
|
||||
def reassignNamespaceId(self, currentNsId, newNsId):
|
||||
""" reassignNamespaceId
|
||||
|
||||
Iterates over all nodes in this document, find those in namespace currentNsId and changes them to newNsId.
|
||||
|
||||
returns: nothing
|
||||
"""
|
||||
log(self, "Migrating nodes /w ns index " + str(currentNsId) + " to " + str(newNsId), LOG_LEVEL_DEBUG)
|
||||
for nd in self.containedNodes:
|
||||
if nd[0].ns == currentNsId:
|
||||
# In our own document, update any references to this node
|
||||
for refNd in self.referencedNodes:
|
||||
if refNd[0].ns == currentNsId and refNd[0] == nd[0]:
|
||||
refNd[1].firstChild.data = refNd[1].firstChild.data.replace("ns="+str(currentNsId), "ns="+str(newNsId))
|
||||
refNd[0].ns = newNsId
|
||||
refNd[0].toString()
|
||||
nd[1].setAttribute(u'NodeId', nd[1].getAttribute(u'NodeId').replace("ns="+str(currentNsId), "ns="+str(newNsId)))
|
||||
nd[0].ns = newNsId
|
||||
nd[0].toString()
|
||||
|
||||
class open62541_XMLPreprocessor:
|
||||
preProcDocuments = []
|
||||
|
||||
def __init__(self):
|
||||
self.preProcDocuments = []
|
||||
|
||||
def addDocument(self, documentPath):
|
||||
self.preProcDocuments.append(preProcessDocument(documentPath))
|
||||
|
||||
def removePreprocessedFiles(self):
|
||||
for doc in self.preProcDocuments:
|
||||
doc.clean()
|
||||
|
||||
def getPreProcessedFiles(self):
|
||||
files = []
|
||||
for doc in self.preProcDocuments:
|
||||
if (doc.parseOK):
|
||||
files.append(doc.getTargetXMLName())
|
||||
return files
|
||||
|
||||
def testModelCongruencyAgainstReferences(self, doc, refs):
|
||||
""" testModelCongruencyAgainstReferences
|
||||
|
||||
Counts how many of the nodes referencef in refs can be found in the model
|
||||
doc.
|
||||
|
||||
returns: double corresponding to the percentage of hits
|
||||
"""
|
||||
sspace = len(refs)
|
||||
if sspace == 0:
|
||||
return float(0)
|
||||
found = 0
|
||||
for ref in refs:
|
||||
for n in doc.containedNodes:
|
||||
if str(ref) == str(n[0]):
|
||||
print ref, n[0]
|
||||
found = found + 1
|
||||
break
|
||||
return float(found)/float(sspace)
|
||||
|
||||
def preprocess_assignUniqueNsIds(self):
|
||||
nsdep = []
|
||||
docLst = []
|
||||
# Search for namespace 0('s) - plural possible if user is overwriting NS0 defaults
|
||||
# Remove them from the list of namespaces, zero does not get demangled
|
||||
for doc in self.preProcDocuments:
|
||||
if doc.getNamespaceId() == 0:
|
||||
docLst.append(doc)
|
||||
for doc in docLst:
|
||||
self.preProcDocuments.remove(doc)
|
||||
|
||||
# Reassign namespace id's to be in ascending order
|
||||
nsidx = 1 # next namespace id to assign on collision (first one will be "2")
|
||||
for doc in self.preProcDocuments:
|
||||
nsidx = nsidx + 1
|
||||
nsid = doc.getNamespaceId()
|
||||
doc.reassignNamespaceId(nsid, nsidx)
|
||||
docLst.append(doc)
|
||||
log(self, "Document " + doc.originXML + " is now namespace " + str(nsidx), LOG_LEVEL_INFO)
|
||||
self.preProcDocuments = docLst
|
||||
|
||||
def getUsedNamespaceArrayNames(self):
|
||||
""" getUsedNamespaceArrayNames
|
||||
|
||||
Returns the XML xmlns:s1 or <URI>[0] of each XML document (if contained/possible)
|
||||
|
||||
returns: dict of int:nsId -> string:url
|
||||
"""
|
||||
nsName = {}
|
||||
for doc in self.preProcDocuments:
|
||||
uri = doc.getReferencedNamespaceUri(1)
|
||||
if uri == None:
|
||||
uri = "http://modeluri.not/retrievable/from/xml"
|
||||
nsName[doc.getNamespaceId()] = doc.getReferencedNamespaceUri(1)
|
||||
return nsName
|
||||
|
||||
def preprocess_linkDependantModels(self):
|
||||
revertToStochastic = [] # (doc, int id), where id was not resolvable using model URIs
|
||||
|
||||
# Attemp to identify the model relations by using model URIs in xmlns:sX or <URI> contents
|
||||
for doc in self.preProcDocuments:
|
||||
nsid = doc.getNamespaceId()
|
||||
dependencies = doc.getNamespaceDependencies()
|
||||
for d in dependencies:
|
||||
if d != nsid and d != 0:
|
||||
# Attempt to identify the namespace URI this d referes to...
|
||||
nsUri = doc.getReferencedNamespaceUri(d) # FIXME: This could actually fail and return ""!
|
||||
log(self, "Need a namespace referenced as " + str(d) + ". Which hopefully is " + nsUri, LOG_LEVEL_INFO)
|
||||
targetDoc = None
|
||||
for tgt in self.preProcDocuments:
|
||||
# That model, whose URI is known but its current id is not, will
|
||||
# refer have referred to itself as "1"
|
||||
if tgt.getReferencedNamespaceUri(1) == nsUri:
|
||||
targetDoc = tgt
|
||||
break
|
||||
if not targetDoc == None:
|
||||
# Found the model... relink the references
|
||||
doc.reassignReferencedNamespaceId(d, targetDoc.getNamespaceId())
|
||||
continue
|
||||
else:
|
||||
revertToStochastic.append((doc, d))
|
||||
log(self, "Failed to reliably identify which XML/Model " + os.path.basename(doc.originXML) + " calls ns=" +str(d), LOG_LEVEL_WARN)
|
||||
|
||||
for (doc, d) in revertToStochastic:
|
||||
log(self, "Attempting to find stochastic match for target namespace ns=" + str(d) + " of " + os.path.basename(doc.originXML), LOG_LEVEL_WARN)
|
||||
# Copy all references to the given namespace
|
||||
refs = []
|
||||
matches = [] # list of (match%, targetDoc) to pick from later
|
||||
for ref in doc.referencedNodes:
|
||||
if ref[0].ns == d:
|
||||
refs.append(opcua_node_id_t(str(ref[0])))
|
||||
for tDoc in self.preProcDocuments:
|
||||
tDocId = tDoc.getNamespaceId()
|
||||
# Scenario: If these references did target this documents namespace...
|
||||
for r in refs:
|
||||
r.ns = tDocId
|
||||
r.toString()
|
||||
# ... how many of them would be found!?
|
||||
c = self.testModelCongruencyAgainstReferences(tDoc, refs)
|
||||
print c
|
||||
if c>0:
|
||||
matches.append(c, tDoc)
|
||||
best = (0, None)
|
||||
for m in matches:
|
||||
print m[0]
|
||||
if m[0] > best[0]:
|
||||
best = m
|
||||
if best[1] != None:
|
||||
log(self, "Best match (" + str(best[1]*100) + "%) for what " + os.path.basename(doc.originXML) + " refers to as ns="+str(d)+" was " + os.path.basename(best[1].originXML), LOG_LEVEL_WARN)
|
||||
doc.reassignReferencedNamespaceId(d, best[1].getNamespaceId())
|
||||
else:
|
||||
log(self, "Failed to find a match for what " + os.path.basename(doc.originXML) + " refers to as ns=" + str(d) ,LOG_LEVEL_ERROR )
|
||||
|
||||
def preprocessAll(self):
|
||||
##
|
||||
## First: Gather statistics about the namespaces:
|
||||
for doc in self.preProcDocuments:
|
||||
doc.analyze()
|
||||
|
||||
# Preprocess step: Remove XML specific Naming scheme ("uax:")
|
||||
# FIXME: Not implemented
|
||||
|
||||
##
|
||||
## Preprocess step: Check namespace ID multiplicity and reassign IDs if necessary
|
||||
##
|
||||
self.preprocess_assignUniqueNsIds()
|
||||
self.preprocess_linkDependantModels()
|
||||
|
||||
|
||||
##
|
||||
## Prep step: prevent any XML from using namespace 1 (reserved for instances)
|
||||
## FIXME: Not implemented
|
||||
|
||||
##
|
||||
## Final: Write modified XML tmp files
|
||||
for doc in self.preProcDocuments:
|
||||
doc.finalize()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
BIN
tools/pyUANamespace/open62541_XMLPreprocessor.pyc
Normal file
BIN
tools/pyUANamespace/open62541_XMLPreprocessor.pyc
Normal file
Binary file not shown.
1276
tools/pyUANamespace/ua_builtin_types.py
Normal file
1276
tools/pyUANamespace/ua_builtin_types.py
Normal file
File diff suppressed because it is too large
Load Diff
BIN
tools/pyUANamespace/ua_builtin_types.pyc
Normal file
BIN
tools/pyUANamespace/ua_builtin_types.pyc
Normal file
Binary file not shown.
57
tools/pyUANamespace/ua_constants.py
Normal file
57
tools/pyUANamespace/ua_constants.py
Normal file
@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
###
|
||||
### Author: Chris Iatrou (ichrispa@core-vector.net)
|
||||
### Version: rev 13
|
||||
###
|
||||
### This program was created for educational purposes and has been
|
||||
### contributed to the open62541 project by the author. All licensing
|
||||
### terms for this source is inherited by the terms and conditions
|
||||
### specified for by the open62541 project (see the projects readme
|
||||
### file for more information on the LGPL terms and restrictions).
|
||||
###
|
||||
### This program is not meant to be used in a production environment. The
|
||||
### author is not liable for any complications arising due to the use of
|
||||
### this program.
|
||||
###
|
||||
|
||||
NODE_CLASS_GENERERIC = 0
|
||||
NODE_CLASS_OBJECT = 1
|
||||
NODE_CLASS_VARIABLE = 2
|
||||
NODE_CLASS_METHOD = 4
|
||||
NODE_CLASS_OBJECTTYPE = 8
|
||||
NODE_CLASS_VARIABLETYPE = 16
|
||||
NODE_CLASS_REFERENCETYPE = 32
|
||||
NODE_CLASS_DATATYPE = 64
|
||||
NODE_CLASS_VIEW = 128
|
||||
|
||||
# Not in OPC-UA, but exists in XML
|
||||
NODE_CLASS_METHODTYPE = 256
|
||||
|
||||
##
|
||||
## Numeric codes used to encode binary type fields:
|
||||
##
|
||||
BUILTINTYPE_TYPEID_EXTENSIONOBJECT = 1
|
||||
BUILTINTYPE_TYPEID_LOCALIZEDTEXT = 2
|
||||
BUILTINTYPE_TYPEID_EXPANDEDNODEID = 3
|
||||
BUILTINTYPE_TYPEID_NODEID = 4
|
||||
BUILTINTYPE_TYPEID_DATETIME = 5
|
||||
BUILTINTYPE_TYPEID_QUALIFIEDNAME = 6
|
||||
BUILTINTYPE_TYPEID_STATUSCODE = 7
|
||||
BUILTINTYPE_TYPEID_GUID = 8
|
||||
BUILTINTYPE_TYPEID_BOOLEAN = 9
|
||||
BUILTINTYPE_TYPEID_BYTE = 10
|
||||
BUILTINTYPE_TYPEID_SBYTE = 11
|
||||
BUILTINTYPE_TYPEID_INT16 = 12
|
||||
BUILTINTYPE_TYPEID_UINT16 = 13
|
||||
BUILTINTYPE_TYPEID_INT32 = 14
|
||||
BUILTINTYPE_TYPEID_UINT32 = 15
|
||||
BUILTINTYPE_TYPEID_INT64 = 16
|
||||
BUILTINTYPE_TYPEID_UINT64 = 17
|
||||
BUILTINTYPE_TYPEID_FLOAT = 18
|
||||
BUILTINTYPE_TYPEID_DOUBLE = 19
|
||||
BUILTINTYPE_TYPEID_STRING = 20
|
||||
BUILTINTYPE_TYPEID_XMLELEMENT = 21
|
||||
BUILTINTYPE_TYPEID_BYTESTRING = 22
|
||||
BUILTINTYPE_TYPEID_DIAGNOSTICINFO = 23
|
BIN
tools/pyUANamespace/ua_constants.pyc
Normal file
BIN
tools/pyUANamespace/ua_constants.pyc
Normal file
Binary file not shown.
811
tools/pyUANamespace/ua_namespace.py
Executable file
811
tools/pyUANamespace/ua_namespace.py
Executable file
@ -0,0 +1,811 @@
|
||||
#!/usr/bin/env/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
###
|
||||
### Author: Chris Iatrou (ichrispa@core-vector.net)
|
||||
### Version: rev 13
|
||||
###
|
||||
### This program was created for educational purposes and has been
|
||||
### contributed to the open62541 project by the author. All licensing
|
||||
### terms for this source is inherited by the terms and conditions
|
||||
### specified for by the open62541 project (see the projects readme
|
||||
### file for more information on the LGPL terms and restrictions).
|
||||
###
|
||||
### This program is not meant to be used in a production environment. The
|
||||
### author is not liable for any complications arising due to the use of
|
||||
### this program.
|
||||
###
|
||||
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
from time import struct_time, strftime, strptime, mktime
|
||||
from struct import pack as structpack
|
||||
|
||||
from logger import *;
|
||||
from ua_builtin_types import *;
|
||||
from ua_node_types import *;
|
||||
from ua_constants import *;
|
||||
from open62541_MacroHelper import open62541_MacroHelper
|
||||
|
||||
def getNextElementNode(xmlvalue):
|
||||
if xmlvalue == None:
|
||||
return None
|
||||
xmlvalue = xmlvalue.nextSibling
|
||||
while not xmlvalue == None and not xmlvalue.nodeType == xmlvalue.ELEMENT_NODE:
|
||||
xmlvalue = xmlvalue.nextSibling
|
||||
return xmlvalue
|
||||
|
||||
###
|
||||
### Namespace Organizer
|
||||
###
|
||||
|
||||
class opcua_namespace():
|
||||
""" Class holding and managing a set of OPCUA nodes.
|
||||
|
||||
This class handles parsing XML description of namespaces, instantiating
|
||||
nodes, linking references, graphing the namespace and compiling a binary
|
||||
representation.
|
||||
|
||||
Note that nodes assigned to this class are not restricted to having a
|
||||
single namespace ID. This class represents the entire physical address
|
||||
space of the binary representation and all nodes that are to be included
|
||||
in that segment of memory.
|
||||
"""
|
||||
nodes = []
|
||||
nodeids = {}
|
||||
aliases = {}
|
||||
__linkLater__ = []
|
||||
__binaryIndirectPointers__ = []
|
||||
name = ""
|
||||
knownNodeTypes = ""
|
||||
namespaceIdentifiers = {} # list of 'int':'string' giving different namespace an array-mapable name
|
||||
|
||||
def __init__(self, name):
|
||||
self.nodes = []
|
||||
self.knownNodeTypes = ['variable', 'object', 'method', 'referencetype', \
|
||||
'objecttype', 'variabletype', 'methodtype', \
|
||||
'datatype', 'referencetype', 'aliases']
|
||||
self.name = name
|
||||
self.nodeids = {}
|
||||
self.aliases = {}
|
||||
self.namespaceIdentifiers = {}
|
||||
self.__binaryIndirectPointers__ = []
|
||||
|
||||
def addNamespace(self, numericId, stringURL):
|
||||
self.namespaceIdentifiers[numericId] = stringURL
|
||||
|
||||
def linkLater(self, pointer):
|
||||
""" Called by nodes or references who have parsed an XML reference to a
|
||||
node represented by a string.
|
||||
|
||||
No return value
|
||||
|
||||
XML String representations of references have the form 'i=xy' or
|
||||
'ns=1;s="This unique Node"'. Since during the parsing of this attribute
|
||||
only a subset of nodes are known/parsed, this reference string cannot be
|
||||
linked when encountered.
|
||||
|
||||
References register themselves with the namespace to have their target
|
||||
attribute (string) parsed by linkOpenPointers() when all nodes are
|
||||
created, so that target can be dereferenced an point to an actual node.
|
||||
"""
|
||||
self.__linkLater__.append(pointer)
|
||||
|
||||
def getUnlinkedPointers(self):
|
||||
""" Return the list of references registered for linking during the next call
|
||||
of linkOpenPointers()
|
||||
"""
|
||||
return self.__linkLater__
|
||||
|
||||
def unlinkedItemCount(self):
|
||||
""" Returns the number of unlinked references that will be processed during
|
||||
the next call of linkOpenPointers()
|
||||
"""
|
||||
return len(self.__linkLater__)
|
||||
|
||||
def buildAliasList(self, xmlelement):
|
||||
""" Parses the <Alias> XML Element present in must XML NodeSet definitions.
|
||||
|
||||
No return value
|
||||
|
||||
Contents the Alias element are stored in a dictionary for further
|
||||
dereferencing during pointer linkage (see linkOpenPointer()).
|
||||
"""
|
||||
if not xmlelement.tagName == "Aliases":
|
||||
log(self, "XMLElement passed is not an Aliaslist", LOG_LEVEL_ERROR)
|
||||
return
|
||||
for al in xmlelement.childNodes:
|
||||
if al.nodeType == al.ELEMENT_NODE:
|
||||
if al.hasAttribute("Alias"):
|
||||
aliasst = al.getAttribute("Alias")
|
||||
if sys.version_info[0] < 3:
|
||||
aliasnd = unicode(al.firstChild.data)
|
||||
else:
|
||||
aliasnd = al.firstChild.data
|
||||
if not aliasst in self.aliases:
|
||||
self.aliases[aliasst] = aliasnd
|
||||
log(self, "Added new alias \"" + str(aliasst) + "\" == \"" + str(aliasnd) + "\"")
|
||||
else:
|
||||
if self.aliases[aliasst] != aliasnd:
|
||||
log(self, "Alias definitions for " + aliasst + " differ. Have " + self.aliases[aliasst] + " but XML defines " + aliasnd + ". Keeping current definition.", LOG_LEVEL_ERROR)
|
||||
|
||||
def getNodeByBrowseName(self, idstring):
|
||||
""" Returns the first node in the nodelist whose browseName matches idstring.
|
||||
"""
|
||||
matches = []
|
||||
for n in self.nodes:
|
||||
if idstring==str(n.browseName()):
|
||||
matches.append(n)
|
||||
if len(matches) > 1:
|
||||
log(self, "Found multiple nodes with same ID!?", LOG_LEVEL_ERROR)
|
||||
if len(matches) == 0:
|
||||
return None
|
||||
else:
|
||||
return matches[0]
|
||||
|
||||
def getNodeByIDString(self, idstring):
|
||||
""" Returns the first node in the nodelist whose id string representation
|
||||
matches idstring.
|
||||
"""
|
||||
matches = []
|
||||
for n in self.nodes:
|
||||
if idstring==str(n.id()):
|
||||
matches.append(n)
|
||||
if len(matches) > 1:
|
||||
log(self, "Found multiple nodes with same ID!?", LOG_LEVEL_ERROR)
|
||||
if len(matches) == 0:
|
||||
return None
|
||||
else:
|
||||
return matches[0]
|
||||
|
||||
def createNode(self, ndtype, xmlelement):
|
||||
""" createNode is instantiates a node described by xmlelement, its type being
|
||||
defined by the string ndtype.
|
||||
|
||||
No return value
|
||||
|
||||
If the xmlelement is an <Alias>, the contents will be parsed and stored
|
||||
for later dereferencing during pointer linking (see linkOpenPointers).
|
||||
|
||||
Recognized types are:
|
||||
* UAVariable
|
||||
* UAObject
|
||||
* UAMethod
|
||||
* UAView
|
||||
* UAVariableType
|
||||
* UAObjectType
|
||||
* UAMethodType
|
||||
* UAReferenceType
|
||||
* UADataType
|
||||
|
||||
For every recognized type, an appropriate node class is added to the node
|
||||
list of the namespace. The NodeId of the given node is created and parsing
|
||||
of the node attributes and elements is delegated to the parseXML() and
|
||||
parseXMLSubType() functions of the instantiated class.
|
||||
|
||||
If the NodeID attribute is non-unique in the node list, the creation is
|
||||
deferred and an error is logged.
|
||||
"""
|
||||
if not isinstance(xmlelement, dom.Element):
|
||||
log(self, "Error: Can not create node from invalid XMLElement", LOG_LEVEL_ERROR)
|
||||
return
|
||||
|
||||
# An ID is manditory for everything but aliases!
|
||||
id = None
|
||||
for idname in ['NodeId', 'NodeID', 'nodeid']:
|
||||
if xmlelement.hasAttribute(idname):
|
||||
id = xmlelement.getAttribute(idname)
|
||||
if ndtype == 'aliases':
|
||||
self.buildAliasList(xmlelement)
|
||||
return
|
||||
elif id == None:
|
||||
log(self, "Error: XMLElement has no id, node will not be created!", LOG_LEVEL_INFO)
|
||||
return
|
||||
else:
|
||||
id = opcua_node_id_t(id)
|
||||
|
||||
if str(id) in self.nodeids:
|
||||
# Normal behavior: Do not allow duplicates, first one wins
|
||||
#log(self, "XMLElement with duplicate ID " + str(id) + " found, node will not be created!", LOG_LEVEL_ERROR)
|
||||
#return
|
||||
# Open62541 behavior for header generation: Replace the duplicate with the new node
|
||||
log(self, "XMLElement with duplicate ID " + str(id) + " found, node will be replaced!", LOG_LEVEL_INFO)
|
||||
nd = self.getNodeByIDString(str(id))
|
||||
self.nodes.remove(nd)
|
||||
self.nodeids.pop(str(nd.id()))
|
||||
|
||||
node = None
|
||||
if (ndtype == 'variable'):
|
||||
node = opcua_node_variable_t(id, self)
|
||||
elif (ndtype == 'object'):
|
||||
node = opcua_node_object_t(id, self)
|
||||
elif (ndtype == 'method'):
|
||||
node = opcua_node_method_t(id, self)
|
||||
elif (ndtype == 'objecttype'):
|
||||
node = opcua_node_objectType_t(id, self)
|
||||
elif (ndtype == 'variabletype'):
|
||||
node = opcua_node_variableType_t(id, self)
|
||||
elif (ndtype == 'methodtype'):
|
||||
node = opcua_node_methodType_t(id, self)
|
||||
elif (ndtype == 'datatype'):
|
||||
node = opcua_node_dataType_t(id, self)
|
||||
elif (ndtype == 'referencetype'):
|
||||
node = opcua_node_referenceType_t(id, self)
|
||||
else:
|
||||
log(self, "No node constructor for type " + ndtype, LOG_LEVEL_ERROR)
|
||||
|
||||
if node != None:
|
||||
node.parseXML(xmlelement)
|
||||
|
||||
self.nodes.append(node)
|
||||
self.nodeids[str(node.id())] = node
|
||||
|
||||
def removeNodeById(self, nodeId):
|
||||
nd = self.getNodeByIDString(nodeId)
|
||||
if nd == None:
|
||||
return False
|
||||
|
||||
log(self, "Removing nodeId " + str(nodeId), LOG_LEVEL_DEBUG)
|
||||
self.nodes.remove(nd)
|
||||
if nd.getInverseReferences() != None:
|
||||
for ref in nd.getInverseReferences():
|
||||
src = ref.target();
|
||||
src.removeReferenceToNode(nd)
|
||||
|
||||
return True
|
||||
|
||||
def registerBinaryIndirectPointer(self, node):
|
||||
""" Appends a node to the list of nodes that should be contained in the
|
||||
first 765 bytes (255 pointer slots a 3 bytes) in the binary
|
||||
representation (indirect referencing space).
|
||||
|
||||
This function is reserved for references and dataType pointers.
|
||||
"""
|
||||
if not node in self.__binaryIndirectPointers__:
|
||||
self.__binaryIndirectPointers__.append(node)
|
||||
return self.__binaryIndirectPointers__.index(node)
|
||||
|
||||
def getBinaryIndirectPointerIndex(self, node):
|
||||
""" Returns the slot/index of a pointer in the indirect referencing space
|
||||
(first 765 Bytes) of the binary representation.
|
||||
"""
|
||||
if not node in self.__binaryIndirectPointers__:
|
||||
return -1
|
||||
return self.__binaryIndirectPointers__.index(node)
|
||||
|
||||
|
||||
def parseXML(self, xmldoc):
|
||||
""" Reads an XML Namespace definition and instantiates node.
|
||||
|
||||
No return value
|
||||
|
||||
parseXML open the file xmldoc using xml.dom.minidom and searches for
|
||||
the first UANodeSet Element. For every Element encountered, createNode
|
||||
is called to instantiate a node of the appropriate type.
|
||||
"""
|
||||
typedict = {}
|
||||
UANodeSet = dom.parse(xmldoc).getElementsByTagName("UANodeSet")
|
||||
if len(UANodeSet) == 0:
|
||||
log(self, "Error: No NodeSets found", LOG_LEVEL_ERROR)
|
||||
return
|
||||
if len(UANodeSet) != 1:
|
||||
log(self, "Error: Found more than 1 Nodeset in XML File", LOG_LEVEL_ERROR)
|
||||
|
||||
UANodeSet = UANodeSet[0]
|
||||
for nd in UANodeSet.childNodes:
|
||||
if nd.nodeType != nd.ELEMENT_NODE:
|
||||
continue
|
||||
|
||||
ndType = nd.tagName.lower()
|
||||
if ndType[:2] == "ua":
|
||||
ndType = ndType[2:]
|
||||
elif not ndType in self.knownNodeTypes:
|
||||
log(self, "XML Element or NodeType " + ndType + " is unknown and will be ignored", LOG_LEVEL_WARN)
|
||||
continue
|
||||
|
||||
if not ndType in typedict:
|
||||
typedict[ndType] = 1
|
||||
else:
|
||||
typedict[ndType] = typedict[ndType] + 1
|
||||
|
||||
self.createNode(ndType, nd)
|
||||
log(self, "Currently " + str(len(self.nodes)) + " nodes in address space. Type distribution for this run was: " + str(typedict))
|
||||
|
||||
def linkOpenPointers(self):
|
||||
""" Substitutes symbolic NodeIds in references for actual node instances.
|
||||
|
||||
No return value
|
||||
|
||||
References that have registered themselves with linkLater() to have
|
||||
their symbolic NodeId targets ("ns=2; i=32") substited for an actual
|
||||
node will be iterated by this function. For each reference encountered
|
||||
in the list of unlinked/open references, the target string will be
|
||||
evaluated and searched for in the node list of this namespace. If found,
|
||||
the target attribute of the reference will be substituted for the
|
||||
found node.
|
||||
|
||||
If a reference fails to get linked, it will remain in the list of
|
||||
unlinked references. The individual items in this list can be
|
||||
retrieved using getUnlinkedPointers().
|
||||
"""
|
||||
linked = []
|
||||
|
||||
log(self, str(self.unlinkedItemCount()) + " pointers need to get linked.")
|
||||
for l in self.__linkLater__:
|
||||
targetLinked = False
|
||||
if not l.target() == None and not isinstance(l.target(), opcua_node_t):
|
||||
if isinstance(l.target(),str) or isinstance(l.target(),unicode):
|
||||
# If is not a node ID, it should be an alias. Try replacing it
|
||||
# with a proper node ID
|
||||
if l.target() in self.aliases:
|
||||
l.target(self.aliases[l.target()])
|
||||
# If the link is a node ID, try to find it hopening that no ass has
|
||||
# defined more than one kind of id for that sucker
|
||||
if l.target()[:2] == "i=" or l.target()[:2] == "g=" or \
|
||||
l.target()[:2] == "b=" or l.target()[:2] == "s=" or \
|
||||
l.target()[:3] == "ns=" :
|
||||
tgt = self.getNodeByIDString(str(l.target()))
|
||||
if tgt == None:
|
||||
log(self, "Failed to link pointer to target (node not found) " + l.target(), LOG_LEVEL_ERROR)
|
||||
else:
|
||||
l.target(tgt)
|
||||
targetLinked = True
|
||||
else:
|
||||
log(self, "Failed to link pointer to target (target not Alias or Node) " + l.target(), LOG_LEVEL_ERROR)
|
||||
else:
|
||||
log(self, "Failed to link pointer to target (don't know dummy type + " + str(type(l.target())) + " +) " + str(l.target()), LOG_LEVEL_ERROR)
|
||||
else:
|
||||
log(self, "Pointer has null target: " + str(l), LOG_LEVEL_ERROR)
|
||||
|
||||
|
||||
referenceLinked = False
|
||||
if not l.referenceType() == None:
|
||||
if l.referenceType() in self.aliases:
|
||||
l.referenceType(self.aliases[l.referenceType()])
|
||||
if l.referenceType()[:2] == "i=" or l.referenceType()[:2] == "g=" or \
|
||||
l.referenceType()[:2] == "b=" or l.referenceType()[:2] == "s=":
|
||||
tgt = self.getNodeByIDString(str(l.referenceType()))
|
||||
if tgt == None:
|
||||
log(self, "Failed to link reference type to target (node not found) " + l.referenceType(), LOG_LEVEL_ERROR)
|
||||
else:
|
||||
l.referenceType(tgt)
|
||||
referenceLinked = True
|
||||
else:
|
||||
referenceLinked = True
|
||||
|
||||
if referenceLinked == True and targetLinked == True:
|
||||
linked.append(l)
|
||||
|
||||
# References marked as "not forward" must be inverted (removed from source node, assigned to target node and relinked)
|
||||
log(self, "Inverting reference direction for all references with isForward==False attribute (is this correct!?)", LOG_LEVEL_WARN)
|
||||
for n in self.nodes:
|
||||
for r in n.getReferences():
|
||||
if r.isForward() == False:
|
||||
tgt = r.target()
|
||||
if isinstance(tgt, opcua_node_t):
|
||||
nref = opcua_referencePointer_t(n, parentNode=tgt)
|
||||
nref.referenceType(r.referenceType())
|
||||
tgt.addReference(nref)
|
||||
|
||||
# Create inverse references for all nodes
|
||||
log(self, "Updating all referencedBy fields in nodes for inverse lookups.")
|
||||
for n in self.nodes:
|
||||
n.updateInverseReferences()
|
||||
|
||||
for l in linked:
|
||||
self.__linkLater__.remove(l)
|
||||
|
||||
if len(self.__linkLater__) != 0:
|
||||
log(self, str(len(self.__linkLater__)) + " could not be linked.", LOG_LEVEL_WARN)
|
||||
|
||||
def sanitize(self):
|
||||
remove = []
|
||||
log(self, "Sanitizing nodes and references...")
|
||||
for n in self.nodes:
|
||||
if n.sanitize() == False:
|
||||
remove.append(n)
|
||||
if not len(remove) == 0:
|
||||
log(self, str(len(remove)) + " nodes will be removed because they failed sanitation.", LOG_LEVEL_WARN)
|
||||
# FIXME: Some variable ns=0 nodes fail because they don't have DataType fields...
|
||||
# How should this be handles!?
|
||||
log(self, "Not actually removing nodes... it's unclear if this is valid or not", LOG_LEVEL_WARN)
|
||||
|
||||
def getRoot(self):
|
||||
""" Returns the first node instance with the browseName "Root".
|
||||
"""
|
||||
return self.getNodeByBrowseName("Root")
|
||||
|
||||
def buildEncodingRules(self):
|
||||
""" Calls buildEncoding() for all DataType nodes (opcua_node_dataType_t).
|
||||
|
||||
No return value
|
||||
"""
|
||||
stat = {True: 0, False: 0}
|
||||
for n in self.nodes:
|
||||
if isinstance(n, opcua_node_dataType_t):
|
||||
n.buildEncoding()
|
||||
stat[n.isEncodable()] = stat[n.isEncodable()] + 1
|
||||
log(self, "Type definitions built/passed: " + str(stat), LOG_LEVEL_DEBUG)
|
||||
|
||||
def allocateVariables(self):
|
||||
for n in self.nodes:
|
||||
if isinstance(n, opcua_node_variable_t):
|
||||
n.allocateValue()
|
||||
|
||||
def printDot(self, filename="namespace.dot"):
|
||||
""" Outputs a graphiz/dot description of all nodes in the namespace.
|
||||
|
||||
Output will written into filename to be parsed by dot/neato...
|
||||
|
||||
Note that for namespaces with more then 20 nodes the reference structure
|
||||
will lead to a mostly illegible and huge graph. Use printDotGraphWalk()
|
||||
for plotting specific portions of a large namespace.
|
||||
"""
|
||||
file=open(filename, 'w+')
|
||||
|
||||
file.write("digraph ns {\n")
|
||||
for n in self.nodes:
|
||||
file.write(n.printDot())
|
||||
file.write("}\n")
|
||||
file.close()
|
||||
|
||||
def getSubTypesOf(self, tdNodes = None, currentNode = None, hasSubtypeRefNode = None):
|
||||
# If this is a toplevel call, collect the following information as defaults
|
||||
if tdNodes == None:
|
||||
tdNodes = []
|
||||
if currentNode == None:
|
||||
currentNode = self.getNodeByBrowseName("HasTypeDefinition")
|
||||
tdNodes.append(currentNode)
|
||||
if len(tdNodes) < 1:
|
||||
return []
|
||||
if hasSubtypeRefNode == None:
|
||||
hasSubtypeRefNode = self.getNodeByBrowseName("HasSubtype")
|
||||
if hasSubtypeRefNode == None:
|
||||
return tdNodes
|
||||
|
||||
# collect all subtypes of this node
|
||||
for ref in currentNode.getReferences():
|
||||
if ref.isForward() and ref.referenceType().id() == hasSubtypeRefNode.id():
|
||||
tdNodes.append(ref.target())
|
||||
self.getTypeDefinitionNodes(tdNodes=tdNodes, currentNode = ref.target(), hasSubtypeRefNode=hasSubtypeRefNode)
|
||||
|
||||
return tdNodes
|
||||
|
||||
|
||||
def printDotGraphWalk(self, depth=1, filename="out.dot", rootNode=None, followInverse = False, excludeNodeIds=[]):
|
||||
""" Outputs a graphiz/dot description the nodes centered around rootNode.
|
||||
|
||||
References beginning from rootNode will be followed for depth steps. If
|
||||
"followInverse = True" is passed, then inverse (not Forward) references
|
||||
will also be followed.
|
||||
|
||||
Nodes can be excluded from the graph by passing a list of NodeIds as
|
||||
string representation using excludeNodeIds (ex ["i=53", "ns=2;i=453"]).
|
||||
|
||||
Output is written into filename to be parsed by dot/neato/srfp...
|
||||
"""
|
||||
iter = depth
|
||||
processed = []
|
||||
if rootNode == None or \
|
||||
not isinstance(rootNode, opcua_node_t) or \
|
||||
not rootNode in self.nodes:
|
||||
root = self.getRoot()
|
||||
else:
|
||||
root = rootNode
|
||||
|
||||
file=open(filename, 'w+')
|
||||
|
||||
if root == None:
|
||||
return
|
||||
|
||||
file.write("digraph ns {\n")
|
||||
file.write(root.printDot())
|
||||
refs=[]
|
||||
if followInverse == True:
|
||||
refs = root.getReferences(); # + root.getInverseReferences()
|
||||
else:
|
||||
for ref in root.getReferences():
|
||||
if ref.isForward():
|
||||
refs.append(ref)
|
||||
while iter > 0:
|
||||
tmp = []
|
||||
for ref in refs:
|
||||
if isinstance(ref.target(), opcua_node_t):
|
||||
tgt = ref.target()
|
||||
if not str(tgt.id()) in excludeNodeIds:
|
||||
if not tgt in processed:
|
||||
file.write(tgt.printDot())
|
||||
processed.append(tgt)
|
||||
if ref.isForward() == False and followInverse == True:
|
||||
tmp = tmp + tgt.getReferences(); # + tgt.getInverseReferences()
|
||||
elif ref.isForward() == True :
|
||||
tmp = tmp + tgt.getReferences();
|
||||
refs = tmp
|
||||
iter = iter - 1
|
||||
|
||||
file.write("}\n")
|
||||
file.close()
|
||||
|
||||
def __reorder_getMinWeightNode__(self, nmatrix):
|
||||
rcind = -1
|
||||
rind = -1
|
||||
minweight = -1
|
||||
minweightnd = None
|
||||
for row in nmatrix:
|
||||
rcind += 1
|
||||
if row[0] == None:
|
||||
continue
|
||||
w = sum(row[1:])
|
||||
if minweight < 0:
|
||||
rind = rcind
|
||||
minweight = w
|
||||
minweightnd = row[0]
|
||||
elif w < minweight:
|
||||
rind = rcind
|
||||
minweight = w
|
||||
minweightnd = row[0]
|
||||
return (rind, minweightnd, minweight)
|
||||
|
||||
def reorderNodesMinDependencies(self):
|
||||
# create a matrix represtantion of all node
|
||||
#
|
||||
nmatrix = []
|
||||
for n in range(0,len(self.nodes)):
|
||||
nmatrix.append([None] + [0]*len(self.nodes))
|
||||
|
||||
typeRefs = []
|
||||
tn = self.getNodeByBrowseName("HasTypeDefinition")
|
||||
if tn != None:
|
||||
typeRefs.append(tn)
|
||||
typeRefs = typeRefs + self.getSubTypesOf(currentNode=tn)
|
||||
subTypeRefs = []
|
||||
tn = self.getNodeByBrowseName("HasSubtype")
|
||||
if tn != None:
|
||||
subTypeRefs.append(tn)
|
||||
subTypeRefs = subTypeRefs + self.getSubTypesOf(currentNode=tn)
|
||||
|
||||
log(self, "Building connectivity matrix for node order optimization.")
|
||||
# Set column 0 to contain the node
|
||||
for node in self.nodes:
|
||||
nind = self.nodes.index(node)
|
||||
nmatrix[nind][0] = node
|
||||
|
||||
# Determine the dependencies of all nodes
|
||||
for node in self.nodes:
|
||||
nind = self.nodes.index(node)
|
||||
#print "Examining node " + str(nind) + " " + str(node)
|
||||
for ref in node.getReferences():
|
||||
if isinstance(ref.target(), opcua_node_t):
|
||||
tind = self.nodes.index(ref.target())
|
||||
# Typedefinition of this node has precedence over this node
|
||||
if ref.referenceType() in typeRefs and ref.isForward():
|
||||
nmatrix[nind][tind+1] += 1
|
||||
# isSubTypeOf/typeDefinition of this node has precedence over this node
|
||||
elif ref.referenceType() in subTypeRefs and not ref.isForward():
|
||||
nmatrix[nind][tind+1] += 1
|
||||
# Else the target depends on us
|
||||
elif ref.isForward():
|
||||
nmatrix[tind][nind+1] += 1
|
||||
|
||||
log(self, "Using Djikstra topological sorting to determine printing order.")
|
||||
reorder = []
|
||||
while len(reorder) < len(self.nodes):
|
||||
(nind, node, w) = self.__reorder_getMinWeightNode__(nmatrix)
|
||||
#print str(100*float(len(reorder))/len(self.nodes)) + "% " + str(w) + " " + str(node) + " " + str(node.browseName())
|
||||
reorder.append(node)
|
||||
for ref in node.getReferences():
|
||||
if isinstance(ref.target(), opcua_node_t):
|
||||
tind = self.nodes.index(ref.target())
|
||||
if ref.referenceType() in typeRefs and ref.isForward():
|
||||
nmatrix[nind][tind+1] -= 1
|
||||
elif ref.referenceType() in subTypeRefs and not ref.isForward():
|
||||
nmatrix[nind][tind+1] -= 1
|
||||
elif ref.isForward():
|
||||
nmatrix[tind][nind+1] -= 1
|
||||
nmatrix[nind][0] = None
|
||||
self.nodes = reorder
|
||||
log(self, "Nodes reordered.")
|
||||
return
|
||||
|
||||
def printOpen62541Header(self, printedExternally=[], supressGenerationOfAttribute=[], outfilename=""):
|
||||
unPrintedNodes = []
|
||||
unPrintedRefs = []
|
||||
code = []
|
||||
header = []
|
||||
|
||||
# Reorder our nodes to produce a bare minimum of bootstrapping dependencies
|
||||
log(self, "Reordering nodes for minimal dependencies during printing.")
|
||||
self.reorderNodesMinDependencies()
|
||||
|
||||
# Some macros (UA_EXPANDEDNODEID_MACRO()...) are easily created, but
|
||||
# bulky. This class will help to offload some code.
|
||||
codegen = open62541_MacroHelper(supressGenerationOfAttribute=supressGenerationOfAttribute)
|
||||
|
||||
# Populate the unPrinted-Lists with everything we have.
|
||||
# Every Time a nodes printfunction is called, it will pop itself and
|
||||
# all printed references from these lists.
|
||||
for n in self.nodes:
|
||||
if not n in printedExternally:
|
||||
unPrintedNodes.append(n)
|
||||
else:
|
||||
log(self, "Node " + str(n.id()) + " is being ignored.", LOG_LEVEL_DEBUG)
|
||||
for n in unPrintedNodes:
|
||||
for r in n.getReferences():
|
||||
if (r.target() != None) and (r.target().id() != None) and (r.parent() != None):
|
||||
unPrintedRefs.append(r)
|
||||
|
||||
log(self, str(len(unPrintedNodes)) + " Nodes, " + str(len(unPrintedRefs)) + "References need to get printed.", LOG_LEVEL_DEBUG)
|
||||
header.append("/* WARNING: This is a generated file.\n * Any manual changes will be overwritten.\n\n */")
|
||||
code.append("/* WARNING: This is a generated file.\n * Any manual changes will be overwritten.\n\n */")
|
||||
|
||||
header.append('#ifndef '+outfilename.upper()+'_H_')
|
||||
header.append('#define '+outfilename.upper()+'_H_')
|
||||
header.append('#ifdef UA_NO_AMALGAMATION')
|
||||
header.append('#include "server/ua_server_internal.h"')
|
||||
header.append('#include "server/ua_nodes.h"')
|
||||
header.append('#include "ua_util.h"')
|
||||
header.append('#include "ua_types.h"')
|
||||
header.append('#include "ua_types_encoding_binary.h"')
|
||||
header.append('#include "ua_types_generated_encoding_binary.h"')
|
||||
header.append('#include "ua_transport_generated_encoding_binary.h"')
|
||||
header.append('#else')
|
||||
header.append('#include "open62541.h"')
|
||||
header.append('#define NULL ((void *)0)')
|
||||
header.append('#endif')
|
||||
|
||||
code.append('#include "'+outfilename+'.h"')
|
||||
code.append("UA_INLINE void "+outfilename+"(UA_Server *server) {")
|
||||
|
||||
# Before printing nodes, we need to request additional namespace arrays from the server
|
||||
for nsid in self.namespaceIdentifiers:
|
||||
if nsid == 0 or nsid==1:
|
||||
continue
|
||||
else:
|
||||
name = self.namespaceIdentifiers[nsid]
|
||||
name = name.replace("\"","\\\"")
|
||||
code.append("UA_Server_addNamespace(server, \"" + name.encode('UTF-8') + "\");")
|
||||
|
||||
# Find all references necessary to create the namespace and
|
||||
# "Bootstrap" them so all other nodes can safely use these referencetypes whenever
|
||||
# they can locate both source and target of the reference.
|
||||
log(self, "Collecting all references used in the namespace.", LOG_LEVEL_DEBUG)
|
||||
refsUsed = []
|
||||
for n in self.nodes:
|
||||
# Since we are already looping over all nodes, use this chance to print NodeId defines
|
||||
if n.id().ns != 0:
|
||||
nc = n.nodeClass()
|
||||
if nc != NODE_CLASS_OBJECT and nc != NODE_CLASS_VARIABLE and nc != NODE_CLASS_VIEW:
|
||||
header = header + codegen.getNodeIdDefineString(n)
|
||||
|
||||
# Now for the actual references...
|
||||
for r in n.getReferences():
|
||||
# Only print valid refernces in namespace 0 (users will not want their refs bootstrapped)
|
||||
if not r.referenceType() in refsUsed and r.referenceType() != None and r.referenceType().id().ns == 0:
|
||||
refsUsed.append(r.referenceType())
|
||||
log(self, str(len(refsUsed)) + " reference types are used in the namespace, which will now get bootstrapped.", LOG_LEVEL_DEBUG)
|
||||
for r in refsUsed:
|
||||
code = code + r.printOpen62541CCode(unPrintedNodes, unPrintedRefs);
|
||||
|
||||
header.append("extern void "+outfilename+"(UA_Server *server);\n")
|
||||
header.append("#endif /* "+outfilename.upper()+"_H_ */")
|
||||
|
||||
# Note to self: do NOT - NOT! - try to iterate over unPrintedNodes!
|
||||
# Nodes remove themselves from this list when printed.
|
||||
log(self, "Printing all other nodes.", LOG_LEVEL_DEBUG)
|
||||
for n in self.nodes:
|
||||
code = code + n.printOpen62541CCode(unPrintedNodes, unPrintedRefs, supressGenerationOfAttribute=supressGenerationOfAttribute)
|
||||
|
||||
if len(unPrintedNodes) != 0:
|
||||
log(self, "" + str(len(unPrintedNodes)) + " nodes could not be translated to code.", LOG_LEVEL_WARN)
|
||||
else:
|
||||
log(self, "Printing suceeded for all nodes", LOG_LEVEL_DEBUG)
|
||||
|
||||
if len(unPrintedRefs) != 0:
|
||||
log(self, "Attempting to print " + str(len(unPrintedRefs)) + " unprinted references.", LOG_LEVEL_DEBUG)
|
||||
tmprefs = []
|
||||
for r in unPrintedRefs:
|
||||
if not (r.target() not in unPrintedNodes) and not (r.parent() in unPrintedNodes):
|
||||
if not isinstance(r.parent(), opcua_node_t):
|
||||
log(self, "Reference has no parent!", LOG_LEVEL_DEBUG)
|
||||
elif not isinstance(r.parent().id(), opcua_node_id_t):
|
||||
log(self, "Parents nodeid is not a nodeID!", LOG_LEVEL_DEBUG)
|
||||
else:
|
||||
if (len(tmprefs) == 0):
|
||||
code.append("// Creating leftover references:")
|
||||
code = code + codegen.getCreateStandaloneReference(r.parent(), r)
|
||||
code.append("")
|
||||
tmprefs.append(r)
|
||||
# Remove printed refs from list
|
||||
for r in tmprefs:
|
||||
unPrintedRefs.remove(r)
|
||||
if len(unPrintedRefs) != 0:
|
||||
log(self, "" + str(len(unPrintedRefs)) + " references could not be translated to code.", LOG_LEVEL_WARN)
|
||||
else:
|
||||
log(self, "Printing succeeded for all references", LOG_LEVEL_DEBUG)
|
||||
|
||||
code.append("}")
|
||||
return (header,code)
|
||||
|
||||
###
|
||||
### Testing
|
||||
###
|
||||
|
||||
class testing:
|
||||
def __init__(self):
|
||||
self.namespace = opcua_namespace("testing")
|
||||
|
||||
log(self, "Phase 1: Reading XML file nodessets")
|
||||
self.namespace.parseXML("Opc.Ua.NodeSet2.xml")
|
||||
#self.namespace.parseXML("Opc.Ua.NodeSet2.Part4.xml")
|
||||
#self.namespace.parseXML("Opc.Ua.NodeSet2.Part5.xml")
|
||||
#self.namespace.parseXML("Opc.Ua.SimulationNodeSet2.xml")
|
||||
|
||||
log(self, "Phase 2: Linking address space references and datatypes")
|
||||
self.namespace.linkOpenPointers()
|
||||
self.namespace.sanitize()
|
||||
|
||||
log(self, "Phase 3: Comprehending DataType encoding rules")
|
||||
self.namespace.buildEncodingRules()
|
||||
|
||||
log(self, "Phase 4: Allocating variable value data")
|
||||
self.namespace.allocateVariables()
|
||||
|
||||
bin = self.namespace.buildBinary()
|
||||
f = open("binary.base64","w+")
|
||||
f.write(bin.encode("base64"))
|
||||
f.close()
|
||||
|
||||
allnodes = self.namespace.nodes;
|
||||
ns = [self.namespace.getRoot()]
|
||||
|
||||
i = 0
|
||||
#print "Starting depth search on " + str(len(allnodes)) + " nodes starting with from " + str(ns)
|
||||
while (len(ns) < len(allnodes)):
|
||||
i = i + 1;
|
||||
tmp = [];
|
||||
print("Iteration: " + str(i))
|
||||
for n in ns:
|
||||
tmp.append(n)
|
||||
for r in n.getReferences():
|
||||
if (not r.target() in tmp):
|
||||
tmp.append(r.target())
|
||||
print("...tmp, " + str(len(tmp)) + " nodes discovered")
|
||||
ns = []
|
||||
for n in tmp:
|
||||
ns.append(n)
|
||||
print("...done, " + str(len(ns)) + " nodes discovered")
|
||||
|
||||
log(self, "Phase 5: Printing pretty graph")
|
||||
self.namespace.printDotGraphWalk(depth=1, rootNode=self.namespace.getNodeByIDString("i=84"), followInverse=False, excludeNodeIds=["i=29", "i=22", "i=25"])
|
||||
#self.namespace.printDot()
|
||||
|
||||
class testing_open62541_header:
|
||||
def __init__(self):
|
||||
self.namespace = opcua_namespace("testing")
|
||||
|
||||
log(self, "Phase 1: Reading XML file nodessets")
|
||||
self.namespace.parseXML("Opc.Ua.NodeSet2.xml")
|
||||
#self.namespace.parseXML("Opc.Ua.NodeSet2.Part4.xml")
|
||||
#self.namespace.parseXML("Opc.Ua.NodeSet2.Part5.xml")
|
||||
#self.namespace.parseXML("Opc.Ua.SimulationNodeSet2.xml")
|
||||
|
||||
log(self, "Phase 2: Linking address space references and datatypes")
|
||||
self.namespace.linkOpenPointers()
|
||||
self.namespace.sanitize()
|
||||
|
||||
log(self, "Phase 3: Calling C Printers")
|
||||
code = self.namespace.printOpen62541Header()
|
||||
|
||||
codeout = open("./open62541_namespace.c", "w+")
|
||||
for line in code:
|
||||
codeout.write(line + "\n")
|
||||
codeout.close()
|
||||
return
|
||||
|
||||
# Call testing routine if invoked standalone.
|
||||
# For better debugging, it is advised to import this file using an interactive
|
||||
# python shell and instantiating a namespace.
|
||||
#
|
||||
# import ua_types.py as ua; ns=ua.testing().namespace
|
||||
if __name__ == '__main__':
|
||||
tst = testing_open62541_header()
|
BIN
tools/pyUANamespace/ua_namespace.pyc
Normal file
BIN
tools/pyUANamespace/ua_namespace.pyc
Normal file
Binary file not shown.
1771
tools/pyUANamespace/ua_node_types.py
Normal file
1771
tools/pyUANamespace/ua_node_types.py
Normal file
File diff suppressed because it is too large
Load Diff
BIN
tools/pyUANamespace/ua_node_types.pyc
Normal file
BIN
tools/pyUANamespace/ua_node_types.pyc
Normal file
Binary file not shown.
95
tools/schema/Custom.Opc.Ua.Transport.bsd
Normal file
95
tools/schema/Custom.Opc.Ua.Transport.bsd
Normal file
@ -0,0 +1,95 @@
|
||||
<opc:TypeDictionary
|
||||
xmlns:opc="http://opcfoundation.org/BinarySchema/"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:ua="http://opcfoundation.org/UA/"
|
||||
xmlns:tns="http://opcfoundation.org/UA/"
|
||||
DefaultByteOrder="LittleEndian"
|
||||
TargetNamespace="http://opcfoundation.org/UA/"
|
||||
>
|
||||
|
||||
<opc:Import Namespace="http://opcfoundation.org/BinarySchema/" />
|
||||
|
||||
<!-- Transport types begin -->
|
||||
|
||||
<opc:EnumeratedType Name="MessageType" LengthInBits="32">
|
||||
<opc:Documentation>Message Type and whether the message contains an intermediate chunk</opc:Documentation>
|
||||
<opc:EnumeratedValue Name="ACK" Value="0x4B4341" />
|
||||
<opc:EnumeratedValue Name="HEL" Value="0x4C4548" />
|
||||
<opc:EnumeratedValue Name="MSG" Value="0x47534D" />
|
||||
<opc:EnumeratedValue Name="OPN" Value="0x4E504F" />
|
||||
<opc:EnumeratedValue Name="CLO" Value="0x4F4C43" />
|
||||
</opc:EnumeratedType>
|
||||
|
||||
<opc:EnumeratedType Name="ChunkType" LengthInBits="32">
|
||||
<opc:Documentation>Type of the chunk</opc:Documentation>
|
||||
<opc:EnumeratedValue Name="FINAL" Value="0x46000000" />
|
||||
<opc:EnumeratedValue Name="INTERMEDIATE" Value="0x43000000" />
|
||||
<opc:EnumeratedValue Name="ABORT" Value="0x41000000" />
|
||||
|
||||
</opc:EnumeratedType>
|
||||
|
||||
<opc:StructuredType Name="TcpMessageHeader">
|
||||
<opc:Documentation>TCP Header</opc:Documentation>
|
||||
<opc:Field Name="MessageTypeAndChunkType" TypeName="opc:UInt32" />
|
||||
<opc:Field Name="MessageSize" TypeName="opc:UInt32" />
|
||||
</opc:StructuredType>
|
||||
|
||||
<opc:StructuredType Name="TcpHelloMessage">
|
||||
<opc:Documentation>Hello Message</opc:Documentation>
|
||||
<opc:Field Name="ProtocolVersion" TypeName="opc:UInt32" />
|
||||
<opc:Field Name="ReceiveBufferSize" TypeName="opc:UInt32" />
|
||||
<opc:Field Name="SendBufferSize" TypeName="opc:UInt32" />
|
||||
<opc:Field Name="MaxMessageSize" TypeName="opc:UInt32" />
|
||||
<opc:Field Name="MaxChunkCount" TypeName="opc:UInt32" />
|
||||
<opc:Field Name="EndpointUrl" TypeName="opc:String" />
|
||||
</opc:StructuredType>
|
||||
|
||||
<opc:StructuredType Name="TcpAcknowledgeMessage">
|
||||
<opc:Documentation>Acknowledge Message</opc:Documentation>
|
||||
<opc:Field Name="ProtocolVersion" TypeName="opc:UInt32" />
|
||||
<opc:Field Name="ReceiveBufferSize" TypeName="opc:UInt32" />
|
||||
<opc:Field Name="SendBufferSize" TypeName="opc:UInt32" />
|
||||
<opc:Field Name="MaxMessageSize" TypeName="opc:UInt32" />
|
||||
<opc:Field Name="MaxChunkCount" TypeName="opc:UInt32" />
|
||||
</opc:StructuredType>
|
||||
|
||||
<opc:StructuredType Name="SecureConversationMessageHeader">
|
||||
<opc:Documentation>Secure Layer Sequence Header</opc:Documentation>
|
||||
<opc:Field Name="MessageHeader" TypeName="opc:TcpMessageHeader" />
|
||||
<opc:Field Name="SecureChannelId" TypeName="opc:UInt32" />
|
||||
</opc:StructuredType>
|
||||
|
||||
<opc:StructuredType Name="AsymmetricAlgorithmSecurityHeader">
|
||||
<opc:Documentation>Security Header</opc:Documentation>
|
||||
<opc:Field Name="SecurityPolicyUri" TypeName="opc:ByteString" />
|
||||
<opc:Field Name="SenderCertificate" TypeName="opc:ByteString" />
|
||||
<opc:Field Name="ReceiverCertificateThumbprint" TypeName="opc:ByteString" />
|
||||
</opc:StructuredType>
|
||||
|
||||
<opc:StructuredType Name="SymmetricAlgorithmSecurityHeader">
|
||||
<opc:Documentation>Secure Layer Symmetric Algorithm Header</opc:Documentation>
|
||||
<opc:Field Name="TokenId" TypeName="opc:UInt32" />
|
||||
</opc:StructuredType>
|
||||
|
||||
<opc:StructuredType Name="SequenceHeader">
|
||||
<opc:Documentation>Secure Layer Sequence Header</opc:Documentation>
|
||||
<opc:Field Name="SequenceNumber" TypeName="opc:UInt32" />
|
||||
<opc:Field Name="RequestId" TypeName="opc:UInt32"/>
|
||||
</opc:StructuredType>
|
||||
|
||||
<opc:StructuredType Name="SecureConversationMessageFooter">
|
||||
<opc:Documentation>Secure Conversation Message Footer</opc:Documentation>
|
||||
<opc:Field Name="PaddingSize" TypeName="opc:Byte" />
|
||||
<opc:Field Name="Padding" TypeName="opc:Byte" LengthField="PaddingSize" />
|
||||
<opc:Field Name="Signature" TypeName="opc:Byte"/>
|
||||
</opc:StructuredType>
|
||||
|
||||
<opc:StructuredType Name="SecureConversationMessageAbortBody">
|
||||
<opc:Documentation>Secure Conversation Message Abort Body</opc:Documentation>
|
||||
<opc:Field Name="Error" TypeName="opc:UInt32" />
|
||||
<opc:Field Name="Reason" TypeName="opc:String" />
|
||||
</opc:StructuredType>
|
||||
|
||||
<!-- Transport types end -->
|
||||
|
||||
</opc:TypeDictionary>
|
4879
tools/schema/NodeIds.csv
Normal file
4879
tools/schema/NodeIds.csv
Normal file
File diff suppressed because it is too large
Load Diff
2394
tools/schema/Opc.Ua.Types.bsd
Normal file
2394
tools/schema/Opc.Ua.Types.bsd
Normal file
File diff suppressed because it is too large
Load Diff
158
tools/schema/datatypes_minimal.txt
Normal file
158
tools/schema/datatypes_minimal.txt
Normal file
@ -0,0 +1,158 @@
|
||||
Boolean
|
||||
SByte
|
||||
Byte
|
||||
Int16
|
||||
UInt16
|
||||
Int32
|
||||
UInt32
|
||||
Int64
|
||||
UInt64
|
||||
Float
|
||||
Double
|
||||
String
|
||||
DateTime
|
||||
Guid
|
||||
ByteString
|
||||
XmlElement
|
||||
NodeId
|
||||
ExpandedNodeId
|
||||
StatusCode
|
||||
QualifiedName
|
||||
LocalizedText
|
||||
ExtensionObject
|
||||
DataValue
|
||||
Variant
|
||||
DiagnosticInfo
|
||||
NodeClass
|
||||
ReferenceNode
|
||||
ApplicationDescription
|
||||
ApplicationType
|
||||
ChannelSecurityToken
|
||||
OpenSecureChannelRequest
|
||||
OpenSecureChannelResponse
|
||||
CloseSecureChannelRequest
|
||||
CloseSecureChannelResponse
|
||||
RequestHeader
|
||||
ResponseHeader
|
||||
SecurityTokenRequestType
|
||||
MessageSecurityMode
|
||||
CloseSessionResponse
|
||||
CloseSessionRequest
|
||||
ActivateSessionRequest
|
||||
ActivateSessionResponse
|
||||
SignatureData
|
||||
SignedSoftwareCertificate
|
||||
CreateSessionResponse
|
||||
CreateSessionRequest
|
||||
EndpointDescription
|
||||
UserTokenPolicy
|
||||
UserTokenType
|
||||
GetEndpointsRequest
|
||||
GetEndpointsResponse
|
||||
PublishRequest
|
||||
PublishResponse
|
||||
FindServersRequest
|
||||
FindServersResponse
|
||||
SubscriptionAcknowledgement
|
||||
ReadRequest
|
||||
ReadResponse
|
||||
ReadValueId
|
||||
TimestampsToReturn
|
||||
WriteRequest
|
||||
WriteResponse
|
||||
WriteValue
|
||||
CreateMonitoredItemsResponse
|
||||
MonitoredItemCreateResult
|
||||
CreateMonitoredItemsRequest
|
||||
MonitoredItemCreateRequest
|
||||
MonitoringMode
|
||||
MonitoringParameters
|
||||
TranslateBrowsePathsToNodeIdsRequest
|
||||
TranslateBrowsePathsToNodeIdsResponse
|
||||
BrowsePath
|
||||
BrowsePathResult
|
||||
RelativePath
|
||||
BrowsePathTarget
|
||||
RelativePathElement
|
||||
BrowseResponse
|
||||
BrowseResult
|
||||
ReferenceDescription
|
||||
BrowseRequest
|
||||
ViewDescription
|
||||
BrowseNextRequest
|
||||
BrowseNextResponse
|
||||
DeleteSubscriptionsRequest
|
||||
DeleteSubscriptionsResponse
|
||||
BrowseDescription
|
||||
BrowseDirection
|
||||
AddNodesRequest
|
||||
AddNodesResponse
|
||||
AddNodesItem
|
||||
AddNodesResult
|
||||
AddReferencesRequest
|
||||
AddReferencesResponse
|
||||
AddReferencesItem
|
||||
BrowseResultMask
|
||||
ServerState
|
||||
ServerStatusDataType
|
||||
BuildInfo
|
||||
IdType
|
||||
NodeAttributes
|
||||
VariableAttributes
|
||||
ObjectAttributes
|
||||
ReferenceTypeAttributes
|
||||
ViewAttributes
|
||||
MethodAttributes
|
||||
ObjectTypeAttributes
|
||||
VariableTypeAttributes
|
||||
DataTypeAttributes
|
||||
NodeAttributesMask
|
||||
DeleteNodesItem
|
||||
DeleteNodesRequest
|
||||
DeleteNodesResponse
|
||||
DeleteReferencesItem
|
||||
DeleteReferencesRequest
|
||||
DeleteReferencesResponse
|
||||
RegisterNodesRequest
|
||||
RegisterNodesResponse
|
||||
UnregisterNodesRequest
|
||||
UnregisterNodesResponse
|
||||
UserIdentityToken
|
||||
UserNameIdentityToken
|
||||
AnonymousIdentityToken
|
||||
ServiceFault
|
||||
CallMethodRequest
|
||||
CallMethodResult
|
||||
CallResponse
|
||||
CallRequest
|
||||
Argument
|
||||
FilterOperator
|
||||
ContentFilterElement
|
||||
ContentFilter
|
||||
QueryDataDescription
|
||||
NodeTypeDescription
|
||||
QueryFirstRequest
|
||||
QueryDataSet
|
||||
ParsingResult
|
||||
ContentFilterElementResult
|
||||
ContentFilterResult
|
||||
QueryFirstResponse
|
||||
QueryNextRequest
|
||||
QueryNextResponse
|
||||
CreateSubscriptionRequest
|
||||
CreateSubscriptionResponse
|
||||
SetPublishingModeRequest
|
||||
SetPublishingModeResponse
|
||||
DeleteMonitoredItemsRequest
|
||||
DeleteMonitoredItemsResponse
|
||||
NotificationMessage
|
||||
MonitoredItemNotification
|
||||
DataChangeNotification
|
||||
ModifySubscriptionRequest
|
||||
ModifySubscriptionResponse
|
||||
RepublishRequest
|
||||
RepublishResponse
|
||||
MonitoredItemModifyRequest
|
||||
ModifyMonitoredItemsRequest
|
||||
MonitoredItemModifyResult
|
||||
ModifyMonitoredItemsResponse
|
11
tools/schema/datatypes_transport.txt
Normal file
11
tools/schema/datatypes_transport.txt
Normal file
@ -0,0 +1,11 @@
|
||||
MessageType
|
||||
ChunkType
|
||||
TcpMessageHeader
|
||||
TcpHelloMessage
|
||||
TcpAcknowledgeMessage
|
||||
SecureConversationMessageHeader
|
||||
AsymmetricAlgorithmSecurityHeader
|
||||
SymmetricAlgorithmSecurityHeader
|
||||
SequenceHeader
|
||||
SecureConversationMessageFooter
|
||||
SecureConversationMessageAbortBody
|
823
tools/schema/namespace0/Opc.Ua.NodeSet2.Minimal.xml
Normal file
823
tools/schema/namespace0/Opc.Ua.NodeSet2.Minimal.xml
Normal file
@ -0,0 +1,823 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<UANodeSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.02" LastModified="2013-03-06T05:36:44.0862658Z" xmlns="http://opcfoundation.org/UA/2011/03/UANodeSet.xsd">
|
||||
<Aliases>
|
||||
<Alias Alias="Boolean">i=1</Alias>
|
||||
<Alias Alias="SByte">i=2</Alias>
|
||||
<Alias Alias="Byte">i=3</Alias>
|
||||
<Alias Alias="Int16">i=4</Alias>
|
||||
<Alias Alias="UInt16">i=5</Alias>
|
||||
<Alias Alias="Int32">i=6</Alias>
|
||||
<Alias Alias="UInt32">i=7</Alias>
|
||||
<Alias Alias="Int64">i=8</Alias>
|
||||
<Alias Alias="UInt64">i=9</Alias>
|
||||
<Alias Alias="Float">i=10</Alias>
|
||||
<Alias Alias="Double">i=11</Alias>
|
||||
<Alias Alias="DateTime">i=13</Alias>
|
||||
<Alias Alias="String">i=12</Alias>
|
||||
<Alias Alias="ByteString">i=15</Alias>
|
||||
<Alias Alias="Guid">i=14</Alias>
|
||||
<Alias Alias="XmlElement">i=16</Alias>
|
||||
<Alias Alias="NodeId">i=17</Alias>
|
||||
<Alias Alias="ExpandedNodeId">i=18</Alias>
|
||||
<Alias Alias="QualifiedName">i=20</Alias>
|
||||
<Alias Alias="LocalizedText">i=21</Alias>
|
||||
<Alias Alias="StatusCode">i=19</Alias>
|
||||
<Alias Alias="Structure">i=22</Alias>
|
||||
<Alias Alias="Number">i=26</Alias>
|
||||
<Alias Alias="Integer">i=27</Alias>
|
||||
<Alias Alias="UInteger">i=28</Alias>
|
||||
<Alias Alias="HasComponent">i=47</Alias>
|
||||
<Alias Alias="HasProperty">i=46</Alias>
|
||||
<Alias Alias="Organizes">i=35</Alias>
|
||||
<Alias Alias="HasEventSource">i=36</Alias>
|
||||
<Alias Alias="HasNotifier">i=48</Alias>
|
||||
<Alias Alias="HasSubtype">i=45</Alias>
|
||||
<Alias Alias="HasTypeDefinition">i=40</Alias>
|
||||
<Alias Alias="HasModellingRule">i=37</Alias>
|
||||
<Alias Alias="HasEncoding">i=38</Alias>
|
||||
<Alias Alias="HasDescription">i=39</Alias>
|
||||
</Aliases>
|
||||
<UAReferenceType NodeId="i=31" BrowseName="References" IsAbstract="true" Symmetric="true">
|
||||
<DisplayName>References</DisplayName>
|
||||
<Description>The abstract base type for all references.</Description>
|
||||
<References />
|
||||
<InverseName>References</InverseName>
|
||||
</UAReferenceType>
|
||||
<UAReferenceType NodeId="i=45" BrowseName="HasSubtype">
|
||||
<DisplayName>HasSubtype</DisplayName>
|
||||
<Description>The type for non-looping hierarchical references that are used to define sub types.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=34</Reference>
|
||||
</References>
|
||||
<InverseName>HasSupertype</InverseName>
|
||||
</UAReferenceType>
|
||||
<UAReferenceType NodeId="i=33" BrowseName="HierarchicalReferences" IsAbstract="true">
|
||||
<DisplayName>HierarchicalReferences</DisplayName>
|
||||
<Description>The abstract base type for all hierarchical references.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=31</Reference>
|
||||
</References>
|
||||
<InverseName>HierarchicalReferences</InverseName>
|
||||
</UAReferenceType>
|
||||
<UAReferenceType NodeId="i=32" BrowseName="NonHierarchicalReferences" IsAbstract="true">
|
||||
<DisplayName>NonHierarchicalReferences</DisplayName>
|
||||
<Description>The abstract base type for all non-hierarchical references.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=31</Reference>
|
||||
</References>
|
||||
<InverseName>NonHierarchicalReferences</InverseName>
|
||||
</UAReferenceType>
|
||||
<UAReferenceType NodeId="i=34" BrowseName="HasChild">
|
||||
<DisplayName>HasChild</DisplayName>
|
||||
<Description>The abstract base type for all non-looping hierarchical references.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=33</Reference>
|
||||
</References>
|
||||
<InverseName>ChildOf</InverseName>
|
||||
</UAReferenceType>
|
||||
<UAReferenceType NodeId="i=35" BrowseName="Organizes">
|
||||
<DisplayName>Organizes</DisplayName>
|
||||
<Description>The type for hierarchical references that are used to organize nodes.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=33</Reference>
|
||||
</References>
|
||||
<InverseName>OrganizedBy</InverseName>
|
||||
</UAReferenceType>
|
||||
<UAReferenceType NodeId="i=36" BrowseName="HasEventSource">
|
||||
<DisplayName>HasEventSource</DisplayName>
|
||||
<Description>The type for non-looping hierarchical references that are used to organize event sources.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=33</Reference>
|
||||
</References>
|
||||
<InverseName>EventSourceOf</InverseName>
|
||||
</UAReferenceType>
|
||||
<UAReferenceType NodeId="i=37" BrowseName="HasModellingRule">
|
||||
<DisplayName>HasModellingRule</DisplayName>
|
||||
<Description>The type for references from instance declarations to modelling rule nodes.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=32</Reference>
|
||||
</References>
|
||||
<InverseName>ModellingRuleOf</InverseName>
|
||||
</UAReferenceType>
|
||||
<UAReferenceType NodeId="i=38" BrowseName="HasEncoding">
|
||||
<DisplayName>HasEncoding</DisplayName>
|
||||
<Description>The type for references from data type nodes to to data type encoding nodes.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=32</Reference>
|
||||
</References>
|
||||
<InverseName>EncodingOf</InverseName>
|
||||
</UAReferenceType>
|
||||
<UAReferenceType NodeId="i=39" BrowseName="HasDescription">
|
||||
<DisplayName>HasDescription</DisplayName>
|
||||
<Description>The type for references from data type encoding nodes to data type description nodes.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=32</Reference>
|
||||
</References>
|
||||
<InverseName>DescriptionOf</InverseName>
|
||||
</UAReferenceType>
|
||||
<UAReferenceType NodeId="i=40" BrowseName="HasTypeDefinition">
|
||||
<DisplayName>HasTypeDefinition</DisplayName>
|
||||
<Description>The type for references from a instance node its type defintion node.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=32</Reference>
|
||||
</References>
|
||||
<InverseName>TypeDefinitionOf</InverseName>
|
||||
</UAReferenceType>
|
||||
<UAReferenceType NodeId="i=41" BrowseName="GeneratesEvent">
|
||||
<DisplayName>GeneratesEvent</DisplayName>
|
||||
<Description>The type for references from a node to an event type that is raised by node.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=32</Reference>
|
||||
</References>
|
||||
<InverseName>GeneratesEvent</InverseName>
|
||||
</UAReferenceType>
|
||||
<UAReferenceType NodeId="i=44" BrowseName="Aggregates">
|
||||
<DisplayName>Aggregates</DisplayName>
|
||||
<Description>The type for non-looping hierarchical references that are used to aggregate nodes into complex types.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=34</Reference>
|
||||
</References>
|
||||
<InverseName>AggregatedBy</InverseName>
|
||||
</UAReferenceType>
|
||||
<UAReferenceType NodeId="i=46" BrowseName="HasProperty">
|
||||
<DisplayName>HasProperty</DisplayName>
|
||||
<Description>The type for non-looping hierarchical reference from a node to its property.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=44</Reference>
|
||||
</References>
|
||||
<InverseName>PropertyOf</InverseName>
|
||||
</UAReferenceType>
|
||||
<UAReferenceType NodeId="i=47" BrowseName="HasComponent">
|
||||
<DisplayName>HasComponent</DisplayName>
|
||||
<Description>The type for non-looping hierarchical reference from a node to its component.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=44</Reference>
|
||||
</References>
|
||||
<InverseName>ComponentOf</InverseName>
|
||||
</UAReferenceType>
|
||||
<UAReferenceType NodeId="i=48" BrowseName="HasNotifier">
|
||||
<DisplayName>HasNotifier</DisplayName>
|
||||
<Description>The type for non-looping hierarchical references that are used to indicate how events propagate from node to node.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=36</Reference>
|
||||
</References>
|
||||
<InverseName>NotifierOf</InverseName>
|
||||
</UAReferenceType>
|
||||
<UAReferenceType NodeId="i=49" BrowseName="HasOrderedComponent">
|
||||
<DisplayName>HasOrderedComponent</DisplayName>
|
||||
<Description>The type for non-looping hierarchical reference from a node to its component when the order of references matters.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=47</Reference>
|
||||
</References>
|
||||
<InverseName>OrderedComponentOf</InverseName>
|
||||
</UAReferenceType>
|
||||
<UAReferenceType NodeId="i=51" BrowseName="FromState">
|
||||
<DisplayName>FromState</DisplayName>
|
||||
<Description>The type for a reference to the state before a transition.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=32</Reference>
|
||||
</References>
|
||||
<InverseName>ToTransition</InverseName>
|
||||
</UAReferenceType>
|
||||
<UAReferenceType NodeId="i=52" BrowseName="ToState">
|
||||
<DisplayName>ToState</DisplayName>
|
||||
<Description>The type for a reference to the state after a transition.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=32</Reference>
|
||||
</References>
|
||||
<InverseName>FromTransition</InverseName>
|
||||
</UAReferenceType>
|
||||
<UAReferenceType NodeId="i=53" BrowseName="HasCause">
|
||||
<DisplayName>HasCause</DisplayName>
|
||||
<Description>The type for a reference to a method that can cause a transition to occur.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=32</Reference>
|
||||
</References>
|
||||
<InverseName>MayBeCausedBy</InverseName>
|
||||
</UAReferenceType>
|
||||
<UAReferenceType NodeId="i=54" BrowseName="HasEffect">
|
||||
<DisplayName>HasEffect</DisplayName>
|
||||
<Description>The type for a reference to an event that may be raised when a transition occurs.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=32</Reference>
|
||||
</References>
|
||||
<InverseName>MayBeEffectedBy</InverseName>
|
||||
</UAReferenceType>
|
||||
<UAReferenceType NodeId="i=56" BrowseName="HasHistoricalConfiguration">
|
||||
<DisplayName>HasHistoricalConfiguration</DisplayName>
|
||||
<Description>The type for a reference to the historical configuration for a data variable.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=44</Reference>
|
||||
</References>
|
||||
<InverseName>HistoricalConfigurationOf</InverseName>
|
||||
</UAReferenceType>
|
||||
|
||||
<UAObject NodeId="i=84" BrowseName="Root" SymbolicName="RootFolder">
|
||||
<DisplayName>Root</DisplayName>
|
||||
<Description>The root of the server address space.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=61</Reference>
|
||||
</References>
|
||||
</UAObject>
|
||||
<UAObject NodeId="i=85" BrowseName="Objects" SymbolicName="ObjectsFolder">
|
||||
<DisplayName>Objects</DisplayName>
|
||||
<Description>The browse entry point when looking for objects in the server address space.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="Organizes" IsForward="false">i=84</Reference>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=61</Reference>
|
||||
</References>
|
||||
</UAObject>
|
||||
<UAObject NodeId="i=86" BrowseName="Types" SymbolicName="TypesFolder">
|
||||
<DisplayName>Types</DisplayName>
|
||||
<Description>The browse entry point when looking for types in the server address space.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="Organizes" IsForward="false">i=84</Reference>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=61</Reference>
|
||||
</References>
|
||||
</UAObject>
|
||||
<UAObject NodeId="i=87" BrowseName="Views" SymbolicName="ViewsFolder">
|
||||
<DisplayName>Views</DisplayName>
|
||||
<Description>The browse entry point when looking for views in the server address space.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="Organizes" IsForward="false">i=84</Reference>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=61</Reference>
|
||||
</References>
|
||||
</UAObject>
|
||||
<UAObject NodeId="i=91" BrowseName="ReferenceTypes" SymbolicName="ReferenceTypesFolder">
|
||||
<DisplayName>ReferenceTypes</DisplayName>
|
||||
<Description>The browse entry point when looking for reference types in the server address space.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="Organizes" IsForward="false">i=86</Reference>
|
||||
<Reference ReferenceType="Organizes">i=31</Reference>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=61</Reference>
|
||||
</References>
|
||||
</UAObject>
|
||||
<UAObjectType NodeId="i=58" BrowseName="BaseObjectType">
|
||||
<DisplayName>BaseObjectType</DisplayName>
|
||||
<Description>The base type for all object nodes.</Description>
|
||||
<References />
|
||||
</UAObjectType>
|
||||
<UAObjectType NodeId="i=61" BrowseName="FolderType">
|
||||
<DisplayName>FolderType</DisplayName>
|
||||
<Description>The type for objects that organize other nodes.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=58</Reference>
|
||||
</References>
|
||||
</UAObjectType>
|
||||
<UAObjectType NodeId="i=2004" BrowseName="ServerType">
|
||||
<DisplayName>ServerType</DisplayName>
|
||||
<Description>Specifies the current status and capabilities of the server.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasProperty">i=2005</Reference>
|
||||
<Reference ReferenceType="HasProperty">i=2006</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2007</Reference>
|
||||
<Reference ReferenceType="HasProperty">i=2008</Reference>
|
||||
<Reference ReferenceType="HasProperty">i=2742</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2009</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2010</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2011</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2012</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=11527</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=11489</Reference>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=58</Reference>
|
||||
</References>
|
||||
</UAObjectType>
|
||||
<UAObjectType NodeId="i=2020" BrowseName="ServerDiagnosticsType">
|
||||
<DisplayName>ServerDiagnosticsType</DisplayName>
|
||||
<Description>The diagnostics information for a server.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasComponent">i=2021</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2022</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2023</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2744</Reference>
|
||||
<Reference ReferenceType="HasProperty">i=2025</Reference>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=58</Reference>
|
||||
</References>
|
||||
</UAObjectType>
|
||||
<UAObjectType NodeId="i=2013" BrowseName="ServerCapabilitiesType">
|
||||
<DisplayName>ServerCapabilitiesType</DisplayName>
|
||||
<Description>Describes the capabilities supported by the server.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasProperty">i=2014</Reference>
|
||||
<Reference ReferenceType="HasProperty">i=2016</Reference>
|
||||
<Reference ReferenceType="HasProperty">i=2017</Reference>
|
||||
<Reference ReferenceType="HasProperty">i=2732</Reference>
|
||||
<Reference ReferenceType="HasProperty">i=2733</Reference>
|
||||
<Reference ReferenceType="HasProperty">i=2734</Reference>
|
||||
<Reference ReferenceType="HasProperty">i=3049</Reference>
|
||||
<Reference ReferenceType="HasProperty">i=11549</Reference>
|
||||
<Reference ReferenceType="HasProperty">i=11550</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=11551</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2019</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2754</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=11562</Reference>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=58</Reference>
|
||||
</References>
|
||||
</UAObjectType>
|
||||
<UAVariableType NodeId="i=2138" BrowseName="ServerStatusType" DataType="i=862">
|
||||
<DisplayName>ServerStatusType</DisplayName>
|
||||
<References>
|
||||
<Reference ReferenceType="HasComponent">i=2139</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2140</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2141</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2142</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2752</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2753</Reference>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=63</Reference>
|
||||
</References>
|
||||
</UAVariableType>
|
||||
<UAVariableType NodeId="i=3051" BrowseName="BuildInfoType" DataType="i=338">
|
||||
<DisplayName>BuildInfoType</DisplayName>
|
||||
<References>
|
||||
<Reference ReferenceType="HasComponent">i=3052</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=3053</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=3054</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=3055</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=3056</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=3057</Reference>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=63</Reference>
|
||||
</References>
|
||||
</UAVariableType>
|
||||
|
||||
|
||||
<UAObject NodeId="i=90" BrowseName="DataTypes" SymbolicName="DataTypesFolder">
|
||||
<DisplayName>DataTypes</DisplayName>
|
||||
<Description>The browse entry point when looking for data types in the server address space.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="Organizes" IsForward="false">i=86</Reference>
|
||||
<Reference ReferenceType="Organizes">i=24</Reference>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=61</Reference>
|
||||
</References>
|
||||
</UAObject>
|
||||
<UADataType NodeId="i=24" BrowseName="BaseDataType" IsAbstract="true">
|
||||
<DisplayName>BaseDataType</DisplayName>
|
||||
<Description>Describes a value that can have any valid DataType.</Description>
|
||||
<References />
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=1" BrowseName="Boolean">
|
||||
<DisplayName>Boolean</DisplayName>
|
||||
<Description>Describes a value that is either TRUE or FALSE.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=24</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=26" BrowseName="Number" IsAbstract="true">
|
||||
<DisplayName>Number</DisplayName>
|
||||
<Description>Describes a value that can have any numeric DataType.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=24</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=10" BrowseName="Float">
|
||||
<DisplayName>Float</DisplayName>
|
||||
<Description>Describes a value that is an IEEE 754-1985 single precision floating point number.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=26</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=11" BrowseName="Double">
|
||||
<DisplayName>Double</DisplayName>
|
||||
<Description>Describes a value that is an IEEE 754-1985 double precision floating point number.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=26</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=27" BrowseName="Integer" IsAbstract="true">
|
||||
<DisplayName>Integer</DisplayName>
|
||||
<Description>Describes a value that can have any integer DataType.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=26</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=2" BrowseName="SByte">
|
||||
<DisplayName>SByte</DisplayName>
|
||||
<Description>Describes a value that is an integer between -128 and 127.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=27</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=4" BrowseName="Int16">
|
||||
<DisplayName>Int16</DisplayName>
|
||||
<Description>Describes a value that is an integer between −32,768 and 32,767.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=27</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=6" BrowseName="Int32">
|
||||
<DisplayName>Int32</DisplayName>
|
||||
<Description>Describes a value that is an integer between −2,147,483,648 and 2,147,483,647.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=27</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=8" BrowseName="Int64">
|
||||
<DisplayName>Int64</DisplayName>
|
||||
<Description>Describes a value that is an integer between −9,223,372,036,854,775,808 and 9,223,372,036,854,775,807.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=27</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=28" BrowseName="UInteger" IsAbstract="true">
|
||||
<DisplayName>UInteger</DisplayName>
|
||||
<Description>Describes a value that can have any unsigned integer DataType.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=27</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=3" BrowseName="Byte">
|
||||
<DisplayName>Byte</DisplayName>
|
||||
<Description>Describes a value that is an integer between 0 and 255.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=28</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=5" BrowseName="UInt16">
|
||||
<DisplayName>UInt16</DisplayName>
|
||||
<Description>Describes a value that is an integer between 0 and 65535.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=28</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=7" BrowseName="UInt32">
|
||||
<DisplayName>UInt32</DisplayName>
|
||||
<Description>Describes a value that is an integer between 0 and 4,294,967,295.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=28</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=9" BrowseName="UInt64">
|
||||
<DisplayName>UInt64</DisplayName>
|
||||
<Description>Describes a value that is an integer between 0 and 18,446,744,073,709,551,615.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=28</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=12" BrowseName="String">
|
||||
<DisplayName>String</DisplayName>
|
||||
<Description>Describes a value that is a sequence of printable Unicode characters.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=24</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=13" BrowseName="DateTime">
|
||||
<DisplayName>DateTime</DisplayName>
|
||||
<Description>Describes a value that is a Gregorian calender date and time.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=24</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=14" BrowseName="Guid">
|
||||
<DisplayName>Guid</DisplayName>
|
||||
<Description>Describes a value that is a 128-bit globally unique identifier.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=24</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=15" BrowseName="ByteString">
|
||||
<DisplayName>ByteString</DisplayName>
|
||||
<Description>Describes a value that is a sequence of bytes.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=24</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=16" BrowseName="XmlElement">
|
||||
<DisplayName>XmlElement</DisplayName>
|
||||
<Description>Describes a value that is an XML element.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=24</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=17" BrowseName="NodeId">
|
||||
<DisplayName>NodeId</DisplayName>
|
||||
<Description>Describes a value that is an identifier for a node within a Server address space.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=24</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=18" BrowseName="ExpandedNodeId">
|
||||
<DisplayName>ExpandedNodeId</DisplayName>
|
||||
<Description>Describes a value that is an absolute identifier for a node.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=24</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=19" BrowseName="StatusCode">
|
||||
<DisplayName>StatusCode</DisplayName>
|
||||
<Description>Describes a value that is a code representing the outcome of an operation by a Server.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=24</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=20" BrowseName="QualifiedName">
|
||||
<DisplayName>QualifiedName</DisplayName>
|
||||
<Description>Describes a value that is a name qualified by a namespace.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=24</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=21" BrowseName="LocalizedText">
|
||||
<DisplayName>LocalizedText</DisplayName>
|
||||
<Description>Describes a value that is human readable Unicode text with a locale identifier.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=24</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=22" BrowseName="Structure" IsAbstract="true">
|
||||
<DisplayName>Structure</DisplayName>
|
||||
<Description>Describes a value that is any type of structure that can be described with a data encoding.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=24</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=862" BrowseName="ServerStatusDataType">
|
||||
<DisplayName>ServerStatusDataType</DisplayName>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=22</Reference>
|
||||
</References>
|
||||
<Definition Name="ServerStatusDataType">
|
||||
<Field Name="StartTime" DataType="i=294" />
|
||||
<Field Name="CurrentTime" DataType="i=294" />
|
||||
<Field Name="State" DataType="i=852" />
|
||||
<Field Name="BuildInfo" DataType="i=338" />
|
||||
<Field Name="SecondsTillShutdown" DataType="i=7" />
|
||||
<Field Name="ShutdownReason" DataType="i=21" />
|
||||
</Definition>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=338" BrowseName="BuildInfo">
|
||||
<DisplayName>BuildInfo</DisplayName>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=22</Reference>
|
||||
</References>
|
||||
<Definition Name="BuildInfo">
|
||||
<Field Name="ProductUri" DataType="i=12" />
|
||||
<Field Name="ManufacturerName" DataType="i=12" />
|
||||
<Field Name="ProductName" DataType="i=12" />
|
||||
<Field Name="SoftwareVersion" DataType="i=12" />
|
||||
<Field Name="BuildNumber" DataType="i=12" />
|
||||
<Field Name="BuildDate" DataType="i=294" />
|
||||
</Definition>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=23" BrowseName="DataValue">
|
||||
<DisplayName>DataValue</DisplayName>
|
||||
<Description>Describes a value that is a structure containing a value, a status code and timestamps.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=24</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=25" BrowseName="DiagnosticInfo">
|
||||
<DisplayName>DiagnosticInfo</DisplayName>
|
||||
<Description>Describes a value that is a structure containing diagnostics associated with a StatusCode.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=24</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=29" BrowseName="Enumeration" IsAbstract="true">
|
||||
<DisplayName>Enumeration</DisplayName>
|
||||
<Description>Describes a value that is an enumerated DataType.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=24</Reference>
|
||||
</References>
|
||||
</UADataType>
|
||||
<UADataType NodeId="i=852" BrowseName="ServerState">
|
||||
<DisplayName>ServerState</DisplayName>
|
||||
<References>
|
||||
<Reference ReferenceType="HasProperty">i=7612</Reference>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=29</Reference>
|
||||
</References>
|
||||
<Definition Name="ServerState">
|
||||
<Field Name="Running" Value="0" />
|
||||
<Field Name="Failed" Value="1" />
|
||||
<Field Name="NoConfiguration" Value="2" />
|
||||
<Field Name="Suspended" Value="3" />
|
||||
<Field Name="Shutdown" Value="4" />
|
||||
<Field Name="Test" Value="5" />
|
||||
<Field Name="CommunicationFault" Value="6" />
|
||||
<Field Name="Unknown" Value="7" />
|
||||
</Definition>
|
||||
</UADataType>
|
||||
<UAObject NodeId="i=89" BrowseName="VariableTypes" SymbolicName="VariableTypesFolder">
|
||||
<DisplayName>VariableTypes</DisplayName>
|
||||
<Description>The browse entry point when looking for variable types in the server address space.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="Organizes" IsForward="false">i=86</Reference>
|
||||
<Reference ReferenceType="Organizes">i=62</Reference>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=61</Reference>
|
||||
</References>
|
||||
</UAObject>
|
||||
<UAVariableType NodeId="i=62" BrowseName="BaseVariableType" IsAbstract="true" ValueRank="-2">
|
||||
<DisplayName>BaseVariableType</DisplayName>
|
||||
<Description>The abstract base type for all variable nodes.</Description>
|
||||
<References />
|
||||
</UAVariableType>
|
||||
<UAVariableType NodeId="i=63" BrowseName="BaseDataVariableType" ValueRank="-2">
|
||||
<DisplayName>BaseDataVariableType</DisplayName>
|
||||
<Description>The type for variable that represents a process value.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=62</Reference>
|
||||
</References>
|
||||
</UAVariableType>
|
||||
<UAVariableType NodeId="i=68" BrowseName="PropertyType" ValueRank="-2">
|
||||
<DisplayName>PropertyType</DisplayName>
|
||||
<Description>The type for variable that represents a property of another node.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasSubtype" IsForward="false">i=62</Reference>
|
||||
</References>
|
||||
</UAVariableType>
|
||||
|
||||
|
||||
<UAObject NodeId="i=2253" BrowseName="Server" EventNotifier="1">
|
||||
<DisplayName>Server</DisplayName>
|
||||
<References>
|
||||
<Reference ReferenceType="HasProperty">i=2254</Reference>
|
||||
<Reference ReferenceType="HasProperty">i=2255</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2256</Reference>
|
||||
<Reference ReferenceType="HasProperty">i=2267</Reference>
|
||||
<Reference ReferenceType="HasProperty">i=2994</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2268</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2274</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2295</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2296</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=11715</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=11492</Reference>
|
||||
<Reference ReferenceType="Organizes" IsForward="false">i=85</Reference>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=2004</Reference>
|
||||
</References>
|
||||
</UAObject>
|
||||
<UAVariable NodeId="i=2255" BrowseName="NamespaceArray" ParentNodeId="i=2253" DataType="String" ValueRank="1" MinimumSamplingInterval="1000">
|
||||
<DisplayName>NamespaceArray</DisplayName>
|
||||
<Description>The list of namespace URIs used by the server.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=68</Reference>
|
||||
<Reference ReferenceType="HasProperty" IsForward="false">i=2253</Reference>
|
||||
</References>
|
||||
</UAVariable>
|
||||
<UAVariable NodeId="i=2254" BrowseName="ServerArray" ParentNodeId="i=2253" DataType="String" ValueRank="1" MinimumSamplingInterval="1000">
|
||||
<DisplayName>ServerArray</DisplayName>
|
||||
<Description>The list of server URIs used by the server.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=68</Reference>
|
||||
<Reference ReferenceType="HasProperty" IsForward="false">i=2253</Reference>
|
||||
</References>
|
||||
</UAVariable>
|
||||
<UAObject NodeId="i=2268" BrowseName="ServerCapabilities" ParentNodeId="i=2253">
|
||||
<DisplayName>ServerCapabilities</DisplayName>
|
||||
<Description>Describes capabilities supported by the server.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasProperty">i=2269</Reference>
|
||||
<Reference ReferenceType="HasProperty">i=2271</Reference>
|
||||
<Reference ReferenceType="HasProperty">i=2272</Reference>
|
||||
<Reference ReferenceType="HasProperty">i=2735</Reference>
|
||||
<Reference ReferenceType="HasProperty">i=2736</Reference>
|
||||
<Reference ReferenceType="HasProperty">i=2737</Reference>
|
||||
<Reference ReferenceType="HasProperty">i=3704</Reference>
|
||||
<Reference ReferenceType="HasProperty">i=11702</Reference>
|
||||
<Reference ReferenceType="HasProperty">i=11703</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=11704</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2996</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2997</Reference>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=2013</Reference>
|
||||
<Reference ReferenceType="HasComponent" IsForward="false">i=2253</Reference>
|
||||
</References>
|
||||
</UAObject>
|
||||
<UAVariable NodeId="i=2271" BrowseName="LocaleIdArray" ParentNodeId="i=2268" DataType="i=295" ValueRank="1">
|
||||
<DisplayName>LocaleIdArray</DisplayName>
|
||||
<Description>A list of locales supported by the server.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=68</Reference>
|
||||
<Reference ReferenceType="HasProperty" IsForward="false">i=2268</Reference>
|
||||
</References>
|
||||
</UAVariable>
|
||||
<UAVariable NodeId="i=2735" BrowseName="MaxBrowseContinuationPoints" ParentNodeId="i=2268" DataType="UInt16">
|
||||
<DisplayName>MaxBrowseContinuationPoints</DisplayName>
|
||||
<Description>The maximum number of continuation points for Browse operations per session.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=68</Reference>
|
||||
<Reference ReferenceType="HasProperty" IsForward="false">i=2268</Reference>
|
||||
</References>
|
||||
</UAVariable>
|
||||
<UAObject NodeId="i=2274" BrowseName="ServerDiagnostics" ParentNodeId="i=2253">
|
||||
<DisplayName>ServerDiagnostics</DisplayName>
|
||||
<Description>Reports diagnostics about the server.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasComponent">i=2275</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2289</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2290</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=3706</Reference>
|
||||
<Reference ReferenceType="HasProperty">i=2294</Reference>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=2020</Reference>
|
||||
<Reference ReferenceType="HasComponent" IsForward="false">i=2253</Reference>
|
||||
</References>
|
||||
</UAObject>
|
||||
<UAVariable NodeId="i=2294" BrowseName="EnabledFlag" ParentNodeId="i=2274" DataType="Boolean" AccessLevel="3" UserAccessLevel="3">
|
||||
<DisplayName>EnabledFlag</DisplayName>
|
||||
<Description>If TRUE the diagnostics collection is enabled.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=68</Reference>
|
||||
<Reference ReferenceType="HasProperty" IsForward="false">i=2274</Reference>
|
||||
</References>
|
||||
</UAVariable>
|
||||
<UAVariable NodeId="i=2256" BrowseName="ServerStatus" ParentNodeId="i=2253" DataType="i=862" MinimumSamplingInterval="1000">
|
||||
<DisplayName>ServerStatus</DisplayName>
|
||||
<Description>The current status of the server.</Description>
|
||||
<References>
|
||||
<Reference ReferenceType="HasComponent">i=2257</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2258</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2259</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2260</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2992</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2993</Reference>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=2138</Reference>
|
||||
<Reference ReferenceType="HasComponent" IsForward="false">i=2253</Reference>
|
||||
</References>
|
||||
</UAVariable>
|
||||
<UAVariable NodeId="i=2257" BrowseName="StartTime" ParentNodeId="i=2256" DataType="i=294">
|
||||
<DisplayName>StartTime</DisplayName>
|
||||
<References>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=63</Reference>
|
||||
<Reference ReferenceType="HasComponent" IsForward="false">i=2256</Reference>
|
||||
</References>
|
||||
</UAVariable>
|
||||
<UAVariable NodeId="i=2258" BrowseName="CurrentTime" ParentNodeId="i=2256" DataType="i=294">
|
||||
<DisplayName>CurrentTime</DisplayName>
|
||||
<References>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=63</Reference>
|
||||
<Reference ReferenceType="HasComponent" IsForward="false">i=2256</Reference>
|
||||
</References>
|
||||
</UAVariable>
|
||||
<UAVariable NodeId="i=2259" BrowseName="State" ParentNodeId="i=2256" DataType="i=852">
|
||||
<DisplayName>State</DisplayName>
|
||||
<References>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=63</Reference>
|
||||
<Reference ReferenceType="HasComponent" IsForward="false">i=2256</Reference>
|
||||
</References>
|
||||
</UAVariable>
|
||||
<UAVariable NodeId="i=2260" BrowseName="BuildInfo" ParentNodeId="i=2256" DataType="i=338">
|
||||
<DisplayName>BuildInfo</DisplayName>
|
||||
<References>
|
||||
<Reference ReferenceType="HasComponent">i=2262</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2263</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2261</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2264</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2265</Reference>
|
||||
<Reference ReferenceType="HasComponent">i=2266</Reference>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=3051</Reference>
|
||||
<Reference ReferenceType="HasComponent" IsForward="false">i=2256</Reference>
|
||||
</References>
|
||||
</UAVariable>
|
||||
<UAVariable NodeId="i=2262" BrowseName="ProductUri" ParentNodeId="i=2260" DataType="String" MinimumSamplingInterval="1000">
|
||||
<DisplayName>ProductUri</DisplayName>
|
||||
<References>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=63</Reference>
|
||||
<Reference ReferenceType="HasComponent" IsForward="false">i=2260</Reference>
|
||||
</References>
|
||||
</UAVariable>
|
||||
<UAVariable NodeId="i=2263" BrowseName="ManufacturerName" ParentNodeId="i=2260" DataType="String" MinimumSamplingInterval="1000">
|
||||
<DisplayName>ManufacturerName</DisplayName>
|
||||
<References>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=63</Reference>
|
||||
<Reference ReferenceType="HasComponent" IsForward="false">i=2260</Reference>
|
||||
</References>
|
||||
</UAVariable>
|
||||
<UAVariable NodeId="i=2261" BrowseName="ProductName" ParentNodeId="i=2260" DataType="String" MinimumSamplingInterval="1000">
|
||||
<DisplayName>ProductName</DisplayName>
|
||||
<References>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=63</Reference>
|
||||
<Reference ReferenceType="HasComponent" IsForward="false">i=2260</Reference>
|
||||
</References>
|
||||
</UAVariable>
|
||||
<UAVariable NodeId="i=2264" BrowseName="SoftwareVersion" ParentNodeId="i=2260" DataType="String" MinimumSamplingInterval="1000">
|
||||
<DisplayName>SoftwareVersion</DisplayName>
|
||||
<References>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=63</Reference>
|
||||
<Reference ReferenceType="HasComponent" IsForward="false">i=2260</Reference>
|
||||
</References>
|
||||
</UAVariable>
|
||||
<UAVariable NodeId="i=2265" BrowseName="BuildNumber" ParentNodeId="i=2260" DataType="String" MinimumSamplingInterval="1000">
|
||||
<DisplayName>BuildNumber</DisplayName>
|
||||
<References>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=63</Reference>
|
||||
<Reference ReferenceType="HasComponent" IsForward="false">i=2260</Reference>
|
||||
</References>
|
||||
</UAVariable>
|
||||
<UAVariable NodeId="i=2266" BrowseName="BuildDate" ParentNodeId="i=2260" DataType="i=294" MinimumSamplingInterval="1000">
|
||||
<DisplayName>BuildDate</DisplayName>
|
||||
<References>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=63</Reference>
|
||||
<Reference ReferenceType="HasComponent" IsForward="false">i=2260</Reference>
|
||||
</References>
|
||||
</UAVariable>
|
||||
<UAVariable NodeId="i=2992" BrowseName="SecondsTillShutdown" ParentNodeId="i=2256" DataType="UInt32">
|
||||
<DisplayName>SecondsTillShutdown</DisplayName>
|
||||
<References>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=63</Reference>
|
||||
<Reference ReferenceType="HasComponent" IsForward="false">i=2256</Reference>
|
||||
</References>
|
||||
</UAVariable>
|
||||
<UAVariable NodeId="i=2993" BrowseName="ShutdownReason" ParentNodeId="i=2256" DataType="LocalizedText">
|
||||
<DisplayName>ShutdownReason</DisplayName>
|
||||
<References>
|
||||
<Reference ReferenceType="HasTypeDefinition">i=63</Reference>
|
||||
<Reference ReferenceType="HasComponent" IsForward="false">i=2256</Reference>
|
||||
</References>
|
||||
</UAVariable>
|
||||
</UANodeSet>
|
17057
tools/schema/namespace0/Opc.Ua.NodeSet2.xml
Normal file
17057
tools/schema/namespace0/Opc.Ua.NodeSet2.xml
Normal file
File diff suppressed because it is too large
Load Diff
3
tools/schema/namespace0/README.md
Normal file
3
tools/schema/namespace0/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
This directory contains XML nodesets of namespace 0 for automatic generation.
|
||||
The generation option can be activated via CMake option ENABLE_GENERATE_NAMESPACE0.
|
||||
The nodesets can be selected via CMake variable GENERATE_NAMESPACE0_FILE.
|
Loading…
x
Reference in New Issue
Block a user