open62541 (R 1.1.2)中文文档 (译文)第四篇 (11 - 13)

本文介绍OPC-UA中的PubSub功能及其配置选项,包括不同实时级别的特性及限制。同时,深入探讨了使用Python编写的XML节点集编译器如何帮助开发者将信息模型转化为实际应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

open62541(R 1.1.2) 文档

*注:原文PDF文档 是从官网下载的 Linux64bit的发布版本中自带的文档,原PDF中的源代码用PDF浏览器查看,有残缺。需要结合源文件中的示例代码进行相应的修改。或参考其它版本的文档。原文代码中的注释并没有译文,这个在使用时再补充进去。
第一篇 章节 一 至 五

第二篇 章节 六

第三篇 章节 七 至 十

第四篇 章节 十一 至 十三

11 通用定义

客户机、服务器和PubSub的通用定义

11.1 Attribute Id

OPC UA信息模型中的每个节点都包含取决于节点类型的属性。可能的属性如下:

typedef enum {
	UA_ATTRIBUTEID_NODEID = 1,
	UA_ATTRIBUTEID_NODECLASS = 2,
	UA_ATTRIBUTEID_BROWSENAME = 3,
	UA_ATTRIBUTEID_DISPLAYNAME = 4,
	UA_ATTRIBUTEID_DESCRIPTION = 5,
	UA_ATTRIBUTEID_WRITEMASK = 6,
	UA_ATTRIBUTEID_USERWRITEMASK = 7,
	UA_ATTRIBUTEID_ISABSTRACT = 8,
	UA_ATTRIBUTEID_SYMMETRIC = 9,
	UA_ATTRIBUTEID_INVERSENAME = 10,
	UA_ATTRIBUTEID_CONTAINSNOLOOPS = 11,
	UA_ATTRIBUTEID_EVENTNOTIFIER = 12,
	UA_ATTRIBUTEID_VALUE = 13,
	UA_ATTRIBUTEID_DATATYPE = 14,
	UA_ATTRIBUTEID_VALUERANK = 15,
	UA_ATTRIBUTEID_ARRAYDIMENSIONS = 16,
	UA_ATTRIBUTEID_ACCESSLEVEL = 17,
	UA_ATTRIBUTEID_USERACCESSLEVEL = 18,
	UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL = 19,
	UA_ATTRIBUTEID_HISTORIZING = 20,
	UA_ATTRIBUTEID_EXECUTABLE = 21,
	UA_ATTRIBUTEID_USEREXECUTABLE = 22,
	UA_ATTRIBUTEID_DATATYPEDEFINITION = 23
} UA_AttributeId;

11.2 Access Level Masks

对节点的访问级别由以下常量给定,这些常量与总体访问级别的 AND。

#define UA_ACCESSLEVELMASK_READ (0x01u << 0u)
#define UA_ACCESSLEVELMASK_WRITE (0x01u << 1u)
#define UA_ACCESSLEVELMASK_HISTORYREAD (0x01u << 2u)
#define UA_ACCESSLEVELMASK_HISTORYWRITE (0x01u << 3u)
#define UA_ACCESSLEVELMASK_SEMANTICCHANGE (0x01u << 4u)
#define UA_ACCESSLEVELMASK_STATUSWRITE (0x01u << 5u)
#define UA_ACCESSLEVELMASK_TIMESTAMPWRITE (0x01u << 6u)

11.3 Write Masks

写入掩码和用户写入掩码由以下常量给定,这些常量是总体写入掩码的 AND。

#define UA_WRITEMASK_ACCESSLEVEL (0x01u << 0u)
#define UA_WRITEMASK_ARRRAYDIMENSIONS (0x01u << 1u)
#define UA_WRITEMASK_BROWSENAME (0x01u << 2u)
#define UA_WRITEMASK_CONTAINSNOLOOPS (0x01u << 3u)
#define UA_WRITEMASK_DATATYPE (0x01u << 4u)
#define UA_WRITEMASK_DESCRIPTION (0x01u << 5u)
#define UA_WRITEMASK_DISPLAYNAME (0x01u << 6u)
#define UA_WRITEMASK_EVENTNOTIFIER (0x01u << 7u)
#define UA_WRITEMASK_EXECUTABLE (0x01u << 8u)
#define UA_WRITEMASK_HISTORIZING (0x01u << 9u)
#define UA_WRITEMASK_INVERSENAME (0x01u << 10u)
#define UA_WRITEMASK_ISABSTRACT (0x01u << 11u)
#define UA_WRITEMASK_MINIMUMSAMPLINGINTERVAL (0x01u << 12u)
#define UA_WRITEMASK_NODECLASS (0x01u << 13u)
#define UA_WRITEMASK_NODEID (0x01u << 14u)
#define UA_WRITEMASK_SYMMETRIC (0x01u << 15u)
#define UA_WRITEMASK_USERACCESSLEVEL (0x01u << 16u)
#define UA_WRITEMASK_USEREXECUTABLE (0x01u << 17u)
#define UA_WRITEMASK_USERWRITEMASK (0x01u << 18u)
#define UA_WRITEMASK_VALUERANK (0x01u << 19u)
#define UA_WRITEMASK_WRITEMASK (0x01u << 20u)
#define UA_WRITEMASK_VALUEFORVARIABLETYPE (0x01u << 21u)

11.4 ValueRanks

以下是变量、变量类型和方法参数最常用的ValueRanks。级别(值小于3,但高于普通值)

#define UA_VALUERANK_SCALAR_OR_ONE_DIMENSION -3
#define UA_VALUERANK_ANY -2
#define UA_VALUERANK_SCALAR -1
#define UA_VALUERANK_ONE_OR_MORE_DIMENSIONS 0
#define UA_VALUERANK_ONE_DIMENSION 1
#define UA_VALUERANK_TWO_DIMENSIONS 2
#define UA_VALUERANK_THREE_DIMENSIONS 3

11.5 Rule Handling

规则处理设置定义了如何处理由OPC UA规范中的规则引起的错误案例。规则处理可以被软化,例如,解决行为不当的实施,或减轻OPC UA规范后续版本中引入的附加规则的影响。

typedef enum {
		UA_RULEHANDLING_DEFAULT = 0,
		UA_RULEHANDLING_ABORT, /* Abort the operation and return an error code */
		UA_RULEHANDLING_WARN, /* Print a message in the logs and continue */
		UA_RULEHANDLING_ACCEPT, /* Continue and disregard the broken rule */
} UA_RuleHandling;

11.6 Order

排序枚举用于在元素之间建立绝对顺序。

typedef enum {
		UA_ORDER_LESS = -1,
		UA_ORDER_EQ = 0,
		UA_ORDER_MORE = 1
} UA_Order;

11.7 Connection State

typedef enum {
		UA_SECURECHANNELSTATE_CLOSED,
		UA_SECURECHANNELSTATE_HEL_SENT,
		UA_SECURECHANNELSTATE_HEL_RECEIVED,
		UA_SECURECHANNELSTATE_ACK_SENT,
		UA_SECURECHANNELSTATE_ACK_RECEIVED,
		UA_SECURECHANNELSTATE_OPN_SENT,
		UA_SECURECHANNELSTATE_OPEN,
		UA_SECURECHANNELSTATE_CLOSING
} UA_SecureChannelState;
typedef enum {
		UA_SESSIONSTATE_CLOSED,
		UA_SESSIONSTATE_CREATE_REQUESTED,
		UA_SESSIONSTATE_CREATED,
		UA_SESSIONSTATE_ACTIVATE_REQUESTED,
		UA_SESSIONSTATE_ACTIVATED,
		UA_SESSIONSTATE_CLOSING
} UA_SessionState;

11.8 Statistic counters

以下层的堆栈管理统计计数器:

  • 网络
  • 安全通道
  • 会议
    会话层计数器与OPC UA Part 5规范中定义的ServerDiagnosticsSummaryDataType的计数器匹配。其他层的计数器不是由OPC UA指定的,但如果可能,与会话层计数器协调。
typedef struct {
	size_t currentConnectionCount;
	size_t cumulatedConnectionCount;
	size_t rejectedConnectionCount;
	size_t connectionTimeoutCount;
	size_t connectionAbortCount;
} UA_NetworkStatistics;
typedef struct {
	size_t currentChannelCount;
	size_t cumulatedChannelCount;
	size_t rejectedChannelCount;
	size_t channelTimeoutCount; /* only used by servers */
	11.6. Order 189open62541 Documentation, Release 1.1.2
	size_t channelAbortCount;
	size_t channelPurgeCount; /* only used by servers */
} UA_SecureChannelStatistics;
typedef struct {
	size_t currentSessionCount;
	size_t cumulatedSessionCount;
	size_t securityRejectedSessionCount; /* only used by servers */
	size_t rejectedSessionCount;
	size_t sessionTimeoutCount; /* only used by servers */
	size_t sessionAbortCount; /* only used by servers */
} UA_SessionStatistics;

11.9 Endpoint URL Parser

端点URL解析器通常用于实现网络层插件。

/* Split the given endpoint url into hostname, port and path. All arguments must
* be non-NULL. EndpointUrls have the form "opc.tcp://hostname:port/path", port
* and path may be omitted (together with the prefix colon and slash).
* *
@param endpointUrl The endpoint URL.
* @param outHostname Set to the parsed hostname. The string points into the
* original endpointUrl, so no memory is allocated. If an IPv6 address is
* given, hostname contains e.g. ’[2001:0db8:85a3::8a2e:0370:7334]’
* @param outPort Set to the port of the url or left unchanged.
* @param outPath Set to the path if one is present in the endpointUrl.
* Starting or trailing ’/’ are NOT included in the path. The string
* points into the original endpointUrl, so no memory is allocated.
* @return Returns UA_STATUSCODE_BADTCPENDPOINTURLINVALID if parsing failed. */
UA_StatusCode
UA_parseEndpointUrl(const UA_String* endpointUrl, UA_String* outHostname,
	UA_UInt16* outPort, UA_String* outPath);
/* Split the given endpoint url into hostname, vid and pcp. All arguments must
* be non-NULL. EndpointUrls have the form "opc.eth://<host>[:<VID>[.PCP]]".
* The host is a MAC address, an IP address or a registered name like a
* hostname. The format of a MAC address is six groups of hexadecimal digits,
* separated by hyphens (e.g. 01-23-45-67-89-ab). A system may also accept
* hostnames and/or IP addresses if it provides means to resolve it to a MAC
* address (e.g. DNS and Reverse-ARP).
* *
Note: currently only parsing MAC address is supported.
* *
@param endpointUrl The endpoint URL.
* @param vid Set to VLAN ID.
* @param pcp Set to Priority Code Point.
* @return Returns UA_STATUSCODE_BADINTERNALERROR if parsing failed. */
UA_StatusCode
UA_parseEndpointUrlEthernet(const UA_String* endpointUrl, UA_String* target,
	UA_UInt16* vid, UA_Byte* pcp);
/* Convert given byte string to a positive number. Returns the number of valid
* digits. Stops if a non-digit char is found and returns the number of digits
* up to that point. */
size_t
UA_readNumber(const UA_Byte* buf, size_t buflen, UA_UInt32* number);
/* Same as UA_ReadNumber but with a base parameter */
size_t
UA_readNumberWithBase(const UA_Byte* buf, size_t buflen,
	UA_UInt32 * number, UA_Byte base);
#ifndef UA_MIN
#define UA_MIN(A,B) (A > B ? B : A)
#endif
#ifndef UA_MAX
#define UA_MAX(A,B) (A > B ? A : B)
#endif

11.10 Parse RelativePath Expressions

根据第4部分A2中定义的格式解析RelativePath。例如,用于BrowsePath结构。目前,只识别来自命名空间0的标准引用类型(请参阅第3部分)

RelativePath := ( ReferenceType [BrowseName]? )*

