学习open62541 --- [28] NodeSet释义

NodeSet就是节点集合的意思,NodeSet可以提供一套设置好的节点,用户可以直接拿来使用,不用自己去重新创建,每个NodeSet有一个自己的NameSpace。

本文主要讲述NodeSet在open62541里是如何起作用的以及使用方法。


一 open62541默认提供的NodeSet

打开open62541源码根目录下的CMakeLists.txt,找到如下语句

set(UA_NAMESPACE_ZERO "REDUCED" CACHE STRING "Completeness of the generated namespace zero (minimal/reduced/full)")
SET_PROPERTY(CACHE UA_NAMESPACE_ZERO PROPERTY STRINGS "MINIMAL" "REDUCED" "FULL")

可以看到变量UA_NAMESPACE_ZERO的值默认是REDUCED。此时在build目录下执行cmake .. && make去生成open62541相关文件,生成完毕后,我们回到源码根目录下执行下面命令,

grep nodeset_compiler.py -r ./*

因为NodeSet必须经过nodeset_compiler.py这个工具去转成C代码,然后才能使用,这个工具位置是open62541/tools/nodeset_compiler/

经过grep查找,我们找到如下语句,这是CMake生成的编译指令,
在这里插入图片描述
图片有点看不清,其种关键语句如下,

/usr/bin/python /home/wh/work/opcua/encryp/open62541/tools/nodeset_compiler/nodeset_compiler.py --internal-headers --ignore=/home/wh/work/opcua/encryp/open62541/tools/nodeset_compiler/NodeID_NS0_Base.txt --xml=/home/wh/work/opcua/encryp/open62541/tools/schema/Opc.Ua.NodeSet2.Minimal.xml /home/wh/work/opcua/encryp/open62541/build/src_generated/open62541/namespace0_generated

其种–xml参数后面跟的是open62541/tools/schema/Opc.Ua.NodeSet2.Minimal.xml,这个就是open62541默认提供的NodeSet,从名字可以看出是阉割版的(Minimal),如下,
在这里插入图片描述
最终会在open62541/build/src_generated/open62541/下生成namespace0_generated.c和namespace0_generated.h
在这里插入图片描述
这2个文件提供了一个函数,

UA_StatusCode namespace0_generated(UA_Server *server);

这个函数的主要功能就是把Opc.Ua.NodeSet2.Minimal.xml里描述的NodeSet添加到OPC UA Server里,这个函数最后会在UA_Server_new()里调用,调用顺序如下,

UA_Server_new() -> UA_Server_init() -> UA_Server_initNS0() ->namespace0_generated()

最终的调用代码如下,从注释也可以看出其来源
在这里插入图片描述
如果选择MINIMAL(之前默认选择的是REDUCED),那么就会调用上图中的UA_Server_minimalServerObject()去手动创建最少量的NodeSet,这就不需要使用nodeset_compiler.py去解析xml文件了,也就不需要xml文件了。


二 添加自定义NodeSet

这个如果看过这篇这篇文章的话,就很容易理解了。

我们使用建模软件去创建的就是自定义的NodeSet,但是这里有个很重要的点需要知道:NodeSet之间有依赖关系

有的NodeSet负责提供大家都会用到的Node,如Opc.Ua.NodeSet2.xml,有的NodeSet负责提供某一领域的Node,如Opc.Ua.Di.NodeSet2.xml,后者就会依赖前者,这样的好处就是可以让结构更加清晰,做专业领域的可以专心在自己的领域里。

当我们自定义NodeSet时,需要依赖Opc.Ua.NodeSet2.xml,这个NodeSet提供了一个基础。此时,open62541默认提供的阉割版NodeSet就无法满足需要了,需要使用完全版的(因为是自定义,所以不知道用户到底会使用基础NodeSet里的哪些部分,干脆就要求你使用完全版,这样Opc.Ua.NodeSet2.Minimal.xml就不适用了)。

使用完全版的基础NodeSet

首先把UA_NAMESPACE_ZERO的值改为FULL,然后在open62541源码根目录下执行下面命令,

git submodule update --init

这个命令会去下载2样东西,一个是mdns相关的库代码(用于LDS和LDS-ME),另一个就是nodeset,位置在open62541/deps/ua-nodeset/,
在这里插入图片描述
Opc.Ua.NodeSet2.xml位于Schema目录下,
在这里插入图片描述
打开这个文件,在开头处可以看到对于Model的描述,其中比较关键的参数是ModelUri,

  <Models>
    <Model ModelUri="http://opcfoundation.org/UA/" Version="1.04" PublicationDate="2019-05-01T00:00:00Z" />
  </Models>

三 添加专业方向的NodeSet

在open62541/deps/ua-nodeset/下除了Schema目录外,还有很多其它目录,这些就是专业方向的NodeSet,例如PLCopen,POWERLINK等。

当我们需要某个或某几个专业方向的NodeSet时,就可以把它们添加到OPC UA Server里来,具体操作如下,这里以PLCopen为例:

  1. 打开PLCopen目录,找到Opc.Ua.Plc.NodeSet2.xml,然后打开并找到Models标签,
    在这里插入图片描述
    可以看到PLCopen的ModelURI是http://PLCopen.org/OpcUa/IEC61131-3/,这个NodeSet依赖另外2个NodeSet,即http://opcfoundation.org/UA/http://opcfoundation.org/UA/DI/

  2. 打开DI目录,找到Opc.Ua.Di.NodeSet2.xml,然后打开并找到Models标签,
    在这里插入图片描述
    这样我们就搞清楚NodeSet之间的依赖关系了,即PLCopen依赖UA和DI,DI依赖UA

  3. 使用nodeset_compiler.py去编译DI和PLCopen,

    /usr/bin/python /home/wh/work/opcua/encryp/open62541/tools/nodeset_compiler/nodeset_compiler.py --existing  /home/wh/work/opcua/encryp/open62541/deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml  --xml=/home/wh/work/opcua/encryp/open62541/deps/ua-nodeset/DI/Opc.Ua.Di.NodeSet2.xml /home/wh/work/opcua/encryp/open62541/build/src_generated/open62541/namespace_di
    
    /usr/bin/python /home/wh/work/opcua/encryp/open62541/tools/nodeset_compiler/nodeset_compiler.py --existing  /home/wh/work/opcua/encryp/open62541/deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml  --existing  /home/wh/work/opcua/encryp/open62541/deps/ua-nodeset/DI/Opc.Ua.Di.NodeSet2.xml --xml=/home/wh/work/opcua/encryp/open62541/deps/ua-nodeset/PLCopen/Opc.Ua.Plc.NodeSet2.xml  /home/wh/work/opcua/encryp/open62541/build/src_generated/open62541/namespace_plcopen
    

    命令里的路径需要根据自己的实际情况进行修改,这里使用的是绝对路径,也可以使用相对路径。另外,命令里使用的existing参数用来指示依赖的NodeSet,可以看到PLCopen使用了2个existing参数。
    最终会生成namespace_di.c/.h和namespace_plcopen.c/.h,如何添加到Server里,请参考这篇文章的第三节,其实和自定义NodeSet是一样的。

OPC基金会还提供了很多其它的NodeSet,如Robotics,这个可以去github上下载,网址是https://github.com/OPCFoundation/UA-Nodeset

为了保证稳定性,请选择Release版本进行下载,下载解压后可以放到open62541/deps/ua-nodeset/下,这个操作也可以用来更新现有的NodeSet。


四 小tips

NodeSet名称

前面看到NodeSet的描述都是在xml文件里,而且这个xml文件最后名称都是NodeSet2,关于这个,可以在https://github.com/OPCFoundation/UA-Nodeset网页上看下ReadMe,
在这里插入图片描述

xml文件内容解读

NodeSet使用一个xml文件进行描述,那么这个xml内容如何解读呢?可以参考官方文档OPC UA Part 6 - Mappings里的Annex F

NodeSet的NameSpace index

每个NodeSet都有一个NameSpace Index,这个和添加顺序有关,UA是基础NodeSet,一定会被第一个添加,所以其NameSpace Index是0,后面再添加的就顺序加1

但是有时不知道添加顺序,就不知道其NameSpace Index,可以使用下面的代码去获取

UA_UInt16 ns = UA_Server_addNamespace(server, "http://PLCopen.org/OpcUa/IEC61131-3/");

该函数的第二个参数就是NodeSet对应的xml文件里的ModelUri,另外这个函数可以重复调用,不会造成重复添加。

这也解释了之前使用建模工具时定义的namespace index不起作用的原因,虽然在建模工具里指定了namespace index,但添加到server里后index变了,这是因为index是由添加顺序决定,所以推荐使用UA_Server_addNamespace()去重新确定一下index


五 总结

本文主要讲述了NodeSet的意义以及在open62541里如何使用,知晓了NodeSet,就可以随意添加任意的NodeSet。

如果有写的不对的地方,希望能留言指正,谢谢阅读。

猜你喜欢

转载自blog.csdn.net/whahu1989/article/details/105747384