引用类型具有以下格式之一:

  • /: 层次引用和子类型
  • .: 聚合参考类型和子类型
  • < [!#] * BrowseName >:ReferenceType由其BrowseName(限定名)指示。前缀修饰符可以如下所示:! 切换到反向引用。# 排除ReferenceType的子类型。
    限定名称由可选的命名空间索引和名称本身组成:
QualifiedName := ([0-9]+ ":")? Name

RelativePaths的限定名表示使用 & 作为转义符。字符 /.<>:#!& 在限定名中必须转义(前缀为 &)。

11.10.1 Example RelativePaths

  • /2:Block&.Output
  • /3:Truck.0:NodeVersion
  • <0:HasProperty>1:Boiler/1:HeatSensor
  • <0:HasChild>2:Wheel
  • <#Aggregates>1:Boiler/
  • <!HasChild>Truck
  • < HasChild >
#ifdef UA_ENABLE_PARSING
UA_StatusCode
UA_RelativePath_parse(UA_RelativePath *rp, const UA_String str);
#endif

11.11 Convenience macros for complex types

复杂类型的便利宏

#define UA_PRINTF_GUID_FORMAT "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"
#define UA_PRINTF_GUID_DATA(GUID) (GUID).data1, (GUID).data2, (GUID).data3, \
(GUID).data4[0], (GUID).data4[1], (GUID).data4[2], (GUID).data4[3], \
(GUID).data4[4], (GUID).data4[5], (GUID).data4[6], (GUID).data4[7]
#define UA_PRINTF_STRING_FORMAT "\"%.*s\""
#define UA_PRINTF_STRING_DATA(STRING) (int)(STRING).length, (STRING).data

11.12 Helper functions for converting data types

用于转换数据类型的助手函数

/* Converts a bytestring to the corresponding base64 representation */
UA_DEPRECATED static UA_INLINE UA_StatusCode
UA_ByteString_toBase64String(const UA_ByteString* byteString,
	UA_String* str) {
	return UA_ByteString_toBase64(byteString, str);
}
/*Converts a node id to the corresponding string representation.
* It can be one of :
*-Numeric : ns = 0; i = 123
* -String: ns = 0; s = Some String
* -Guid: ns = 0; g = A123456C - 0ABC - 1A2B - 815F - 687212AAEE1B
* -ByteString: ns = 0; b = AA == */
UA_DEPRECATED static UA_INLINE UA_StatusCode
UA_NodeId_toString(const UA_NodeId * nodeId, UA_String * nodeIdStr) {
	return UA_NodeId_print(nodeId, nodeIdStr);
}
/*Compare memory in constant time to mitigate timing attacks.
* Returns true if ptr1and ptr2 are equal for length bytes.*/
static UA_INLINE UA_Boolean
UA_constantTimeEqual(const void* ptr1, const void* ptr2, size_t length) {
	volatile const UA_Byte* a = (volatile const UA_Byte*)ptr1;
	volatile const UA_Byte* b = (volatile const UA_Byte*)ptr2;
	volatile UA_Byte c = 0;
	for (size_t i = 0; i < length; ++i) {
		UA_Byte x = a[i], y = b[i];
		c |= x ^ y;
	}
	return !c;
}

12 XML节点集编译器

在编写应用程序时,使用一些GUI工具创建信息模型更为方便。大多数工具可以根据OPC-UA节点集XML模式导出数据。open62541包含一个基于python的nodeset编译器,它可以将这些信息模型定义转换为一个工作的服务器。

请注意,您可以在tools/nodeset_ compiler子文件夹中找到的nodeset编译器不是一个XML转换工具,而是一个编译器。这意味着它将在解析XML文件时创建一个内部表示,并尝试理解和验证该表示的正确性,以便生成C代码。

12.1入门

我们将以下信息模型片段作为以下教程的起点。关于如何创建自己的信息模型和 NodeSet2.xml 的更详细的教程可以在这个博客中找到发布:https://opcua.rocks/custom-information-models/

<UANodeSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:uax="http://opcfoundation.org/UA/2008/02/Types.xsd"
xmlns="http://opcfoundation.org/UA/2011/03/UANodeSet.xsd"
xmlns:s1="http://yourorganisation.org/example_nodeset/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <NamespaceUris>
    <Uri>http://yourorganisation.org/example_nodeset/</Uri>
  </NamespaceUris>
  <Aliases>
    <Alias Alias="Boolean">i=1</Alias>
    <Alias Alias="UInt32">i=7</Alias>
    <Alias Alias="String">i=12</Alias>
    <Alias Alias="HasModellingRule">i=37</Alias>
    <Alias Alias="HasTypeDefinition">i=40</Alias>
    <Alias Alias="HasSubtype">i=45</Alias>
    <Alias Alias="HasProperty">i=46</Alias>
    <Alias Alias="HasComponent">i=47</Alias>
    <Alias Alias="Argument">i=296</Alias>
  </Aliases>
  <Extensions>
    <Extension>
      <ModelInfo Tool="UaModeler" Hash="Zs8w1AQI71W8P/GOk3k/xQ=="
      Version="1.3.4"/>
    </Extension>
  </Extensions>
  <UAReferenceType NodeId="ns=1;i=4001" BrowseName="1:providesInputTo">
    <DisplayName>providesInputTo</DisplayName>
    <References>
      <Reference ReferenceType="HasSubtype" IsForward="false">
        i=33
      </Reference>
    </References>
    <InverseName Locale="en-US">inputProcidedBy</InverseName>
  </UAReferenceType>
  <UAObjectType IsAbstract="true" NodeId="ns=1;i=1001"
  BrowseName="1:FieldDevice">
    <DisplayName>FieldDevice</DisplayName>
    <References>
      <Reference ReferenceType="HasSubtype" IsForward="false">
        i=58
      </Reference>
      <Reference ReferenceType="HasComponent">ns=1;i=6001</Reference>
      <Reference ReferenceType="HasComponent">ns=1;i=6002</Reference>
    </References>
  </UAObjectType>
  <UAVariable DataType="String" ParentNodeId="ns=1;i=1001"
  NodeId="ns=1;i=6001" BrowseName="1:ManufacturerName"
  UserAccessLevel="3" AccessLevel="3">
    <DisplayName>ManufacturerName</DisplayName>
    <References>
      <Reference ReferenceType="HasTypeDefinition">i=63</Reference>
      <Reference ReferenceType="HasModellingRule">i=78</Reference>
      <Reference ReferenceType="HasComponent" IsForward="false">
        ns=1;i=1001
      </Reference>
    </References>
  </UAVariable>
  <UAVariable DataType="String" ParentNodeId="ns=1;i=1001"
  NodeId="ns=1;i=6002" BrowseName="1:ModelName"
  UserAccessLevel="3" AccessLevel="3">
    <DisplayName>ModelName</DisplayName>
    <References>
      <Reference ReferenceType="HasTypeDefinition">i=63</Reference>
      <Reference ReferenceType="HasModellingRule">i=78</Reference>
      <Reference ReferenceType="HasComponent" IsForward="false">
        ns=1;i=1001
      </Reference>
    </References>
  </UAVariable>
  <UAObjectType NodeId="ns=1;i=1002" BrowseName="1:Pump">
    <DisplayName>Pump</DisplayName>
    <References>
      <Reference ReferenceType="HasComponent">ns=1;i=6003</Reference>
      <Reference ReferenceType="HasComponent">ns=1;i=6004</Reference>
      <Reference ReferenceType="HasSubtype" IsForward="false">
        ns=1;i=1001
      </Reference>
      <Reference ReferenceType="HasComponent">ns=1;i=7001</Reference>
      <Reference ReferenceType="HasComponent">ns=1;i=7002</Reference>
    </References>
  </UAObjectType>
  <UAVariable DataType="Boolean" ParentNodeId="ns=1;i=1002"
  NodeId="ns=1;i=6003" BrowseName="1:isOn" UserAccessLevel="3"
  AccessLevel="3">
    <DisplayName>isOn</DisplayName>
    <References>
      <Reference ReferenceType="HasTypeDefinition">i=63</Reference>
      <Reference ReferenceType="HasModellingRule">i=78</Reference>
      <Reference ReferenceType="HasComponent" IsForward="false">
        ns=1;i=1002
      </Reference>
    </References>
  </UAVariable>
  <UAVariable DataType="UInt32" ParentNodeId="ns=1;i=1002"
  NodeId="ns=1;i=6004" BrowseName="1:MotorRPM"
  UserAccessLevel="3" AccessLevel="3">
    <DisplayName>MotorRPM</DisplayName>
    <References>
      <Reference ReferenceType="HasTypeDefinition">i=63</Reference>
      <Reference ReferenceType="HasModellingRule">i=78</Reference>
      <Reference ReferenceType="HasComponent" IsForward="false">
        ns=1;i=1002
      </Reference>
    </References>
  </UAVariable>
  <UAMethod ParentNodeId="ns=1;i=1002" NodeId="ns=1;i=7001"
  BrowseName="1:startPump">
    <DisplayName>startPump</DisplayName>
    <References>
      <Reference ReferenceType="HasModellingRule">i=78</Reference>
      <Reference ReferenceType="HasProperty">ns=1;i=6005</Reference>
      <Reference ReferenceType="HasComponent" IsForward="false">
        ns=1;i=1002
      </Reference>
    </References>
  </UAMethod>
  <UAVariable DataType="Argument" ParentNodeId="ns=1;i=7001" ValueRank="1"
  NodeId="ns=1;i=6005" ArrayDimensions="1"
  BrowseName="OutputArguments">
    <DisplayName>OutputArguments</DisplayName>
    <References>
      <Reference ReferenceType="HasModellingRule">i=78</Reference>
      <Reference ReferenceType="HasProperty"
      IsForward="false">ns=1;i=7001</Reference>
      <Reference ReferenceType="HasTypeDefinition">i=68</Reference>
    </References>
    <Value>
      <ListOfExtensionObject>
        <ExtensionObject>
          <TypeId>
            <Identifier>i=297</Identifier>
          </TypeId>
          <Body>
            <Argument>
              <Name>started</Name>
              <DataType>
                <Identifier>i=1</Identifier>
              </DataType>
              <ValueRank>-1</ValueRank>
              <ArrayDimensions></ArrayDimensions>
              <Description/>
            </Argument>
          </Body>
        </ExtensionObject>
      </ListOfExtensionObject>
    </Value>
  </UAVariable>
  <UAMethod ParentNodeId="ns=1;i=1002" NodeId="ns=1;i=7002"
  BrowseName="1:stopPump">
    <DisplayName>stopPump</DisplayName>
    <References>
      <Reference ReferenceType="HasModellingRule">i=78</Reference>
      <Reference ReferenceType="HasProperty">ns=1;i=6006</Reference>
      <Reference ReferenceType="HasComponent"
      IsForward="false">ns=1;i=1002</Reference>
    </References>
  </UAMethod>
  <UAVariable DataType="Argument" ParentNodeId="ns=1;i=7002" ValueRank="1"
  NodeId="ns=1;i=6006" ArrayDimensions="1"
  BrowseName="OutputArguments">
    <DisplayName>OutputArguments</DisplayName>
    <References>
      <Reference ReferenceType="HasModellingRule">i=78</Reference>
      <Reference ReferenceType="HasProperty" IsForward="false">
        ns=1;i=7002
      </Reference>
      <Reference ReferenceType="HasTypeDefinition">i=68</Reference>
    </References>
    <Value>
      <ListOfExtensionObject>
        <ExtensionObject>
          <TypeId>
            <Identifier>i=297</Identifier>
          </TypeId>
          <Body>
            <Argument>
              <Name>stopped</Name>
              <DataType>
                <Identifier>i=1</Identifier>
              </DataType>
              <ValueRank>-1</ValueRank>
              <ArrayDimensions></ArrayDimensions>
              <Description/>
            </Argument>
          </Body>
        </ExtensionObject>
      </ListOfExtensionObject>
    </Value>
  </UAVariable>
</UANodeSet>

获取上一个代码段并将其保存到文件中myNS.xml. 要将这个nodeset编译成相应的C代码(open62541堆栈可以使用这些代码),nodeset编译器在调用它时需要一些参数。help命令的输出提供以下信息:

$ python . / nodeset_compiler.py - h
usage : nodeset_compiler.py[-h][-e <existingNodeSetXML>][-x <nodeSetXML>]
							[--internal - headers]
							[-b <blacklistFile>][-i <ignoreFile>]
							[-t <typesArray>]
							[-v]
							<outputFile>
positional arguments :
<outputFile> The path / basename for the <output file>.cand <output
			file>.h files to be generated.This will also be the
			function name used in the headerand c - file.
optional arguments :
	-h, --help show this help messageand exit
	- e <existingNodeSetXML>, --existing <existingNodeSetXML>
							NodeSet XML files with nodes that are already present
							on the server.
	- x <nodeSetXML>, --xml <nodeSetXML>
							NodeSet XML files with nodes that shall be generated.
	--internal - headers Include internal headers instead of amalgamated header
	- b <blacklistFile>, --blacklist <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 nodeset prior to
							compilation.Any references to these nodes will also
							be removed
	- i <ignoreFile>, --ignore <ignoreFile>
							Loads a list of NodeIDs stored in ignoreFile(one
								NodeID per line).Any of the nodeIds encountered in
							this file will be kept in the nodestore but not
							printed in the generated code
	- t <typesArray>, --types - array <typesArray>
							Types array for the given namespace.Can be used
							mutliple times to define(in the same order as the
								.xml files, first for --existing, then --xml) the type
							arrays
	--max - string - length MAX_STRING_LENGTH
							Maximum allowed length of a string literal.If longer,
							it will be set to an empty string
	- v, --verbose Make the script more verbose.Can be applied up to 4
		times

因此结果调用如下所示:

$ python ./nodeset_compiler.py --types-array=UA_TYPES --existing ../../deps/ua-nodeset/Schema/Opc.

以及命令的输出:

INFO:__main__:Preprocessing (existing) ../../deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml
INFO:__main__:Preprocessing myNS.xml
INFO:__main__:Generating Code
INFO:__main__:NodeSet generation code successfully printed

第一个参数 --types-array=UA_TYPES 定义open62541中全局数组的名称,其中包含NodeSet2.xml中nodeset中使用的相应类型。如果不自己定义数据类型,则始终可以使用UA_TYPES值。在本教程后面的部分中会有更多的介绍。下一个参数–existing …/…/deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml 指向标准定义的命名空间0(NS0)的xml定义。假定命名空间0已预先加载并提供定义数据类型、引用类型等。因为在myNS.xml我们需要告诉nodeset编译器它也应该加载该nodeset,但不能将其编译到输出中。请注意,您可能需要初始化git子模块以获取deps/ua-nodeset文件夹(git submodule update–init)或手动下载完整的NodeSet2.xml。参数 --xml myNS.xml 指向用户定义的信息模型,其节点将被添加到抽象语法树中。然后脚本将创建文件myNS.c和myNS.h(由最后一个参数myNS指示),其中包含实例化这些名称空间所需的 c 代码。
虽然以这种方式运行编译器是可能的,但这是非常不可取的。如果你想检查 CMakeLists.txt 文件(examples/nodeset/CMakeLists.txt),您将发现文件 server_nodeset.xml 使用以下函数编译:

ua_generate_nodeset(
		NAME "example"
		FILE "${PROJECT_SOURCE_DIR}/examples/nodeset/server_nodeset.xml"
		DEPENDS_TYPES "UA_TYPES"
		DEPENDS_NS "${UA_FILE_NS0}"
)

如果您查看nodeset编译器生成的文件,您将看到它生成了一个名为extern UA_StatusCode myNS(UA_Server*Server);。您需要包含头文件和源文件,然后在使用UA_server_new创建服务器实例后立即调用 myNS(server) 方法。这将自动将所有节点添加到服务器,并在没有任何错误的情况下返回UA_STATUSCODE_GOOD。另外,您需要在CMake中设置UA_NAMESPACE_ZERO=FULL,用完整的NS0编译open62541堆栈。否则,堆栈使用一个子集,其中没有包含许多节点,因此添加自定义节点集可能会失败。
这就是如何使用nodeset编译器编译open62541堆栈使用的简单nodeset xml。
为了您的方便和更简单的使用,我们还提供了一个CMake函数,它进一步简化了ua_generate_datatypes 和 ua_generate_nodeset 函数的使用。强烈建议使用此函数:ua_generate_nodeset_and_datatypes。它使用一些最佳实践设置,您只需要传递一个名称、名称空间索引 NAMESPACE_IDX (如上所述)和nodeset文件。传递.csv和.bsd文件是可选的,如果未指定,将跳过为该注释集生成数据类型。还可以使用DEPENDS参数定义节点集之间的依赖关系。
以下是 DI 和 PLCOpen 节点集的一些示例:

#Generate types and namespace for DI
ua_generate_nodeset_and_datatypes(
		NAME "di"
		FILE_CSV "${PROJECT_SOURCE_DIR}/deps/ua-nodeset/DI/OpcUaDiModel.csv"
		FILE_BSD "${PROJECT_SOURCE_DIR}/deps/ua-nodeset/DI/Opc.Ua.Di.Types.bsd"
		NAMESPACE_IDX 2
		FILE_NS "${PROJECT_SOURCE_DIR}/deps/ua-nodeset/DI/Opc.Ua.Di.NodeSet2.xml"
)
#generate PLCopen namespace which is using DI
ua_generate_nodeset_and_datatypes(
		NAME "plc"
		#PLCopen does not define custom types. Only generate the nodeset
		FILE_NS "${PROJECT_SOURCE_DIR}/deps/ua-nodeset/PLCopen/Opc.Ua.Plc.NodeSet2.xml"
		#PLCopen depends on the di nodeset, which must be generated before
		DEPENDS "di"
)

12.2创建对象实例

定义对象类型的一个主要好处是能够相当容易地创建对象实例。当 NodeId指向有效的ObjectType节点时,将自动处理对象实例化。对象类型定义中包含的所有属性和方法都将与对象节点一起实例化。
虽然变量是从objetType定义复制的(例如允许用户将新的数据源附加到它们上),但是方法总是只链接的。这个范例与C++语言相同:调用的方法总是相同的代码,但是第一个参数是指向对象的指针。同样,在OPC-UA中,一个特定的methodNode只能附加一个methodCallback。如果调用了该methodNode,父对象ID将传递给该方法-此时取消划分它所属的对象实例是methods作业。
让我们看一个示例,该示例将创建一个泵实例,该实例给定myNS.xml:

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
* See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
#include <signal.h>
#include <stdio.h>
#include "open62541.h"
/* Files myNS.h and myNS.c are created from myNS.xml */
#include "myNS.h"
UA_Boolean running = true;
static void stopHandler(int sign) {
	UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
	running = false;
}
int main(int argc, char** argv) {
	signal(SIGINT, stopHandler);
	signal(SIGTERM, stopHandler);
	UA_ServerConfig * config = UA_ServerConfig_new_default();
	UA_Server* server = UA_Server_new(config);
	UA_StatusCode retval;
	/* create nodes from nodeset */
	if (myNS(server) != UA_STATUSCODE_GOOD) {
		UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Could not add the example nodeset. "
			"Check previous output for any error.");
		retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
	}
	else {
		UA_NodeId createdNodeId;
		UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
		object_attr.description = UA_LOCALIZEDTEXT("en-US", "A pump!");
		object_attr.displayName = UA_LOCALIZEDTEXT("en-US", "Pump1");
		// we assume that the myNS nodeset was added in namespace 2.
		// You should always use UA_Server_addNamespace to check what the
		// namespace index is for a given namespace URI. UA_Server_addNamespace
		// will just return the index if it is already added.
		UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 0),
			UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
			UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
			UA_QUALIFIEDNAME(1, "Pump1"),
			UA_NODEID_NUMERIC(2, 1002),
			object_attr, NULL, &createdNodeId);
		retval = UA_Server_run(server, &running);
	}
	UA_Server_delete(server);
	UA_ServerConfig_delete(config);
	return (int)retval;
}

确保您已经更新了项目中的头和库,然后重新编译并运行服务器。特别要确保你已经将myNS.h添加到你的include文件夹中
如您所见,实例化一个对象与创建一个对象节点没有多大区别。主要区别在于必须使用objectType节点作为typeDefinition。
如果您启动服务器并使用UA Expert检查节点,您将在objects文件夹中找到泵,该文件夹如下所示::numref:‘nodeset-compiler-pump‘
如您所见,泵继承了它的父属性(ManufacturerName和ModelName)。与对象和变量不同的是,方法从不被克隆,而只被链接起来。原因是您很可能会将方法回调附加到一个中心方法,而不是每个对象。如果对象位于创建的对象之下,则对象将被实例化,因此作为泵一部分的任何对象(如名为ServerType的associatedServer的对象)也将被实例化。对象之上的对象永远不会被实例化,因此Fielddevices中的同一个ServerType对象也会被省略(原因是递归实例化函数保护自己不受无限递归的影响,这种递归在第一次升序,然后重新升华到树中时很难跟踪)。

12.3多节点集的组合

在前面的部分中,您已经看到了如何使用nodeset编译器,它依赖于默认nodeset(NS0)的单个Opc.Ua.NodeSet2.xml。节点集编译器还支持多个节点集。我们将用PLCopen节点集展示这个用例。PLCopen 节点集Opc.Ua.Plc.NodeSet2.xml 依赖于DI nodeset Opc.Ua.Di.NodeSet2.xml ,它依赖于NS0。此示例也显示在 examples/nodeset/CMakeLists.txt 文件.这个DI nodeset使用deps/ua-nodeset/DI/Opc.Ua.Di.Types.bsd 中的一些附加数据类型. 因为我们在生成的代码中也需要这些类型,所以我们首先需要将这些类型编译成C代码。生成的代码主要是对编码和解码所需类型的二进制表示的定义。生成可以使用 ua_generate_datatypes CMake函数完成,该函数使用

#tools/generate_datatypes.py script:
ua_generate_datatypes(
		NAME "ua_types_di"
		TARGET_SUFFIX "types-di"
		NAMESPACE_IDX 2
		FILE_CSV "${PROJECT_SOURCE_DIR}/deps/ua-nodeset/DI/OpcUaDiModel.csv"
		FILES_BSD "${PROJECT_SOURCE_DIR}/deps/ua-nodeset/DI/Opc.Ua.Di.Types.bsd"
)

NAMESPACE_IDX参数指示为类型定义生成的节点id的命名空间索引。目前,我们需要依赖于名称空间也被添加到最终服务器的这个位置。目前还没有自动推断(热烈欢迎拉取请求)。CSV和BSD文件包含类型的元数据和定义。用于创建后缀名为TARGET_SUFFIX 的 open62541-generator-TARGET_SUFFIX。
现在可以使用以下命令编译 DI nodeset XML:

ua_generate_nodeset(
	NAME "di"
	FILE "${PROJECT_SOURCE_DIR}/deps/ua-nodeset/DI/Opc.Ua.Di.NodeSet2.xml"
	TYPES_ARRAY "UA_TYPES_DI"
	INTERNAL
	DEPENDS_TYPES "UA_TYPES"
	DEPENDS_NS "${PROJECT_SOURCE_DIR}/deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml"
	DEPENDS_TARGET "open62541-generator-types-di"
)

现在有两个新的论点:
INTERNAL指示生成的源代码中应包含内部头(和非公共API)。这是当前使用结构作为数据值的节点集所必需的,并且可能在将来被修复。DEPENDS_TYPES 数组参数与节点集匹配的顺序与它们在 DEPENDS_TARGET 参数上出现的顺序相同。它告诉nodeset编译器它应该使用哪个类型数组: Opc.Ua.NodeSet2.xml 的 UA_TYPES 和 Opc.Ua.Di.NodeSet2.xml 的 UA_TYPES_DI。generate_datatypes.py 生成类型数组的脚本。其余部分与上一节中的示例类似:Opc.Ua.NodeSet2.xml 假定已经存在,只需加载以进行一致性检查,Opc.Ua.Di.NodeSet2.xml 将在输出文件 ua_namespace_di.c/.h 中生成
接下来我们可以生成PLCopen节点集。因为它不需要任何额外的数据类型定义,所以我们可以立即从nodeset编译器命令开始:

ua_generate_nodeset(
	NAME "plc"
	FILE "${PROJECT_SOURCE_DIR}/deps/ua-nodeset/PLCopen/Opc.Ua.Plc.NodeSet2.xml"
	INTERNAL
	DEPENDS_TYPES
		"UA_TYPES" "UA_TYPES_DI"
	DEPENDS_NS
		"${PROJECT_SOURCE_DIR}/deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml"
		"${PROJECT_SOURCE_DIR}/deps/ua-nodeset/DI/Opc.Ua.Di.NodeSet2.xml"
	DEPENDS_TARGET "open62541-generator-ns-di"
)

这个调用非常类似于DI nodeset的编译。如您所见,我们没有为PLCopen节点集定义任何特定的类型数组。由于PLCopen nodeset依赖于NS0和DI nodeset,我们需要告诉nodeset编译器这两个nodeset应该被视为已经存在。确保顺序与XML文件中的顺序相同,例如,在本例中,顺序是 Opc.Ua.Plc.NodeSet2.xml -> UANodeSet -> Models -> Model.
由于前面的脚本,您将拥有多个源文件:

  • ua_types_di_generated.c
  • ua_types_di_generated.h
  • ua_types_di_generated_encoding_binary.h
  • ua_types_di_generated_handling.h
  • ua_namespace_di.c
  • ua_namespace_di.h
  • ua_namespace_plc.c
  • ua_namespace_plc.h
    最后,您需要在构建过程中包括所有这些文件,并为节点集调用相应的初始化方法。示例应用程序如下所示:
UA_ServerConfig* config = UA_ServerConfig_new_default();
UA_Server* server = UA_Server_new(config);
/* create nodes from nodeset */
UA_StatusCode retval = ua_namespace_di(server);
if (retval != UA_STATUSCODE_GOOD) {
	UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Adding the DI namespace failed. Please che"
		UA_Server_delete(server);
	UA_ServerConfig_delete(config);
	return (int)UA_STATUSCODE_BADUNEXPECTEDERROR;
}
retval |= ua_namespace_plc(server);
if (retval != UA_STATUSCODE_GOOD) {
	UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Adding the PLCopen namespace failed. Pleas"
		UA_Server_delete(server);
	UA_ServerConfig_delete(config);
	return (int)UA_STATUSCODE_BADUNEXPECTEDERROR;
}
retval = UA_Server_run(server, &running);

13 内部构件

13.1 状态代码

状态码广泛用于OPC UA协议和open62541 API中。它们由StatusCode数据类型表示。以下定义来至于标准.OPC UA文件Opc.Ua.StatusCodes.csv 。

/* These StatusCodes are manually generated. */
#define UA_STATUSCODE_GOOD 0x00
#define UA_STATUSCODE_INFOTYPE_DATAVALUE 0x00000400
#define UA_STATUSCODE_INFOBITS_OVERFLOW 0x00000080
/* An unexpected error occurred. */
#define UA_STATUSCODE_BADUNEXPECTEDERROR 0x80010000
/* An internal error occurred as a result of a programming or configuration error. */
#define UA_STATUSCODE_BADINTERNALERROR 0x80020000
/* Not enough memory to complete the operation. */
#define UA_STATUSCODE_BADOUTOFMEMORY 0x80030000
/* An operating system resource is not available. */
#define UA_STATUSCODE_BADRESOURCEUNAVAILABLE 0x80040000
/* A low level communication error occurred. */
#define UA_STATUSCODE_BADCOMMUNICATIONERROR 0x80050000
/* Encoding halted because of invalid data in the objects being serialized. */
#define UA_STATUSCODE_BADENCODINGERROR 0x80060000
/* Decoding halted because of invalid data in the stream. */
#define UA_STATUSCODE_BADDECODINGERROR 0x80070000
/* The message encoding/decoding limits imposed by the stack have been exceeded. */
#define UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED 0x80080000
/* The request message size exceeds limits set by the server. */
#define UA_STATUSCODE_BADREQUESTTOOLARGE 0x80B80000
/* The response message size exceeds limits set by the client. */
#define UA_STATUSCODE_BADRESPONSETOOLARGE 0x80B90000
/* An unrecognized response was received from the server. */
#define UA_STATUSCODE_BADUNKNOWNRESPONSE 0x80090000
/* The operation timed out. */
#define UA_STATUSCODE_BADTIMEOUT 0x800A0000
/* The server does not support the requested service. */
#define UA_STATUSCODE_BADSERVICEUNSUPPORTED 0x800B0000
/* The operation was cancelled because the application is shutting down. */
#define UA_STATUSCODE_BADSHUTDOWN 0x800C0000
/* The operation could not complete because the client is not connected to the server. */
#define UA_STATUSCODE_BADSERVERNOTCONNECTED 0x800D0000
/* The server has stopped and cannot process any requests. */
#define UA_STATUSCODE_BADSERVERHALTED 0x800E0000
/* There was nothing to do because the client passed a list of operations with no elements. */
#define UA_STATUSCODE_BADNOTHINGTODO 0x800F0000
/* The request could not be processed because it specified too many operations. */
#define UA_STATUSCODE_BADTOOMANYOPERATIONS 0x80100000
/* The request could not be processed because there are too many monitored items in the subscripti*/
#define UA_STATUSCODE_BADTOOMANYMONITOREDITEMS 0x80DB0000
/* The extension object cannot be (de)serialized because the data type id is not recognized. */
#define UA_STATUSCODE_BADDATATYPEIDUNKNOWN 0x80110000
/* The certificate provided as a parameter is not valid. */
#define UA_STATUSCODE_BADCERTIFICATEINVALID 0x80120000
/* An error occurred verifying security. */
#define UA_STATUSCODE_BADSECURITYCHECKSFAILED 0x80130000
/* The certificate does not meet the requirements of the security policy. */
#define UA_STATUSCODE_BADCERTIFICATEPOLICYCHECKFAILED 0x81140000
/* The certificate has expired or is not yet valid. */
#define UA_STATUSCODE_BADCERTIFICATETIMEINVALID 0x80140000
/* An issuer certificate has expired or is not yet valid. */
#define UA_STATUSCODE_BADCERTIFICATEISSUERTIMEINVALID 0x80150000
/* The HostName used to connect to a server does not match a HostName in the certificate. */
#define UA_STATUSCODE_BADCERTIFICATEHOSTNAMEINVALID 0x80160000
/* The URI specified in the ApplicationDescription does not match the URI in the certificate. */
#define UA_STATUSCODE_BADCERTIFICATEURIINVALID 0x80170000
/* The certificate may not be used for the requested operation. */
#define UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED 0x80180000
/* The issuer certificate may not be used for the requested operation. */
#define UA_STATUSCODE_BADCERTIFICATEISSUERUSENOTALLOWED 0x80190000
/* The certificate is not trusted. */
#define UA_STATUSCODE_BADCERTIFICATEUNTRUSTED 0x801A0000
/* It was not possible to determine if the certificate has been revoked. */
#define UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN 0x801B0000
/* It was not possible to determine if the issuer certificate has been revoked. */
#define UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN 0x801C0000
/* The certificate has been revoked. */
#define UA_STATUSCODE_BADCERTIFICATEREVOKED 0x801D0000
/* The issuer certificate has been revoked. */
#define UA_STATUSCODE_BADCERTIFICATEISSUERREVOKED 0x801E0000
/* The certificate chain is incomplete. */
#define UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE 0x810D0000
/* User does not have permission to perform the requested operation. */
#define UA_STATUSCODE_BADUSERACCESSDENIED 0x801F0000
/* The user identity token is not valid. */
#define UA_STATUSCODE_BADIDENTITYTOKENINVALID 0x80200000
/* The user identity token is valid but the server has rejected it. */
#define UA_STATUSCODE_BADIDENTITYTOKENREJECTED 0x80210000
/* The specified secure channel is no longer valid. */
#define UA_STATUSCODE_BADSECURECHANNELIDINVALID 0x80220000
/* The timestamp is outside the range allowed by the server. */
#define UA_STATUSCODE_BADINVALIDTIMESTAMP 0x80230000
/* The nonce does appear to be not a random value or it is not the correct length. */
#define UA_STATUSCODE_BADNONCEINVALID 0x80240000
/* The session id is not valid. */
#define UA_STATUSCODE_BADSESSIONIDINVALID 0x80250000
/* The session was closed by the client. */
#define UA_STATUSCODE_BADSESSIONCLOSED 0x80260000
/* The session cannot be used because ActivateSession has not been called. */
#define UA_STATUSCODE_BADSESSIONNOTACTIVATED 0x80270000
/* The subscription id is not valid. */
#define UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID 0x80280000
/* The header for the request is missing or invalid. */
#define UA_STATUSCODE_BADREQUESTHEADERINVALID 0x802A0000
/* The timestamps to return parameter is invalid. */
#define UA_STATUSCODE_BADTIMESTAMPSTORETURNINVALID 0x802B0000
/* The request was cancelled by the client. */
#define UA_STATUSCODE_BADREQUESTCANCELLEDBYCLIENT 0x802C0000
/* Too many arguments were provided. */
#define UA_STATUSCODE_BADTOOMANYARGUMENTS 0x80E50000
/* The server requires a license to operate in general or to perform a service or operation */
#define UA_STATUSCODE_BADLICENSEEXPIRED 0x810E0000
/* The server has limits on number of allowed operations / objects */
#define UA_STATUSCODE_BADLICENSELIMITSEXCEEDED 0x810F0000
/* The server does not have a license which is required to operate in general or to perform a serv*/
#define UA_STATUSCODE_BADLICENSENOTAVAILABLE 0x81100000
/* The subscription was transferred to another session. */
#define UA_STATUSCODE_GOODSUBSCRIPTIONTRANSFERRED 0x002D0000
/* The processing will complete asynchronously. */
#define UA_STATUSCODE_GOODCOMPLETESASYNCHRONOUSLY 0x002E0000
/* Sampling has slowed down due to resource limitations. */
#define UA_STATUSCODE_GOODOVERLOAD 0x002F0000
/* The value written was accepted but was clamped. */
#define UA_STATUSCODE_GOODCLAMPED 0x00300000
/* Communication with the data source is defined */
#define UA_STATUSCODE_BADNOCOMMUNICATION 0x80310000
/* Waiting for the server to obtain values from the underlying data source. */
#define UA_STATUSCODE_BADWAITINGFORINITIALDATA 0x80320000
/* The syntax of the node id is not valid. */
#define UA_STATUSCODE_BADNODEIDINVALID 0x80330000
/* The node id refers to a node that does not exist in the server address space. */
#define UA_STATUSCODE_BADNODEIDUNKNOWN 0x80340000
/* The attribute is not supported for the specified Node. */
#define UA_STATUSCODE_BADATTRIBUTEIDINVALID 0x80350000
/* The syntax of the index range parameter is invalid. */
#define UA_STATUSCODE_BADINDEXRANGEINVALID 0x80360000
/* No data exists within the range of indexes specified. */
#define UA_STATUSCODE_BADINDEXRANGENODATA 0x80370000
/* The data encoding is invalid. */
#define UA_STATUSCODE_BADDATAENCODINGINVALID 0x80380000
/* The server does not support the requested data encoding for the node. */
#define UA_STATUSCODE_BADDATAENCODINGUNSUPPORTED 0x80390000
/* The access level does not allow reading or subscribing to the Node. */
#define UA_STATUSCODE_BADNOTREADABLE 0x803A0000
/* The access level does not allow writing to the Node. */
#define UA_STATUSCODE_BADNOTWRITABLE 0x803B0000
/* The value was out of range. */
#define UA_STATUSCODE_BADOUTOFRANGE 0x803C0000
/* The requested operation is not supported. */
#define UA_STATUSCODE_BADNOTSUPPORTED 0x803D0000
/* A requested item was not found or a search operation ended without success. */
#define UA_STATUSCODE_BADNOTFOUND 0x803E0000
/* The object cannot be used because it has been deleted. */
#define UA_STATUSCODE_BADOBJECTDELETED 0x803F0000
/* Requested operation is not implemented. */
#define UA_STATUSCODE_BADNOTIMPLEMENTED 0x80400000
/* The monitoring mode is invalid. */
#define UA_STATUSCODE_BADMONITORINGMODEINVALID 0x80410000
/* The monitoring item id does not refer to a valid monitored item. */
#define UA_STATUSCODE_BADMONITOREDITEMIDINVALID 0x80420000
/* The monitored item filter parameter is not valid. */
#define UA_STATUSCODE_BADMONITOREDITEMFILTERINVALID 0x80430000
/* The server does not support the requested monitored item filter. */
#define UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED 0x80440000
/* A monitoring filter cannot be used in combination with the attribute specified. */
#define UA_STATUSCODE_BADFILTERNOTALLOWED 0x80450000
/* A mandatory structured parameter was missing or null. */
#define UA_STATUSCODE_BADSTRUCTUREMISSING 0x80460000
/* The event filter is not valid. */
#define UA_STATUSCODE_BADEVENTFILTERINVALID 0x80470000
/* The content filter is not valid. */
#define UA_STATUSCODE_BADCONTENTFILTERINVALID 0x80480000
/* An unrecognized operator was provided in a filter. */
#define UA_STATUSCODE_BADFILTEROPERATORINVALID 0x80C10000
/* A valid operator was provided */
#define UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED 0x80C20000
/* The number of operands provided for the filter operator was less then expected for the operand*/
#define UA_STATUSCODE_BADFILTEROPERANDCOUNTMISMATCH 0x80C30000
/* The operand used in a content filter is not valid. */
#define UA_STATUSCODE_BADFILTEROPERANDINVALID 0x80490000
/* The referenced element is not a valid element in the content filter. */
#define UA_STATUSCODE_BADFILTERELEMENTINVALID 0x80C40000
/* The referenced literal is not a valid value. */
#define UA_STATUSCODE_BADFILTERLITERALINVALID 0x80C50000
/* The continuation point provide is longer valid. */
#define UA_STATUSCODE_BADCONTINUATIONPOINTINVALID 0x804A0000
/* The operation could not be processed because all continuation points have been allocated. */
#define UA_STATUSCODE_BADNOCONTINUATIONPOINTS 0x804B0000
/* The reference type id does not refer to a valid reference type node. */
#define UA_STATUSCODE_BADREFERENCETYPEIDINVALID 0x804C0000
/* The browse direction is not valid. */
#define UA_STATUSCODE_BADBROWSEDIRECTIONINVALID 0x804D0000
/* The node is not part of the view. */
#define UA_STATUSCODE_BADNODENOTINVIEW 0x804E0000
/* The number was not accepted because of a numeric overflow. */
#define UA_STATUSCODE_BADNUMERICOVERFLOW 0x81120000
/* The ServerUri is not a valid URI. */
#define UA_STATUSCODE_BADSERVERURIINVALID 0x804F0000
/* No ServerName was specified. */
#define UA_STATUSCODE_BADSERVERNAMEMISSING 0x80500000
/* No DiscoveryUrl was specified. */
#define UA_STATUSCODE_BADDISCOVERYURLMISSING 0x80510000
/* The semaphore file specified by the client is not valid. */
#define UA_STATUSCODE_BADSEMPAHOREFILEMISSING 0x80520000
/* The security token request type is not valid. */
#define UA_STATUSCODE_BADREQUESTTYPEINVALID 0x80530000
/* The security mode does not meet the requirements set by the server. */
#define UA_STATUSCODE_BADSECURITYMODEREJECTED 0x80540000
/* The security policy does not meet the requirements set by the server. */
#define UA_STATUSCODE_BADSECURITYPOLICYREJECTED 0x80550000
/* The server has reached its maximum number of sessions. */
#define UA_STATUSCODE_BADTOOMANYSESSIONS 0x80560000
/* The user token signature is missing or invalid. */
#define UA_STATUSCODE_BADUSERSIGNATUREINVALID 0x80570000
/* The signature generated with the client certificate is missing or invalid. */
#define UA_STATUSCODE_BADAPPLICATIONSIGNATUREINVALID 0x80580000
/* The client did not provide at least one software certificate that is valid and meets the profil*/
#define UA_STATUSCODE_BADNOVALIDCERTIFICATES 0x80590000
/* The server does not support changing the user identity assigned to the session. */
#define UA_STATUSCODE_BADIDENTITYCHANGENOTSUPPORTED 0x80C60000
/* The request was cancelled by the client with the Cancel service. */
#define UA_STATUSCODE_BADREQUESTCANCELLEDBYREQUEST 0x805A0000
/* The parent node id does not to refer to a valid node. */
#define UA_STATUSCODE_BADPARENTNODEIDINVALID 0x805B0000
/* The reference could not be created because it violates constraints imposed by the data model.*/
#define UA_STATUSCODE_BADREFERENCENOTALLOWED 0x805C0000
/* The requested node id was reject because it was either invalid or server does not allow node id*/
#define UA_STATUSCODE_BADNODEIDREJECTED 0x805D0000
/* The requested node id is already used by another node. */
#define UA_STATUSCODE_BADNODEIDEXISTS 0x805E0000
/* The node class is not valid. */
#define UA_STATUSCODE_BADNODECLASSINVALID 0x805F0000
/* The browse name is invalid. */
#define UA_STATUSCODE_BADBROWSENAMEINVALID 0x80600000
/* The browse name is not unique among nodes that share the same relationship with the parent. */
#define UA_STATUSCODE_BADBROWSENAMEDUPLICATED 0x80610000
/* The node attributes are not valid for the node class. */
#define UA_STATUSCODE_BADNODEATTRIBUTESINVALID 0x80620000
/* The type definition node id does not reference an appropriate type node. */
#define UA_STATUSCODE_BADTYPEDEFINITIONINVALID 0x80630000
/* The source node id does not reference a valid node. */
#define UA_STATUSCODE_BADSOURCENODEIDINVALID 0x80640000
/* The target node id does not reference a valid node. */
#define UA_STATUSCODE_BADTARGETNODEIDINVALID 0x80650000
/* The reference type between the nodes is already defined. */
#define UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED 0x80660000
/* The server does not allow this type of self reference on this node. */
#define UA_STATUSCODE_BADINVALIDSELFREFERENCE 0x80670000
/* The reference type is not valid for a reference to a remote server. */
#define UA_STATUSCODE_BADREFERENCELOCALONLY 0x80680000
/* The server will not allow the node to be deleted. */
#define UA_STATUSCODE_BADNODELETERIGHTS 0x80690000
/* The server was not able to delete all target references. */
#define UA_STATUSCODE_UNCERTAINREFERENCENOTDELETED 0x40BC0000
/* The server index is not valid. */
#define UA_STATUSCODE_BADSERVERINDEXINVALID 0x806A0000
/* The view id does not refer to a valid view node. */
#define UA_STATUSCODE_BADVIEWIDUNKNOWN 0x806B0000
/* The view timestamp is not available or not supported. */
#define UA_STATUSCODE_BADVIEWTIMESTAMPINVALID 0x80C90000
/* The view parameters are not consistent with each other. */
#define UA_STATUSCODE_BADVIEWPARAMETERMISMATCH 0x80CA0000
/* The view version is not available or not supported. */
#define UA_STATUSCODE_BADVIEWVERSIONINVALID 0x80CB0000
/* The list of references may not be complete because the underlying system is not available. */
#define UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE 0x40C00000
/* The server should have followed a reference to a node in a remote server but did not. The resul*/
#define UA_STATUSCODE_GOODRESULTSMAYBEINCOMPLETE 0x00BA0000
/* The provided Nodeid was not a type definition nodeid. */
#define UA_STATUSCODE_BADNOTTYPEDEFINITION 0x80C80000
/* One of the references to follow in the relative path references to a node in the address space*/
#define UA_STATUSCODE_UNCERTAINREFERENCEOUTOFSERVER 0x406C0000
/* The requested operation has too many matches to return. */
#define UA_STATUSCODE_BADTOOMANYMATCHES 0x806D0000
/* The requested operation requires too many resources in the server. */
#define UA_STATUSCODE_BADQUERYTOOCOMPLEX 0x806E0000
/* The requested operation has no match to return. */
#define UA_STATUSCODE_BADNOMATCH 0x806F0000
/* The max age parameter is invalid. */
#define UA_STATUSCODE_BADMAXAGEINVALID 0x80700000
/* The operation is not permitted over the current secure channel. */
#define UA_STATUSCODE_BADSECURITYMODEINSUFFICIENT 0x80E60000
/* The history details parameter is not valid. */
#define UA_STATUSCODE_BADHISTORYOPERATIONINVALID 0x80710000
/* The server does not support the requested operation. */
#define UA_STATUSCODE_BADHISTORYOPERATIONUNSUPPORTED 0x80720000
/* The defined timestamp to return was invalid. */
#define UA_STATUSCODE_BADINVALIDTIMESTAMPARGUMENT 0x80BD0000
/* The server does not support writing the combination of value */
#define UA_STATUSCODE_BADWRITENOTSUPPORTED 0x80730000
/* The value supplied for the attribute is not of the same type as the attribute’s value. */
#define UA_STATUSCODE_BADTYPEMISMATCH 0x80740000
/* The method id does not refer to a method for the specified object. */
#define UA_STATUSCODE_BADMETHODINVALID 0x80750000
/* The client did not specify all of the input arguments for the method. */
#define UA_STATUSCODE_BADARGUMENTSMISSING 0x80760000
/* The executable attribute does not allow the execution of the method. */
#define UA_STATUSCODE_BADNOTEXECUTABLE 0x81110000
/* The server has reached its maximum number of subscriptions. */
#define UA_STATUSCODE_BADTOOMANYSUBSCRIPTIONS 0x80770000
/* The server has reached the maximum number of queued publish requests. */
#define UA_STATUSCODE_BADTOOMANYPUBLISHREQUESTS 0x80780000
/* There is no subscription available for this session. */
#define UA_STATUSCODE_BADNOSUBSCRIPTION 0x80790000
/* The sequence number is unknown to the server. */
#define UA_STATUSCODE_BADSEQUENCENUMBERUNKNOWN 0x807A0000
/* The requested notification message is no longer available. */
#define UA_STATUSCODE_BADMESSAGENOTAVAILABLE 0x807B0000
/* The client of the current session does not support one or more Profiles that are necessary for*/
#define UA_STATUSCODE_BADINSUFFICIENTCLIENTPROFILE 0x807C0000
/* The sub-state machine is not currently active. */
#define UA_STATUSCODE_BADSTATENOTACTIVE 0x80BF0000
/* An equivalent rule already exists. */
#define UA_STATUSCODE_BADALREADYEXISTS 0x81150000
/* The server cannot process the request because it is too busy. */
#define UA_STATUSCODE_BADTCPSERVERTOOBUSY 0x807D0000
/* The type of the message specified in the header invalid. */
#define UA_STATUSCODE_BADTCPMESSAGETYPEINVALID 0x807E0000
/* The SecureChannelId and/or TokenId are not currently in use. */
#define UA_STATUSCODE_BADTCPSECURECHANNELUNKNOWN 0x807F0000
/* The size of the message specified in the header is too large. */
#define UA_STATUSCODE_BADTCPMESSAGETOOLARGE 0x80800000
/* There are not enough resources to process the request. */
#define UA_STATUSCODE_BADTCPNOTENOUGHRESOURCES 0x80810000
/* An internal error occurred. */
#define UA_STATUSCODE_BADTCPINTERNALERROR 0x80820000
/* The server does not recognize the QueryString specified. */
#define UA_STATUSCODE_BADTCPENDPOINTURLINVALID 0x80830000
/* The request could not be sent because of a network interruption. */
#define UA_STATUSCODE_BADREQUESTINTERRUPTED 0x80840000
/* Timeout occurred while processing the request. */
#define UA_STATUSCODE_BADREQUESTTIMEOUT 0x80850000
/* The secure channel has been closed. */
#define UA_STATUSCODE_BADSECURECHANNELCLOSED 0x80860000
/* The token has expired or is not recognized. */
#define UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN 0x80870000
/* The sequence number is not valid. */
#define UA_STATUSCODE_BADSEQUENCENUMBERINVALID 0x80880000
/* The applications do not have compatible protocol versions. */
#define UA_STATUSCODE_BADPROTOCOLVERSIONUNSUPPORTED 0x80BE0000
/* There is a problem with the configuration that affects the usefulness of the value. */
#define UA_STATUSCODE_BADCONFIGURATIONERROR 0x80890000
/* The variable should receive its value from another variable */
#define UA_STATUSCODE_BADNOTCONNECTED 0x808A0000
/* There has been a failure in the device/data source that generates the value that has affected t*/
#define UA_STATUSCODE_BADDEVICEFAILURE 0x808B0000
/* There has been a failure in the sensor from which the value is derived by the device/data sourc*/
#define UA_STATUSCODE_BADSENSORFAILURE 0x808C0000
/* The source of the data is not operational. */
#define UA_STATUSCODE_BADOUTOFSERVICE 0x808D0000
/* The deadband filter is not valid. */
#define UA_STATUSCODE_BADDEADBANDFILTERINVALID 0x808E0000
/* Communication to the data source has failed. The variable value is the last value that had a go*/
#define UA_STATUSCODE_UNCERTAINNOCOMMUNICATIONLASTUSABLEVALUE 0x408F0000
/* Whatever was updating this value has stopped doing so. */
#define UA_STATUSCODE_UNCERTAINLASTUSABLEVALUE 0x40900000
/* The value is an operational value that was manually overwritten. */
#define UA_STATUSCODE_UNCERTAINSUBSTITUTEVALUE 0x40910000
/* The value is an initial value for a variable that normally receives its value from another vari*/
#define UA_STATUSCODE_UNCERTAININITIALVALUE 0x40920000
/* The value is at one of the sensor limits. */
#define UA_STATUSCODE_UNCERTAINSENSORNOTACCURATE 0x40930000
/* The value is outside of the range of values defined for this parameter. */
#define UA_STATUSCODE_UNCERTAINENGINEERINGUNITSEXCEEDED 0x40940000
/* The value is derived from multiple sources and has less than the required number of Good source*/
#define UA_STATUSCODE_UNCERTAINSUBNORMAL 0x40950000
/* The value has been overridden. */
#define UA_STATUSCODE_GOODLOCALOVERRIDE 0x00960000
/* This Condition refresh failed */
#define UA_STATUSCODE_BADREFRESHINPROGRESS 0x80970000
/* This condition has already been disabled. */
#define UA_STATUSCODE_BADCONDITIONALREADYDISABLED 0x80980000
/* This condition has already been enabled. */
#define UA_STATUSCODE_BADCONDITIONALREADYENABLED 0x80CC0000
/* Property not available */
#define UA_STATUSCODE_BADCONDITIONDISABLED 0x80990000
/* The specified event id is not recognized. */
#define UA_STATUSCODE_BADEVENTIDUNKNOWN 0x809A0000
/* The event cannot be acknowledged. */
#define UA_STATUSCODE_BADEVENTNOTACKNOWLEDGEABLE 0x80BB0000
/* The dialog condition is not active. */
#define UA_STATUSCODE_BADDIALOGNOTACTIVE 0x80CD0000
/* The response is not valid for the dialog. */
#define UA_STATUSCODE_BADDIALOGRESPONSEINVALID 0x80CE0000
/* The condition branch has already been acknowledged. */
#define UA_STATUSCODE_BADCONDITIONBRANCHALREADYACKED 0x80CF0000
/* The condition branch has already been confirmed. */
#define UA_STATUSCODE_BADCONDITIONBRANCHALREADYCONFIRMED 0x80D00000
/* The condition has already been shelved. */
#define UA_STATUSCODE_BADCONDITIONALREADYSHELVED 0x80D10000
/* The condition is not currently shelved. */
#define UA_STATUSCODE_BADCONDITIONNOTSHELVED 0x80D20000
/* The shelving time not within an acceptable range. */
#define UA_STATUSCODE_BADSHELVINGTIMEOUTOFRANGE 0x80D30000
/* No data exists for the requested time range or event filter. */
#define UA_STATUSCODE_BADNODATA 0x809B0000
/* No data found to provide upper or lower bound value. */
#define UA_STATUSCODE_BADBOUNDNOTFOUND 0x80D70000
/* The server cannot retrieve a bound for the variable. */
#define UA_STATUSCODE_BADBOUNDNOTSUPPORTED 0x80D80000
/* Data is missing due to collection started/stopped/lost. */
#define UA_STATUSCODE_BADDATALOST 0x809D0000
/* Expected data is unavailable for the requested time range due to an un-mounted volume */
#define UA_STATUSCODE_BADDATAUNAVAILABLE 0x809E0000
/* The data or event was not successfully inserted because a matching entry exists. */
#define UA_STATUSCODE_BADENTRYEXISTS 0x809F0000
/* The data or event was not successfully updated because no matching entry exists. */
#define UA_STATUSCODE_BADNOENTRYEXISTS 0x80A00000
/* The client requested history using a timestamp format the server does not support (i.e requeste*/
#define UA_STATUSCODE_BADTIMESTAMPNOTSUPPORTED 0x80A10000
/* The data or event was successfully inserted into the historical database. */
#define UA_STATUSCODE_GOODENTRYINSERTED 0x00A20000
/* The data or event field was successfully replaced in the historical database. */
#define UA_STATUSCODE_GOODENTRYREPLACED 0x00A30000
/* The value is derived from multiple values and has less than the required number of Good values.*/
#define UA_STATUSCODE_UNCERTAINDATASUBNORMAL 0x40A40000
/* No data exists for the requested time range or event filter. */
#define UA_STATUSCODE_GOODNODATA 0x00A50000
/* The data or event field was successfully replaced in the historical database. */
#define UA_STATUSCODE_GOODMOREDATA 0x00A60000
/* The requested number of Aggregates does not match the requested number of NodeIds. */
#define UA_STATUSCODE_BADAGGREGATELISTMISMATCH 0x80D40000
/* The requested Aggregate is not support by the server. */
#define UA_STATUSCODE_BADAGGREGATENOTSUPPORTED 0x80D50000
/* The aggregate value could not be derived due to invalid data inputs. */
#define UA_STATUSCODE_BADAGGREGATEINVALIDINPUTS 0x80D60000
/* The aggregate configuration is not valid for specified node. */
#define UA_STATUSCODE_BADAGGREGATECONFIGURATIONREJECTED 0x80DA0000
/* The request specifies fields which are not valid for the EventType or cannot be saved by the hi*/
#define UA_STATUSCODE_GOODDATAIGNORED 0x00D90000
/* The request was rejected by the server because it did not meet the criteria set by the server.*/
#define UA_STATUSCODE_BADREQUESTNOTALLOWED 0x80E40000
/* The request has not been processed by the server yet. */
#define UA_STATUSCODE_BADREQUESTNOTCOMPLETE 0x81130000
/* The value does not come from the real source and has been edited by the server. */
#define UA_STATUSCODE_GOODEDITED 0x00DC0000
/* There was an error in execution of these post-actions. */
#define UA_STATUSCODE_GOODPOSTACTIONFAILED 0x00DD0000
/* The related EngineeringUnit has been changed but the Variable Value is still provided based on*/
#define UA_STATUSCODE_UNCERTAINDOMINANTVALUECHANGED 0x40DE0000
/* A dependent value has been changed but the change has not been applied to the device. */
#define UA_STATUSCODE_GOODDEPENDENTVALUECHANGED 0x00E00000
/* The related EngineeringUnit has been changed but this change has not been applied to the device*/
#define UA_STATUSCODE_BADDOMINANTVALUECHANGED 0x80E10000
/* A dependent value has been changed but the change has not been applied to the device. The quali*/
#define UA_STATUSCODE_UNCERTAINDEPENDENTVALUECHANGED 0x40E20000
/* A dependent value has been changed but the change has not been applied to the device. The quali*/
#define UA_STATUSCODE_BADDEPENDENTVALUECHANGED 0x80E30000
/* The communication layer has raised an event. */
#define UA_STATUSCODE_GOODCOMMUNICATIONEVENT 0x00A70000
/* The system is shutting down. */
#define UA_STATUSCODE_GOODSHUTDOWNEVENT 0x00A80000
/* The operation is not finished and needs to be called again. */
#define UA_STATUSCODE_GOODCALLAGAIN 0x00A90000
/* A non-critical timeout occurred. */
#define UA_STATUSCODE_GOODNONCRITICALTIMEOUT 0x00AA0000
/* One or more arguments are invalid. */
#define UA_STATUSCODE_BADINVALIDARGUMENT 0x80AB0000
/* Could not establish a network connection to remote server. */
#define UA_STATUSCODE_BADCONNECTIONREJECTED 0x80AC0000
/* The server has disconnected from the client. */
#define UA_STATUSCODE_BADDISCONNECT 0x80AD0000
/* The network connection has been closed. */
#define UA_STATUSCODE_BADCONNECTIONCLOSED 0x80AE0000
/* The operation cannot be completed because the object is closed */
#define UA_STATUSCODE_BADINVALIDSTATE 0x80AF0000
/* Cannot move beyond end of the stream. */
#define UA_STATUSCODE_BADENDOFSTREAM 0x80B00000
/* No data is currently available for reading from a non-blocking stream. */
#define UA_STATUSCODE_BADNODATAAVAILABLE 0x80B10000
/* The asynchronous operation is waiting for a response. */
#define UA_STATUSCODE_BADWAITINGFORRESPONSE 0x80B20000
/* The asynchronous operation was abandoned by the caller. */
#define UA_STATUSCODE_BADOPERATIONABANDONED 0x80B30000
/* The stream did not return all data requested (possibly because it is a non-blocking stream). */
#define UA_STATUSCODE_BADEXPECTEDSTREAMTOBLOCK 0x80B40000
/* Non blocking behaviour is required and the operation would block. */
#define UA_STATUSCODE_BADWOULDBLOCK 0x80B50000
/* A value had an invalid syntax. */
#define UA_STATUSCODE_BADSYNTAXERROR 0x80B60000
/* The operation could not be finished because all available connections are in use. */
#define UA_STATUSCODE_BADMAXCONNECTIONSREACHED 0x80B70000

13.2 网络插件API

13.2.1连接

客户机-服务器连接由 UA_Connection 表示。连接是有状态的,存储部分接收到的消息,依此类推。此外,连接还包含指向底层网络实现的函数指针。例如 send 函数。因此,连接封装了所有必需的网络功能。这使得嵌入式(或其他外来的)系统上的用户可以实现他们自己的网络插件,并具有到主open62541库的清晰接口。

typedef struct {
	UA_UInt32 protocolVersion;
	UA_UInt32 recvBufferSize;
	UA_UInt32 sendBufferSize;
	UA_UInt32 localMaxMessageSize; /* (0 = unbounded) */
	UA_UInt32 remoteMaxMessageSize; /* (0 = unbounded) */
	UA_UInt32 localMaxChunkCount; /* (0 = unbounded) */
	UA_UInt32 remoteMaxChunkCount; /* (0 = unbounded) */
} UA_ConnectionConfig;
typedef enum {
	UA_CONNECTIONSTATE_CLOSED, /* The socket has been closed and the connection
	* will be deleted */
	UA_CONNECTIONSTATE_OPENING, /* The socket is open, but the HEL/ACK handshake
	* is not done */
	UA_CONNECTIONSTATE_ESTABLISHED /* The socket is open and the connection
	* configured */
} UA_ConnectionState;
struct UA_Connection {
	UA_ConnectionState state;
	UA_SecureChannel* channel; /* The securechannel that is attached to
	* this connection */
	UA_SOCKET sockfd; /* Most connectivity solutions run on
	* sockets. Having the socket id here
	* simplifies the design. */
	UA_DateTime openingDate; /* The date the connection was created */
	void* handle; /* A pointer to internal data */
	/* Get a buffer for sending */
	UA_StatusCode(*getSendBuffer)(UA_Connection* connection, size_t length,
		UA_ByteString* buf);
	/* Release the send buffer manually */
	void (*releaseSendBuffer)(UA_Connection* connection, UA_ByteString* buf);
	/* Sends a message over the connection. The message buffer is always freed,
	* even if sending fails.
	* *
	@param connection The connection
	* @param buf The message buffer
	* @return Returns an error code or UA_STATUSCODE_GOOD. */
	UA_StatusCode(*send)(UA_Connection* connection, UA_ByteString* buf);
	/* Receive a message from the remote connection
	* *
	@param connection The connection
	* @param response The response string. If this is empty, it will be
	* allocated by the connection and needs to be freed with
	* connection->releaseBuffer. If the response string is non-empty, it
	* will be used as the receive buffer. If bytes are received, the
	* length of the buffer is adjusted to match the length of the
	* received bytes.
	* @param timeout Timeout of the recv operation in milliseconds
	* @return Returns UA_STATUSCODE_BADCOMMUNICATIONERROR if the recv operation
	* can be repeated, UA_STATUSCODE_GOOD if it succeeded and
	* UA_STATUSCODE_BADCONNECTIONCLOSED if the connection was
	* closed. */
	UA_StatusCode(*recv)(UA_Connection* connection, UA_ByteString* response,
		UA_UInt32 timeout);
	/* Release the buffer of a received message */
	void (*releaseRecvBuffer)(UA_Connection* connection, UA_ByteString* buf);
	/* Close the connection. The network layer closes the socket. This is picked
	* up during the next ’listen’ and the connection is freed in the network
	* layer. */
	void (*close)(UA_Connection* connection);
	/* To be called only from within the server (and not the network layer).
	* Frees up the connection’s memory. */
	void (*free)(UA_Connection* connection);
};

13.2.2服务器网络层

remobinaryexpositionremote-processveconnection与两个远程客户端进行交互。这些函数由服务器网络层调用。
服务器网络层的工作是监听TCP套接字,接受新的连接,用接收到的消息调用服务器,并向服务器发出关闭的连接信号。
网络层是服务器配置的一部分。因此,如果提供的示例不适合他们的体系结构,则用户可以提供自定义实现。网络层只能从服务器的主循环调用。所以网络层不需要是线程安全的。如果一个监听层接收到的消息持续时间是正的,则服务器将阻塞该消息。

/* Process a binary message (TCP packet). The message can contain partial
* chunks. (TCP is a streaming protocol and packets may be split/merge during
* transport.) After processing, the message is freed with
* connection->releaseRecvBuffer. */
void
UA_Server_processBinaryMessage(UA_Server* server, UA_Connection* connection,
	UA_ByteString* message);
/* The server internally cleans up the connection and then calls
* connection->free. */
void
UA_Server_removeConnection(UA_Server* server, UA_Connection* connection);
struct UA_ServerNetworkLayer {
	void* handle; /* Internal data */
	/* Points to external memory, i.e. handled by server or client */
	UA_NetworkStatistics* statistics;
	UA_String discoveryUrl;
	UA_ConnectionConfig localConnectionConfig;
	/* Start listening on the networklayer.
	* *
	@param nl The network layer
	* @return Returns UA_STATUSCODE_GOOD or an error code. */
	UA_StatusCode(*start)(UA_ServerNetworkLayer* nl, const UA_String* customHostname);
	/* Listen for new and closed connections and arriving packets. Calls
	* UA_Server_processBinaryMessage for the arriving packets. Closed
	* connections are picked up here and forwarded to
	* UA_Server_removeConnection where they are cleaned up and freed.
	* *
	@param nl The network layer
	* @param server The server for processing the incoming packets and for
	* closing connections.
	* @param timeout The timeout during which an event must arrive in
	* milliseconds
	* @return A statuscode for the status of the network layer. */
	UA_StatusCode(*listen)(UA_ServerNetworkLayer* nl, UA_Server* server,
		UA_UInt16 timeout);
	/* Close the network socket and all open connections. Afterwards, the
	* network layer can be safely deleted.
	* *
	@param nl The network layer
	* @param server The server that processes the incoming packets and for
	* closing connections before deleting them.
	* @return A statuscode for the status of the closing operation. */
	void (*stop)(UA_ServerNetworkLayer* nl, UA_Server* server);
	/* Deletes the network layer context. Call only after stopping. */
	void (*clear)(UA_ServerNetworkLayer* nl);
};

13.2.3客户端网络层

客户端只有一个用于发送和接收二进制消息的连接。

/* @param config the connection config for this client
* @param endpointUrl to where to connect
* @param timeout in ms until the connection try times out if remote not reachable
* @param logger the logger to use */
typedef UA_Connection
(*UA_ConnectClientConnection)(UA_ConnectionConfig config, UA_String endpointUrl,
							UA_UInt32 timeout, UA_Logger *logger);

13.3访问控制插件API

相应地,使用回调来验证和授予访问权限。

struct UA_AccessControl {
	void* context;
	void (*clear)(UA_AccessControl* ac);
	/* Supported login mechanisms. The server endpoints are created from here. */
	size_t userTokenPoliciesSize;
	UA_UserTokenPolicy* userTokenPolicies;
	/* Authenticate a session. The session context is attached to the session
	* and later passed into the node-based access control callbacks. The new
	* session is rejected if a StatusCode other than UA_STATUSCODE_GOOD is
	* returned. */
	UA_StatusCode(*activateSession)(UA_Server* server, UA_AccessControl* ac,
		const UA_EndpointDescription* endpointDescription,
		const UA_ByteString* secureChannelRemoteCertificate,
		const UA_NodeId* sessionId,
		const UA_ExtensionObject* userIdentityToken,
		void** sessionContext);
	/* Deauthenticate a session and cleanup */
	void (*closeSession)(UA_Server* server, UA_AccessControl* ac,
		const UA_NodeId* sessionId, void* sessionContext);
	/* Access control for all nodes*/
	UA_UInt32(*getUserRightsMask)(UA_Server* server, UA_AccessControl* ac,
		const UA_NodeId* sessionId, void* sessionContext,
		const UA_NodeId* nodeId, void* nodeContext);
	/* Additional access control for variable nodes */
	UA_Byte(*getUserAccessLevel)(UA_Server* server, UA_AccessControl* ac,
		const UA_NodeId* sessionId, void* sessionContext,
		const UA_NodeId* nodeId, void* nodeContext);
	/* Additional access control for method nodes */
	UA_Boolean(*getUserExecutable)(UA_Server * server, UA_AccessControl * ac,
		const UA_NodeId * sessionId, void* sessionContext,
		const UA_NodeId * methodId, void* methodContext);
	/* Additional access control for calling a method node in the context of a
	* specific object */
	UA_Boolean(*getUserExecutableOnObject)(UA_Server* server, UA_AccessControl* ac,
		const UA_NodeId* sessionId, void* sessionContext,
		const UA_NodeId* methodId, void* methodContext,
		const UA_NodeId* objectId, void* objectContext);
	/* Allow adding a node */
	UA_Boolean(*allowAddNode)(UA_Server* server, UA_AccessControl* ac,
		const UA_NodeId* sessionId, void* sessionContext,
		const UA_AddNodesItem* item);
	/* Allow adding a reference */
	UA_Boolean(*allowAddReference)(UA_Server* server, UA_AccessControl* ac,
		const UA_NodeId* sessionId, void* sessionContext,
		const UA_AddReferencesItem* item);
	/* Allow deleting a node */
	UA_Boolean(*allowDeleteNode)(UA_Server* server, UA_AccessControl* ac,
		const UA_NodeId* sessionId, void* sessionContext,
		const UA_DeleteNodesItem* item);
	/* Allow deleting a reference */
	UA_Boolean(*allowDeleteReference)(UA_Server* server, UA_AccessControl* ac,
		const UA_NodeId* sessionId, void* sessionContext,
		const UA_DeleteReferencesItem* item);
	/* Allow browsing a node */
	UA_Boolean(*allowBrowseNode)(UA_Server* server, UA_AccessControl* ac,
		const UA_NodeId* sessionId, void* sessionContext,
		const UA_NodeId* nodeId, void* nodeContext);
#ifdef UA_ENABLE_HISTORIZING
	/* Allow insert,replace,update of historical data */
	UA_Boolean(*allowHistoryUpdateUpdateData)(UA_Server* server, UA_AccessControl* ac,
		const UA_NodeId* sessionId, void* sessionContext,
		const UA_NodeId* nodeId,
		UA_PerformUpdateType performInsertReplace,
		const UA_DataValue* value);
	/* Allow delete of historical data */
	UA_Boolean(*allowHistoryUpdateDeleteRawModified)(UA_Server* server, UA_AccessControl* ac,
		const UA_NodeId* sessionId, void* sessionCon
		const UA_NodeId* nodeId,
		UA_DateTime startTimestamp,
		UA_DateTime endTimestamp,
		bool isDeleteModified);
#endif
};

13.4日志插件API

服务器和客户端在其配置中定义一个记录器。记录器是一个插件。作为一个例子,我们提供了一个记录到stdout的默认插件。logger插件是有状态的,可以指向自定义数据。因此,可以在记录器上下文中保持打开的文件处理程序。
每个日志消息都由日志级别、日志类别和字符串消息内容组成。日志消息的时间戳在记录器中创建。

typedef enum {
	UA_LOGLEVEL_TRACE,
	UA_LOGLEVEL_DEBUG,
	UA_LOGLEVEL_INFO,
	UA_LOGLEVEL_WARNING,
	UA_LOGLEVEL_ERROR,
	UA_LOGLEVEL_FATAL
} UA_LogLevel;
typedef enum {
	UA_LOGCATEGORY_NETWORK,
	UA_LOGCATEGORY_SECURECHANNEL,
	UA_LOGCATEGORY_SESSION,
	UA_LOGCATEGORY_SERVER,
	UA_LOGCATEGORY_CLIENT,
	UA_LOGCATEGORY_USERLAND,
	UA_LOGCATEGORY_SECURITYPOLICY
} UA_LogCategory;
typedef struct {
	/* Log a message. The message string and following varargs are formatted
	* according to the rules of the printf command. Use the convenience macros
	* below that take the minimum log-level defined in ua_config.h into
	* account. */
	void (*log)(void* logContext, UA_LogLevel level, UA_LogCategory category,
		const char* msg, va_list args);
	void* context; /* Logger state */
	void (*clear)(void* context); /* Clean up the logger plugin */
} UA_Logger;
static UA_INLINE UA_FORMAT(3, 4) void
UA_LOG_TRACE(const UA_Logger* logger, UA_LogCategory category, const char* msg, ...) {
#if UA_LOGLEVEL <= 100
	if (!logger || !logger->log)
		return;
	va_list args; va_start(args, msg);
	logger->log(logger->context, UA_LOGLEVEL_TRACE, category, msg, args);
	va_end(args);
#else
	(void)logger;
	(void)category;
	(void)msg;
#endif
}
static UA_INLINE UA_FORMAT(3, 4) void
UA_LOG_DEBUG(const UA_Logger* logger, UA_LogCategory category, const char* msg, ...) {
#if UA_LOGLEVEL <= 200
	if (!logger || !logger->log)
		return;
	va_list args; va_start(args, msg);
	logger->log(logger->context, UA_LOGLEVEL_DEBUG, category, msg, args);
	va_end(args);
#else
	(void)logger;
	(void)category;
	(void)msg;
#endif
}
static UA_INLINE UA_FORMAT(3, 4) void
UA_LOG_INFO(const UA_Logger * logger, UA_LogCategory category, const char* msg, ...) {
#if UA_LOGLEVEL <= 300
	if (!logger || !logger->log)
		return;
	va_list args; va_start(args, msg);
	logger->log(logger->context, UA_LOGLEVEL_INFO, category, msg, args);
	va_end(args);
#else
	(void)logger;
	(void)category;
	(void)msg;
#endif
}
static UA_INLINE UA_FORMAT(3, 4) void
UA_LOG_WARNING(const UA_Logger* logger, UA_LogCategory category, const char* msg, ...) {
#if UA_LOGLEVEL <= 400
	if (!logger || !logger->log)
		return;
	va_list args; va_start(args, msg);
	logger->log(logger->context, UA_LOGLEVEL_WARNING, category, msg, args);
	va_end(args);
#else
	(void)logger;
	(void)category;
	(void)msg;
#endif
}
static UA_INLINE UA_FORMAT(3, 4) void
UA_LOG_ERROR(const UA_Logger* logger, UA_LogCategory category, const char* msg, ...) {
#if UA_LOGLEVEL <= 500
	if (!logger || !logger->log)
		return;
	va_list args; va_start(args, msg);
	logger->log(logger->context, UA_LOGLEVEL_ERROR, category, msg, args);
	va_end(args);
#else
	(void)logger;
	(void)category;
	(void)msg;
#endif
}
static UA_INLINE UA_FORMAT(3, 4) void
UA_LOG_FATAL(const UA_Logger* logger, UA_LogCategory category, const char* msg, ...) {
#if UA_LOGLEVEL <= 600
	if (!logger || !logger->log)
		return;
	va_list args; va_start(args, msg);
	logger->log(logger->context, UA_LOGLEVEL_FATAL, category, msg, args);
	va_end(args);
#else
	(void)logger;
	(void)category;
	(void)msg;
#endif
}

13.5 PubSub连接插件API

PubSub连接API是具体网络实现和内部PubSub代码之间的接口。
PubSub规范允许在运行时创建新的连接。措辞: ‘Connection’ -> OPC UA standard ‘highlevel’ perspective, ‘Channel’ -> open62541实施“lowlevel”透视图。通道可以分配给不同的网络实现,如UDP、MQTT、AMQP。通道提供基本服务,如send、regist、unregister、receive、close。

typedef enum {
	UA_PUBSUB_CHANNEL_RDY,
	UA_PUBSUB_CHANNEL_PUB,
	UA_PUBSUB_CHANNEL_SUB,
	UA_PUBSUB_CHANNEL_PUB_SUB,
	UA_PUBSUB_CHANNEL_ERROR,
	UA_PUBSUB_CHANNEL_CLOSED
} UA_PubSubChannelState;
struct UA_PubSubChannel;
typedef struct UA_PubSubChannel UA_PubSubChannel;
/* Interface structure between network plugin and internal implementation */
struct UA_PubSubChannel {
	UA_UInt32 publisherId; /* unique identifier */
	UA_PubSubChannelState state;
	UA_PubSubConnectionConfig* connectionConfig; /* link to parent connection config */
	UA_SOCKET sockfd;
	void* handle; /* implementation specific data */
	/*@info for handle: each network implementation should provide an structure
	* UA_PubSubChannelData[ImplementationName] This structure can be used by the
	* network implementation to store network implementation specific data.*/
	/* Sending out the content of the buf parameter */
	UA_StatusCode(*send)(UA_PubSubChannel* channel, UA_ExtensionObject* transportSettings,
		const UA_ByteString* buf);
	/* Register to an specified message source, e.g. multicast group or topic. Callback is used fo
	UA_StatusCode (*regist)(UA_PubSubChannel * channel, UA_ExtensionObject *transportSettings,
	void (*callback)(UA_ByteString *encodedBuffer, UA_ByteString *topic));
	/* Remove subscription to an specified message source, e.g. multicast group or topic */
	UA_StatusCode(*unregist)(UA_PubSubChannel* channel, UA_ExtensionObject* transportSettings);
	/* Receive messages. A regist to the message source is needed before. */
	UA_StatusCode(*receive)(UA_PubSubChannel* channel, UA_ByteString*,
		UA_ExtensionObject* transportSettings, UA_UInt32 timeout);
	/* Closing the connection and implicit free of the channel structures. */
	UA_StatusCode(*close)(UA_PubSubChannel* channel);
	/* Giving the connection protocoll time to process inbound and outbound traffic. */
	UA_StatusCode(*yield)(UA_PubSubChannel* channel, UA_UInt16 timeout);
};

UA_PubSubTransportLayer用于创建新连接。每当在运行时请求新连接时,内部PubSub实现调用*createPubSubChannel函数。“transportProfileUri”包含标准定义的传输配置文件信息,用于标识可由TransportLayer创建的连接类型。服务器配置包含UA_PubSubTransportLayer的列表。查看 tutorial_pubsub_connection 以获取有关TransportLayer处理的信息。

typedef struct {
	UA_String transportProfileUri;
	UA_PubSubChannel *(*createPubSubChannel)(UA_PubSubConnectionConfig *connectionConfig);
} UA_PubSubTransportLayer;

UA_ServerConfig_addPubSubTransportLayer用于将传输层添加到服务器配置中。列表内存已分配,并将使用UA_PubSubManager_delete释放。


注意:如果UA_String transportProfileUri是动态分配的,则必须在不再需要时释放内存。



注意:在启动服务器之前,必须先运行UA_server_run。


UA_StatusCode
UA_ServerConfig_addPubSubTransportLayer(UA_ServerConfig *config,
									UA_PubSubTransportLayer *pubsubTransportLayer);
#endif /* UA_ENABLE_PUBSUB */

13.6发布/订阅

正在工作!这一部分稍后将是新的一章。
TODO:编写通用PubSub简介
OPC UA的发布/订阅(PubSub)扩展使1:m 通信快速高效。PubSub扩展不依赖协议,可以与基于代理的协议(如MQTT和AMQP)或UDP多播等无代理实现一起使用。
PubSub API使用以下方案:
1.为所需的PubSub元素创建配置。
2.调用add[element]函数并传入配置。
3.add[element]函数返回内部创建的元素的唯一nodeId。
查看PubSub教程,了解有关API用法的mor详细信息:
在这里插入图片描述

13.6.1 PubSub编译标志

UA_ENABLE_PUBSUB启用实验性OPC UA PUBSUB支持。该选项将包括pubsubudp多播插件。默认禁用。
UA_ENABLE_PUBSUB_DELTAFRAMES PUBSUB消息区分keyframe(包含所有已发布的值)和deltaframe(仅包含更改的值)消息。Deltaframe消息创建会消耗一些额外的资源,可以使用此标志禁用。默认禁用。将状态码的可读名称编译为二进制文件。默认禁用。
UA_ENABLE_PUBSUB_INFORMATIONMODEL启用PUBSUB配置的信息模型表示。有关详细信息,请参阅下面的部分PubSub信息模型表示。默认情况下禁用。

13.6.2 PubSub信息模型表示

完整的PubSub配置在信息模型中可用。入口点是节点的PublishSubscribe,位于服务器节点下。该标准为PubSub定义了没有新的服务集。可以选择在信息模型内的方法上进行配置。自动生成当前PubSub配置的信息模型表示。通过更改UA_ENABLE_PUBSUB_INFORMATIONMODEL 选项,可以启用/禁用此功能。

13.6.3连接

PubSub连接是具体传输协议和PubSub之间的抽象功能性。It可以在运行时使用不同的传输协议创建多个连接。
查看PubSub教程,了解有关API用法的mor详细信息。

typedef enum {
	UA_PUBSUB_PUBLISHERID_NUMERIC,
	UA_PUBSUB_PUBLISHERID_STRING
} UA_PublisherIdType;
#ifdef UA_ENABLE_PUBSUB_ETH_UADP_ETF
typedef struct {
	UA_Int32 socketPriority;
	UA_Boolean sotxtimeEnabled;
	/* SO_TXTIME-specific additional socket config */
	UA_Int32 sotxtimeDeadlinemode;
	UA_Int32 sotxtimeReceiveerrors;
} UA_ETFConfiguration;
#endif
typedef struct {
	UA_String name;
	UA_Boolean enabled;
	UA_PublisherIdType publisherIdType;
	union { /* std: valid types UInt or String */
		UA_UInt32 numeric;
		UA_String string;
	} publisherId;
	UA_String transportProfileUri;
	UA_Variant address;
	size_t connectionPropertiesSize;
	UA_KeyValuePair* connectionProperties;
	UA_Variant connectionTransportSettings;
	/* This flag is ’read only’ and is set internally based on the PubSub state. */
	UA_Boolean configurationFrozen;
#ifdef UA_ENABLE_PUBSUB_ETH_UADP_ETF
	/* ETF related connection configuration - Not in PubSub specfication */
	UA_ETFConfiguration etfConfiguration;
#endif
} UA_PubSubConnectionConfig;
UA_StatusCode
UA_Server_addPubSubConnection(UA_Server* server,
	const UA_PubSubConnectionConfig* connectionConfig,
	UA_NodeId* connectionIdentifier);
/* Returns a deep copy of the config */
UA_StatusCode
UA_Server_getPubSubConnectionConfig(UA_Server* server,
	const UA_NodeId connection,
	UA_PubSubConnectionConfig* config);
/* Remove Connection, identified by the NodeId. Deletion of Connection
* removes all contained WriterGroups and Writers. */
UA_StatusCode
UA_Server_removePubSubConnection(UA_Server* server, const UA_NodeId connection);

13.6.4发布的数据集

PublishedDataSets(PDS)是发布信息的容器。PDS包含已发布的变量和元信息。元数据通常是自动生成的,或者作为模板函数的一部分作为常量参数给定。模板函数是标准定义的,用于配置工具。通常应该创建一个空的PDS并调用函数来添加新字段。

/* The UA_PUBSUB_DATASET_PUBLISHEDITEMS has currently no additional members and
* thus no dedicated config structure. */
typedef enum {
	UA_PUBSUB_DATASET_PUBLISHEDITEMS,
	UA_PUBSUB_DATASET_PUBLISHEDEVENTS,
	UA_PUBSUB_DATASET_PUBLISHEDITEMS_TEMPLATE,
	UA_PUBSUB_DATASET_PUBLISHEDEVENTS_TEMPLATE,
} UA_PublishedDataSetType;
typedef struct {
	UA_DataSetMetaDataType metaData;
	size_t variablesToAddSize;
	UA_PublishedVariableDataType* variablesToAdd;
} UA_PublishedDataItemsTemplateConfig;
typedef struct {
	UA_NodeId eventNotfier;
	UA_ContentFilter filter;
} UA_PublishedEventConfig;
typedef struct {
	UA_DataSetMetaDataType metaData;
	UA_NodeId eventNotfier;
	size_t selectedFieldsSize;
	UA_SimpleAttributeOperand* selectedFields;
	UA_ContentFilter filter;
} UA_PublishedEventTemplateConfig;
/* Configuration structure for PublishedDataSet */
typedef struct {
	UA_String name;
	UA_PublishedDataSetType publishedDataSetType;
	union {
		/* The UA_PUBSUB_DATASET_PUBLISHEDITEMS has currently no additional members
		* and thus no dedicated config structure.*/
		UA_PublishedDataItemsTemplateConfig itemsTemplate;
		UA_PublishedEventConfig event;
		UA_PublishedEventTemplateConfig eventTemplate;
	} config;
	/* This flag is ’read only’ and is set internally based on the PubSub state. */
	UA_Boolean configurationFrozen;
} UA_PublishedDataSetConfig;
void
UA_PublishedDataSetConfig_clear(UA_PublishedDataSetConfig* pdsConfig);
typedef struct {
	UA_StatusCode addResult;
	size_t fieldAddResultsSize;
	UA_StatusCode* fieldAddResults;
	UA_ConfigurationVersionDataType configurationVersion;
} UA_AddPublishedDataSetResult;
UA_AddPublishedDataSetResult
UA_Server_addPublishedDataSet(UA_Server* server,
	const UA_PublishedDataSetConfig* publishedDataSetConfig,
	UA_NodeId* pdsIdentifier);
/* Returns a deep copy of the config */
UA_StatusCode
UA_Server_getPublishedDataSetConfig(UA_Server* server, const UA_NodeId pds,
	UA_PublishedDataSetConfig* config);
/* Returns a deep copy of the DataSetMetaData for an specific PDS */
UA_StatusCode
UA_Server_getPublishedDataSetMetaData(UA_Server* server, const UA_NodeId pds,
	UA_DataSetMetaDataType* metaData);
/* Remove PublishedDataSet, identified by the NodeId. Deletion of PDS removes
* all contained and linked PDS Fields. Connected WriterGroups will be also
* removed. */
UA_StatusCode
UA_Server_removePublishedDataSet(UA_Server* server, const UA_NodeId pds);

13.6.5数据集字段

已发布变量的描述名为DataSetField。每个DataSetField包含一个信息模型节点的选择。DataSetField具有用于发布、采样和错误处理过程的其他参数。

typedef struct {
	UA_ConfigurationVersionDataType configurationVersion;
	UA_String fieldNameAlias;
	UA_Boolean promotedField;
	UA_PublishedVariableDataType publishParameters;
	/* non std. field */
	UA_Boolean staticValueSourceEnabled;
	UA_DataValue staticValueSource;
} UA_DataSetVariableConfig;
typedef enum {
	UA_PUBSUB_DATASETFIELD_VARIABLE,
	UA_PUBSUB_DATASETFIELD_EVENT
} UA_DataSetFieldType;
typedef struct {
	UA_DataSetFieldType dataSetFieldType;
	union {
		/* events need other config later */
		UA_DataSetVariableConfig variable;
	} field;
	/* This flag is ’read only’ and is set internally based on the PubSub state. */
	UA_Boolean configurationFrozen;
} UA_DataSetFieldConfig;
void
UA_DataSetFieldConfig_clear(UA_DataSetFieldConfig* dataSetFieldConfig);
typedef struct {
	UA_StatusCode result;
	UA_ConfigurationVersionDataType configurationVersion;
} UA_DataSetFieldResult;
UA_DataSetFieldResult
UA_Server_addDataSetField(UA_Server* server,
	const UA_NodeId publishedDataSet,
	const UA_DataSetFieldConfig* fieldConfig,
	UA_NodeId* fieldIdentifier);
/* Returns a deep copy of the config */
UA_StatusCode
UA_Server_getDataSetFieldConfig(UA_Server* server, const UA_NodeId dsf,
	UA_DataSetFieldConfig* config);
UA_DataSetFieldResult
UA_Server_removeDataSetField(UA_Server* server, const UA_NodeId dsf);

13.6.6写入组

所有WriterGroups都是在PubSubConnection中创建的,如果连接被删除,则会自动删除。WriterGroup主要用作DataSetWriter和网络消息设置的容器。WriterGroup可以想象为网络消息的生产者。网络消息的创建由诸如publish interval之类的参数控制,比如WriterGroup中包含的时间间隔。

typedef enum {
		UA_PUBSUB_ENCODING_BINARY,
		UA_PUBSUB_ENCODING_JSON,
		UA_PUBSUB_ENCODING_UADP
} UA_PubSubEncodingType;

13.6.7 写入组配置

可以根据实时要求配置消息发布。RT-levels 随不同的要求而变化。可以配置以下列出的级别:
UA_PUBSUB_RT_NONE:默认模式。
无要求
无限制
UA_PUBSUB_RT_DIRECT_VALUE_ACCESS:(预览未实现)描述:通常,从信息中读取每个DataSetField的最新值模型。在此RT-mode中,每个字段的值源配置为指向数据值发布周期不会使用调用服务器读取函数。
要求: 所有字段都必须配置“staticValueSource”。
无限制
UA_PUBSUB_RT_FIXED_LENGTH:(预览未实现) :描述:所有数据集字段都有一个已知的、不变的长度服务器将预先生成一些缓冲区,并且只使用memcopy操作来生成请求的PubSub包。
要求:在这种模式下不能使用大小可变的DataSetFields。
限制:当WriterGroup为“Operational”时,必须冻结配置并且不允许更改。
UA_PUBSUB_RT_DETERMINISTIC:(预览未实现) 无要求、无限制。
警告!对于硬实时需求,底层系统必须具有 rt 能力。

typedef enum {
	UA_PUBSUB_RT_NONE = 0,
	UA_PUBSUB_RT_DIRECT_VALUE_ACCESS = 1,
	UA_PUBSUB_RT_FIXED_SIZE = 2,
	UA_PUBSUB_RT_DETERMINISTIC = 4,
} UA_PubSubRTLevel;
typedef struct {
	UA_String name;
	UA_Boolean enabled;
	UA_UInt16 writerGroupId;
	UA_Duration publishingInterval;
	UA_Double keepAliveTime;
	UA_Byte priority;
	UA_MessageSecurityMode securityMode;
	UA_ExtensionObject transportSettings;
	UA_ExtensionObject messageSettings;
	size_t groupPropertiesSize;
	UA_KeyValuePair* groupProperties;
	UA_PubSubEncodingType encodingMimeType;
	/* non std. config parameter. maximum count of embedded DataSetMessage in
	* one NetworkMessage */
	UA_UInt16 maxEncapsulatedDataSetMessageCount;
	/* This flag is ’read only’ and is set internally based on the PubSub state. */
	UA_Boolean configurationFrozen;
	/* non std. field */
	UA_PubSubRTLevel rtLevel;
} UA_WriterGroupConfig;
void
UA_WriterGroupConfig_clear(UA_WriterGroupConfig* writerGroupConfig);
/* Add a new WriterGroup to an existing Connection */
UA_StatusCode
UA_Server_addWriterGroup(UA_Server* server, const UA_NodeId connection,
	const UA_WriterGroupConfig* writerGroupConfig,
	UA_NodeId* writerGroupIdentifier);
/* Returns a deep copy of the config */
UA_StatusCode
UA_Server_getWriterGroupConfig(UA_Server* server, const UA_NodeId writerGroup,
	UA_WriterGroupConfig* config);
UA_StatusCode
UA_Server_updateWriterGroupConfig(UA_Server * server, UA_NodeId writerGroupIdentifier,
	const UA_WriterGroupConfig * config);
UA_StatusCode
UA_Server_removeWriterGroup(UA_Server* server, const UA_NodeId writerGroup);
UA_StatusCode
UA_Server_freezeWriterGroupConfiguration(UA_Server* server, const UA_NodeId writerGroup);
UA_StatusCode
UA_Server_unfreezeWriterGroupConfiguration(UA_Server* server, const UA_NodeId writerGroup);
UA_StatusCode
UA_Server_setWriterGroupOperational(UA_Server* server, const UA_NodeId writerGroup);
UA_StatusCode
UA_Server_setWriterGroupDisabled(UA_Server* server, const UA_NodeId writerGroup);

13.6.8数据网络

数据采集器是WriterGroups和publishedDataset之间的粘合剂。DataSetWriter包含影响数据集消息创建的配置参数和标志。这些消息封装在网络消息中。DataSetWriter必须与现有PublishedDataSet链接,并包含在WriterGroup中。

typedef struct {
	UA_String name;
	UA_UInt16 dataSetWriterId;
	UA_DataSetFieldContentMask dataSetFieldContentMask;
	UA_UInt32 keyFrameCount;
	UA_ExtensionObject messageSettings;
	UA_ExtensionObject transportSettings;
	UA_String dataSetName;
	size_t dataSetWriterPropertiesSize;
	UA_KeyValuePair* dataSetWriterProperties;
	/* This flag is ’read only’ and is set internally based on the PubSub state. */
	UA_Boolean configurationFrozen;
} UA_DataSetWriterConfig;
void
UA_DataSetWriterConfig_clear(UA_DataSetWriterConfig* pdsConfig);
/* Add a new DataSetWriter to a existing WriterGroup. The DataSetWriter must be
* coupled with a PublishedDataSet on creation.
* *
Part 14, 7.1.5.2.1 defines: The link between the PublishedDataSet and
* DataSetWriter shall be created when an instance of the DataSetWriterType is
* created. */
UA_StatusCode
UA_Server_addDataSetWriter(UA_Server* server,
	const UA_NodeId writerGroup, const UA_NodeId dataSet,
	const UA_DataSetWriterConfig* dataSetWriterConfig,
	UA_NodeId* writerIdentifier);
/* Returns a deep copy of the config */
UA_StatusCode
UA_Server_getDataSetWriterConfig(UA_Server* server, const UA_NodeId dsw,
	UA_DataSetWriterConfig* config);
UA_StatusCode
UA_Server_removeDataSetWriter(UA_Server * server, const UA_NodeId dsw);

13.6.9数据采集器

DataSetReader可以接收带有发布者发送的感兴趣数据集的NetworkMessages。datasetreader表示在订阅服务器端接收和处理DataSetMessages所需的配置,

/* Parameters for PubSubSecurity */
typedef struct {
	UA_Int32 securityMode; /* placeholder datatype ’MessageSecurityMode’ */
	UA_String securityGroupId;
	size_t keyServersSize;
	UA_Int32* keyServers;
} UA_PubSubSecurityParameters;
/* Parameters for PubSub DataSetReader Configuration */
typedef struct {
	UA_String name;
	UA_Variant publisherId;
	UA_UInt16 writerGroupId;
	UA_UInt16 dataSetWriterId;
	UA_DataSetMetaDataType dataSetMetaData;
	UA_DataSetFieldContentMask dataSetFieldContentMask;
	UA_Double messageReceiveTimeout;
	UA_PubSubSecurityParameters securityParameters;
	UA_UadpDataSetReaderMessageDataType messageSettings;
	UA_ExtensionObject transportSettings;
	UA_TargetVariablesDataType subscribedDataSetTarget;
} UA_DataSetReaderConfig;
/* Update configuration to the dataSetReader */
UA_StatusCode
UA_Server_DataSetReader_updateConfig(UA_Server* server, UA_NodeId dataSetReaderIdentifier,
	UA_NodeId readerGroupIdentifier, const UA_DataSetReaderConfig*
	/* Get configuration of the dataSetReader */
	UA_StatusCode
	UA_Server_DataSetReader_getConfig(UA_Server* server, UA_NodeId dataSetReaderIdentifier,
		UA_DataSetReaderConfig* config);
/* Return Status Code after creating TargetVariables in Subscriber AddressSpace
* TargetVariables define a list of variable mappings between received DataSet fields
* and the TargetVariables in the Subscriber AddressSpace */
UA_StatusCode
UA_Server_DataSetReader_createTargetVariables(UA_Server* server, UA_NodeId dataSetReaderIdentifier
	UA_TargetVariablesDataType* targetVariables);
/* To Do:Implementation of SubscribedDataSetMirrorType
* UA_StatusCode
* A_PubSubDataSetReader_createDataSetMirror(UA_Server *server, UA_NodeId dataSetReaderIdentifier,
* UA_SubscribedDataSetMirrorDataType* mirror) */

13.6.10读取组

所有readergroup都是在PubSubConnection中创建的,如果连接被删除,则会自动删除。

/* ReaderGroup configuration */
typedef struct {
	UA_String name;
	UA_PubSubSecurityParameters securityParameters;
} UA_ReaderGroupConfig;
/* Add DataSetReader to the ReaderGroup */
UA_StatusCode
UA_Server_addDataSetReader(UA_Server* server, UA_NodeId readerGroupIdentifier,
	const UA_DataSetReaderConfig* dataSetReaderConfig,
	UA_NodeId* readerIdentifier);
/* Remove DataSetReader from ReaderGroup */
UA_StatusCode
UA_Server_removeDataSetReader(UA_Server* server, UA_NodeId readerIdentifier);
/* To Do: Update Configuration of ReaderGroup
* UA_StatusCode
* UA_Server_ReaderGroup_updateConfig(UA_Server *server, UA_NodeId readerGroupIdentifier,
* const UA_ReaderGroupConfig *config);
*/
/* Get configuraiton of ReaderGroup */
UA_StatusCode
UA_Server_ReaderGroup_getConfig(UA_Server* server, UA_NodeId readerGroupIdentifier,
	UA_ReaderGroupConfig* config);
/* Add ReaderGroup to the created connection */
UA_StatusCode
UA_Server_addReaderGroup(UA_Server* server, UA_NodeId connectionIdentifier,
	const UA_ReaderGroupConfig* readerGroupConfig,
	UA_NodeId* readerGroupIdentifier);
/* Remove ReaderGroup from connection */
UA_StatusCode
UA_Server_removeReaderGroup(UA_Server* server, UA_NodeId groupIdentifier);
#endif /* UA_ENABLE_PUBSUB */
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值