open62541 linux编译,open62541学习

本文详细介绍OPCUA客户端如何连接服务、浏览节点、读写指定节点数据及订阅模式的操作方法,并提供了添加新节点的初步指导。

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

连接OPC UA服务

UA_Client *client = UA_Client_new(UA_ClientConfig_default);

char *uri = "opc.tcp://127.0.0.1:49320";

retval = UA_Client_connect(client, uri);

if (retval != UA_STATUSCODE_GOOD)

{

UA_Client_delete(client);

return (int)retval;

}

这里还可以用指定用户名和密码去连接,连接函数原型为:但是我没有测试

UA_StatusCode

UA_Client_connect_username(UA_Client *client, const char *endpointUrl,

const char *username, const char *password) {

client->authenticationMethod = UA_CLIENTAUTHENTICATION_USERNAME;

client->username = UA_STRING_ALLOC(username);

client->password = UA_STRING_ALLOC(password);

return UA_Client_connect(client, endpointUrl);

}

浏览指定节点下NODE

static void BrowseNode(UA_Client *client,char* nodeIdStr)

{

/* Browse some objects */

if (nodeIdStr == NULL)

{

printf("nodeIdStr == NULL");

return;

}

printf("Browsing nodes in objects folder:

");

UA_NodeId nodeId = UA_NODEID_STRING(2, nodeIdStr);

//UA_NodeId nodeId = UA_NODEID_NUMERIC(0, 8);

UA_BrowseRequest bReq ;

UA_BrowseRequest_init(&bReq);

bReq.requestedMaxReferencesPerNode = 0;

bReq.nodesToBrowse = UA_BrowseDescription_new();

bReq.nodesToBrowseSize = 1;

bReq.nodesToBrowse[0].nodeId = nodeId;

bReq.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL; /* return everything */

UA_BrowseResponse bResp = UA_Client_Service_browse(client, bReq);

printf("%-9s %-16s %-16s %-16s

", "NAMESPACE", "NODEID", "BROWSE NAME", "DISPLAY NAME");

for (size_t i = 0; i < bResp.resultsSize; ++i) {

for (size_t j = 0; j < bResp.results[i].referencesSize; ++j) {

UA_ReferenceDescription *ref = &(bResp.results[i].references[j]);

if (ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_NUMERIC) {

printf("%-9d %-16d %-16.*s %-16.*s

", ref->nodeId.nodeId.namespaceIndex,

ref->nodeId.nodeId.identifier.numeric, (int)ref->browseName.name.length,

ref->browseName.name.data, (int)ref->displayName.text.length,

ref->displayName.text.data);

}

else if (ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_STRING) {

printf("%-9d %-16.*s %-16.*s %-16.*s

", ref->nodeId.nodeId.namespaceIndex,

(int)ref->nodeId.nodeId.identifier.string.length,

ref->nodeId.nodeId.identifier.string.data,

(int)ref->browseName.name.length, ref->browseName.name.data,

(int)ref->displayName.text.length, ref->displayName.text.data);

}

}

}

UA_BrowseDescription_deleteMembers(&bReq);

//UA_BrowseRequest_deleteMembers(&bReq);

UA_BrowseResponse_deleteMembers(&bResp);

}

这里遇到个小问题,其实应该用UA_BrowseRequest_deleteMembers(&bReq);来释放资源,浏览根节点释放资源时没问题,指定Node去浏览后 释放就报错,这样写同样可以起到释放的效果。

UA_BrowseDescription_deleteMembers(&bReq);

这里还有一种枚举指定节点下NODE的方法

UA_NodeId *parent = UA_NodeId_new();

*parent = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);

UA_Client_forEachChildNodeCall(client, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),

nodeIter, (void *)parent);

UA_NodeId_delete(parent);

static UA_StatusCode

nodeIter(UA_NodeId childId, UA_Boolean isInverse, UA_NodeId referenceTypeId, void *handle) {

if (isInverse)

return UA_STATUSCODE_GOOD;

UA_NodeId *parent = (UA_NodeId *)handle;

printf("%d, %d --- %d ---> NodeId %d, %d

",

parent->namespaceIndex, parent->identifier.numeric,

referenceTypeId.identifier.numeric, childId.namespaceIndex,

childId.identifier.numeric);

return UA_STATUSCODE_GOOD;

}

每个子节点会以回调的方式反馈给我们。

读指定Node

UA_Variant *val = UA_Variant_new();

UA_LocalizedText outDisplayName;

UA_NodeId nodeId = UA_NODEID_STRING(2, nodeIdStr);

//CX62KX63.ER.Queue.CarVin

//CX62KX63.ER.Queue.Request

UA_StatusCode retval = UA_Client_readValueAttribute(client, nodeId, val);

主动读的时候需要注意,根据指定node的数据类型指定类型来接收,不然可能拿不到或者拿到错误的数据,因为C语言嘛,比较基于内存。

读的时候很灵活可以用底层的

__UA_Client_readAttribute(UA_Client *client, const UA_NodeId *nodeId,

UA_AttributeId attributeId, void *out,

const UA_DataType *outDataType);

指定UA_AttributeId 去读。但是推荐使用包装后的读取方式,官方文档上有说明

static UA_INLINE UA_StatusCode

UA_Client_readNodeIdAttribute(UA_Client *client, const UA_NodeId nodeId,

UA_NodeId *outNodeId) {

return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_NODEID,

outNodeId, &UA_TYPES[UA_TYPES_NODEID]);

}

static UA_INLINE UA_StatusCode

UA_Client_readNodeClassAttribute(UA_Client *client, const UA_NodeId nodeId,

UA_NodeClass *outNodeClass) {

return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_NODECLASS,

outNodeClass, &UA_TYPES[UA_TYPES_NODECLASS]);

}

static UA_INLINE UA_StatusCode

UA_Client_readBrowseNameAttribute(UA_Client *client, const UA_NodeId nodeId,

UA_QualifiedName *outBrowseName) {

return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_BROWSENAME,

outBrowseName,

&UA_TYPES[UA_TYPES_QUALIFIEDNAME]);

}

static UA_INLINE UA_StatusCode

UA_Client_readDisplayNameAttribute(UA_Client *client, const UA_NodeId nodeId,

UA_LocalizedText *outDisplayName) {

return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME,

outDisplayName,

&UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);

}

static UA_INLINE UA_StatusCode

UA_Client_readDescriptionAttribute(UA_Client *client, const UA_NodeId nodeId,

UA_LocalizedText *outDescription) {

return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_DESCRIPTION,

outDescription,

&UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);

}

static UA_INLINE UA_StatusCode

UA_Client_readWriteMaskAttribute(UA_Client *client, const UA_NodeId nodeId,

UA_UInt32 *outWriteMask) {

return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_WRITEMASK,

outWriteMask, &UA_TYPES[UA_TYPES_UINT32]);

}

static UA_INLINE UA_StatusCode

UA_Client_readUserWriteMaskAttribute(UA_Client *client, const UA_NodeId nodeId,

UA_UInt32 *outUserWriteMask) {

return __UA_Client_readAttribute(client, &nodeId,

UA_ATTRIBUTEID_USERWRITEMASK,

outUserWriteMask,

&UA_TYPES[UA_TYPES_UINT32]);

}

static UA_INLINE UA_StatusCode

UA_Client_readIsAbstractAttribute(UA_Client *client, const UA_NodeId nodeId,

UA_Boolean *outIsAbstract) {

return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_ISABSTRACT,

outIsAbstract, &UA_TYPES[UA_TYPES_BOOLEAN]);

}

static UA_INLINE UA_StatusCode

UA_Client_readSymmetricAttribute(UA_Client *client, const UA_NodeId nodeId,

UA_Boolean *outSymmetric) {

return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_SYMMETRIC,

outSymmetric, &UA_TYPES[UA_TYPES_BOOLEAN]);

}

static UA_INLINE UA_StatusCode

UA_Client_readInverseNameAttribute(UA_Client *client, const UA_NodeId nodeId,

UA_LocalizedText *outInverseName) {

return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_INVERSENAME,

outInverseName,

&UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);

}

static UA_INLINE UA_StatusCode

UA_Client_readContainsNoLoopsAttribute(UA_Client *client, const UA_NodeId nodeId,

UA_Boolean *outContainsNoLoops) {

return __UA_Client_readAttribute(client, &nodeId,

UA_ATTRIBUTEID_CONTAINSNOLOOPS,

outContainsNoLoops,

&UA_TYPES[UA_TYPES_BOOLEAN]);

}

static UA_INLINE UA_StatusCode

UA_Client_readEventNotifierAttribute(UA_Client *client, const UA_NodeId nodeId,

UA_Byte *outEventNotifier) {

return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER,

outEventNotifier, &UA_TYPES[UA_TYPES_BYTE]);

}

static UA_INLINE UA_StatusCode

UA_Client_readValueAttribute(UA_Client *client, const UA_NodeId nodeId,

UA_Variant *outValue) {

return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUE,

outValue, &UA_TYPES[UA_TYPES_VARIANT]);

}

static UA_INLINE UA_StatusCode

UA_Client_readDataTypeAttribute(UA_Client *client, const UA_NodeId nodeId,

UA_NodeId *outDataType) {

return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_DATATYPE,

outDataType, &UA_TYPES[UA_TYPES_NODEID]);

}

static UA_INLINE UA_StatusCode

UA_Client_readValueRankAttribute(UA_Client *client, const UA_NodeId nodeId,

UA_Int32 *outValueRank) {

return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUERANK,

outValueRank, &UA_TYPES[UA_TYPES_INT32]);

}

UA_StatusCode UA_EXPORT

UA_Client_readArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId,

size_t *outArrayDimensionsSize,

UA_UInt32 **outArrayDimensions);

static UA_INLINE UA_StatusCode

UA_Client_readAccessLevelAttribute(UA_Client *client, const UA_NodeId nodeId,

UA_Byte *outAccessLevel) {

return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL,

outAccessLevel, &UA_TYPES[UA_TYPES_BYTE]);

}

static UA_INLINE UA_StatusCode

UA_Client_readUserAccessLevelAttribute(UA_Client *client, const UA_NodeId nodeId,

UA_Byte *outUserAccessLevel) {

return __UA_Client_readAttribute(client, &nodeId,

UA_ATTRIBUTEID_USERACCESSLEVEL,

outUserAccessLevel,

&UA_TYPES[UA_TYPES_BYTE]);

}

static UA_INLINE UA_StatusCode

UA_Client_readMinimumSamplingIntervalAttribute(UA_Client *client,

const UA_NodeId nodeId,

UA_Double *outMinSamplingInterval) {

return __UA_Client_readAttribute(client, &nodeId,

UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL,

outMinSamplingInterval,

&UA_TYPES[UA_TYPES_DOUBLE]);

}

static UA_INLINE UA_StatusCode

UA_Client_readHistorizingAttribute(UA_Client *client, const UA_NodeId nodeId,

UA_Boolean *outHistorizing) {

return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_HISTORIZING,

outHistorizing, &UA_TYPES[UA_TYPES_BOOLEAN]);

}

static UA_INLINE UA_StatusCode

UA_Client_readExecutableAttribute(UA_Client *client, const UA_NodeId nodeId,

UA_Boolean *outExecutable) {

return __UA_Client_readAttribute(client, &nodeId, UA_ATTRIBUTEID_EXECUTABLE,

outExecutable, &UA_TYPES[UA_TYPES_BOOLEAN]);

}

static UA_INLINE UA_StatusCode

UA_Client_readUserExecutableAttribute(UA_Client *client, const UA_NodeId nodeId,

UA_Boolean *outUserExecutable) {

return __UA_Client_readAttribute(client, &nodeId,

UA_ATTRIBUTEID_USEREXECUTABLE,

outUserExecutable,

&UA_TYPES[UA_TYPES_BOOLEAN]);

}

看这些函数命名,几乎不用注释就可以猜到每个函数读的是什么内容。

写指定Node

static bool WriteValue(UA_Client *client,char* nodeIdStr,void *value,UINT type)

{

boolean result = true;

UA_Variant *myVariant = UA_Variant_new();

UA_NodeId nodeId = UA_NODEID_STRING(2, nodeIdStr);

UA_StatusCode code = UA_Variant_setScalarCopy(myVariant, value, &UA_TYPES[type]);

if(code != UA_STATUSCODE_GOOD)

{

result = false;

UA_Variant_delete(myVariant);

return result;

}

code=UA_Client_writeValueAttribute(client, nodeId, myVariant);

if (code != UA_STATUSCODE_GOOD)

{

result = false;

UA_Variant_delete(myVariant);

return result;

}

UA_Variant_delete(myVariant);

return result;

}

我是测试写了个字符串,因为相对字符串要比int、bool这些基本类型字符串读写的时候更需要注意。

和读一样,写也有一个比较低级的函数

UA_StatusCode UA_EXPORT

__UA_Client_writeAttribute(UA_Client *client, const UA_NodeId *nodeId,

UA_AttributeId attributeId, const void *in,

const UA_DataType *inDataType);

指定UA_AttributeId 去写。但是推荐比较高级的包装函数。

static UA_INLINE UA_StatusCode

UA_Client_writeNodeIdAttribute(UA_Client *client, const UA_NodeId nodeId,

const UA_NodeId *newNodeId) {

return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_NODEID,

newNodeId, &UA_TYPES[UA_TYPES_NODEID]);

}

static UA_INLINE UA_StatusCode

UA_Client_writeNodeClassAttribute(UA_Client *client, const UA_NodeId nodeId,

const UA_NodeClass *newNodeClass) {

return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_NODECLASS,

newNodeClass, &UA_TYPES[UA_TYPES_NODECLASS]);

}

static UA_INLINE UA_StatusCode

UA_Client_writeBrowseNameAttribute(UA_Client *client, const UA_NodeId nodeId,

const UA_QualifiedName *newBrowseName) {

return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_BROWSENAME,

newBrowseName,

&UA_TYPES[UA_TYPES_QUALIFIEDNAME]);

}

static UA_INLINE UA_StatusCode

UA_Client_writeDisplayNameAttribute(UA_Client *client, const UA_NodeId nodeId,

const UA_LocalizedText *newDisplayName) {

return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME,

newDisplayName,

&UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);

}

static UA_INLINE UA_StatusCode

UA_Client_writeDescriptionAttribute(UA_Client *client, const UA_NodeId nodeId,

const UA_LocalizedText *newDescription) {

return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_DESCRIPTION,

newDescription,

&UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);

}

static UA_INLINE UA_StatusCode

UA_Client_writeWriteMaskAttribute(UA_Client *client, const UA_NodeId nodeId,

const UA_UInt32 *newWriteMask) {

return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_WRITEMASK,

newWriteMask, &UA_TYPES[UA_TYPES_UINT32]);

}

static UA_INLINE UA_StatusCode

UA_Client_writeUserWriteMaskAttribute(UA_Client *client, const UA_NodeId nodeId,

const UA_UInt32 *newUserWriteMask) {

return __UA_Client_writeAttribute(client, &nodeId,

UA_ATTRIBUTEID_USERWRITEMASK,

newUserWriteMask,

&UA_TYPES[UA_TYPES_UINT32]);

}

static UA_INLINE UA_StatusCode

UA_Client_writeIsAbstractAttribute(UA_Client *client, const UA_NodeId nodeId,

const UA_Boolean *newIsAbstract) {

return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_ISABSTRACT,

newIsAbstract, &UA_TYPES[UA_TYPES_BOOLEAN]);

}

static UA_INLINE UA_StatusCode

UA_Client_writeSymmetricAttribute(UA_Client *client, const UA_NodeId nodeId,

const UA_Boolean *newSymmetric) {

return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_SYMMETRIC,

newSymmetric, &UA_TYPES[UA_TYPES_BOOLEAN]);

}

static UA_INLINE UA_StatusCode

UA_Client_writeInverseNameAttribute(UA_Client *client, const UA_NodeId nodeId,

const UA_LocalizedText *newInverseName) {

return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_INVERSENAME,

newInverseName,

&UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);

}

static UA_INLINE UA_StatusCode

UA_Client_writeContainsNoLoopsAttribute(UA_Client *client, const UA_NodeId nodeId,

const UA_Boolean *newContainsNoLoops) {

return __UA_Client_writeAttribute(client, &nodeId,

UA_ATTRIBUTEID_CONTAINSNOLOOPS,

newContainsNoLoops,

&UA_TYPES[UA_TYPES_BOOLEAN]);

}

static UA_INLINE UA_StatusCode

UA_Client_writeEventNotifierAttribute(UA_Client *client, const UA_NodeId nodeId,

const UA_Byte *newEventNotifier) {

return __UA_Client_writeAttribute(client, &nodeId,

UA_ATTRIBUTEID_EVENTNOTIFIER,

newEventNotifier,

&UA_TYPES[UA_TYPES_BYTE]);

}

static UA_INLINE UA_StatusCode

UA_Client_writeValueAttribute(UA_Client *client, const UA_NodeId nodeId,

const UA_Variant *newValue) {

return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUE,

newValue, &UA_TYPES[UA_TYPES_VARIANT]);

}

static UA_INLINE UA_StatusCode

UA_Client_writeDataTypeAttribute(UA_Client *client, const UA_NodeId nodeId,

const UA_NodeId *newDataType) {

return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_DATATYPE,

newDataType, &UA_TYPES[UA_TYPES_NODEID]);

}

static UA_INLINE UA_StatusCode

UA_Client_writeValueRankAttribute(UA_Client *client, const UA_NodeId nodeId,

const UA_Int32 *newValueRank) {

return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_VALUERANK,

newValueRank, &UA_TYPES[UA_TYPES_INT32]);

}

UA_StatusCode UA_EXPORT

UA_Client_writeArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId,

size_t newArrayDimensionsSize,

const UA_UInt32 *newArrayDimensions);

static UA_INLINE UA_StatusCode

UA_Client_writeAccessLevelAttribute(UA_Client *client, const UA_NodeId nodeId,

const UA_Byte *newAccessLevel) {

return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL,

newAccessLevel, &UA_TYPES[UA_TYPES_BYTE]);

}

static UA_INLINE UA_StatusCode

UA_Client_writeUserAccessLevelAttribute(UA_Client *client, const UA_NodeId nodeId,

const UA_Byte *newUserAccessLevel) {

return __UA_Client_writeAttribute(client, &nodeId,

UA_ATTRIBUTEID_USERACCESSLEVEL,

newUserAccessLevel,

&UA_TYPES[UA_TYPES_BYTE]);

}

static UA_INLINE UA_StatusCode

UA_Client_writeMinimumSamplingIntervalAttribute(UA_Client *client,

const UA_NodeId nodeId,

const UA_Double *newMinInterval) {

return __UA_Client_writeAttribute(client, &nodeId,

UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL,

newMinInterval, &UA_TYPES[UA_TYPES_DOUBLE]);

}

static UA_INLINE UA_StatusCode

UA_Client_writeHistorizingAttribute(UA_Client *client, const UA_NodeId nodeId,

const UA_Boolean *newHistorizing) {

return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_HISTORIZING,

newHistorizing, &UA_TYPES[UA_TYPES_BOOLEAN]);

}

static UA_INLINE UA_StatusCode

UA_Client_writeExecutableAttribute(UA_Client *client, const UA_NodeId nodeId,

const UA_Boolean *newExecutable) {

return __UA_Client_writeAttribute(client, &nodeId, UA_ATTRIBUTEID_EXECUTABLE,

newExecutable, &UA_TYPES[UA_TYPES_BOOLEAN]);

}

static UA_INLINE UA_StatusCode

UA_Client_writeUserExecutableAttribute(UA_Client *client, const UA_NodeId nodeId,

const UA_Boolean *newUserExecutable) {

return __UA_Client_writeAttribute(client, &nodeId,

UA_ATTRIBUTEID_USEREXECUTABLE,

newUserExecutable,

&UA_TYPES[UA_TYPES_BOOLEAN]);

}

函数命名几乎和读一样,根据函数名称一目了然。

订阅模式

static void

handler_TheAnswerChanged(UA_Client *client, UA_UInt32 subId, void *subContext,

UA_UInt32 monId, void *monContext, UA_DataValue *value) {

UA_String valueStr = *(UA_String*)value->value.data;

printf("The Answer has changed! %s

",valueStr.data);

}

UA_CreateSubscriptionRequest request = UA_CreateSubscriptionRequest_default();

UA_CreateSubscriptionResponse response = UA_Client_Subscriptions_create(client, request,

NULL, NULL, NULL);

UA_UInt32 subId = response.subscriptionId;

if (response.responseHeader.serviceResult == UA_STATUSCODE_GOOD)

printf("Create subscription succeeded, id %u

", subId);

UA_MonitoredItemCreateRequest monRequest =

UA_MonitoredItemCreateRequest_default(UA_NODEID_STRING(2, "CX62KX63.ER.Queue.CarVin"));

UA_MonitoredItemCreateResult monResponse =

UA_Client_MonitoredItems_createDataChange(client, response.subscriptionId,

UA_TIMESTAMPSTORETURN_BOTH,

monRequest, NULL, handler_TheAnswerChanged, NULL);

if (monResponse.statusCode == UA_STATUSCODE_GOOD)

printf("Monitoring 'the.answer', id %u

", monResponse.monitoredItemId);

//UA_Client_Subscriptions_manuallySendPublishRequest(client);

UA_StatusCode code = UA_Client_run_iterate(client, 10);  //lw这里报错,所以先注释掉

对于订阅模式,open62541.c 和 open62541.h和源代码不一致,找不到UA_StatusCode code = UA_Client_run_iterate(client, 10);这个函数(其实用了这个函数程序就编译不过去,我这里是因为我把源代码的一些东西拿过来了,所以能编译过)。也可以不用这个函数,用UA_Client_Subscriptions_manuallySendPublishRequest(client);这个函数,但是这个函数被标记废弃了

不过我测试了下,还可以用。

未测试的功能

添加NODE

/* Add new nodes*/

/* New ReferenceType */

UA_NodeId ref_id;

UA_ReferenceTypeAttributes ref_attr = UA_ReferenceTypeAttributes_default;

ref_attr.displayName = UA_LOCALIZEDTEXT("en-US", "NewReference");

ref_attr.description = UA_LOCALIZEDTEXT("en-US", "References something that might or might not exist");

ref_attr.inverseName = UA_LOCALIZEDTEXT("en-US", "IsNewlyReferencedBy");

retval = UA_Client_addReferenceTypeNode(client,

UA_NODEID_NUMERIC(1, 12133),

UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),

UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),

UA_QUALIFIEDNAME(1, "NewReference"),

ref_attr, &ref_id);

if (retval == UA_STATUSCODE_GOOD)

printf("Created 'NewReference' with numeric NodeID %u

", ref_id.identifier.numeric);

/* New ObjectType */

UA_NodeId objt_id;

UA_ObjectTypeAttributes objt_attr = UA_ObjectTypeAttributes_default;

objt_attr.displayName = UA_LOCALIZEDTEXT("en-US", "TheNewObjectType");

objt_attr.description = UA_LOCALIZEDTEXT("en-US", "Put innovative description here");

retval = UA_Client_addObjectTypeNode(client,

UA_NODEID_NUMERIC(1, 12134),

UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),

UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),

UA_QUALIFIEDNAME(1, "NewObjectType"),

objt_attr, &objt_id);

if (retval == UA_STATUSCODE_GOOD)

printf("Created 'NewObjectType' with numeric NodeID %u

", objt_id.identifier.numeric);

/* New Object */

UA_NodeId obj_id;

UA_ObjectAttributes obj_attr = UA_ObjectAttributes_default;

obj_attr.displayName = UA_LOCALIZEDTEXT("en-US", "TheNewGreatNode");

obj_attr.description = UA_LOCALIZEDTEXT("de-DE", "Hier koennte Ihre Webung stehen!");

retval = UA_Client_addObjectNode(client,

UA_NODEID_NUMERIC(1, 0),

UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),

UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),

UA_QUALIFIEDNAME(1, "TheGreatNode"),

UA_NODEID_NUMERIC(1, 12134),

obj_attr, &obj_id);

if (retval == UA_STATUSCODE_GOOD)

printf("Created 'NewObject' with numeric NodeID %u

", obj_id.identifier.numeric);

/* New Integer Variable */

UA_NodeId var_id;

UA_VariableAttributes var_attr = UA_VariableAttributes_default;

var_attr.displayName = UA_LOCALIZEDTEXT("en-US", "TheNewVariableNode");

var_attr.description =

UA_LOCALIZEDTEXT("en-US", "This integer is just amazing - it has digits and everything.");

UA_Int32 int_value = 1234;

/* This does not copy the value */

UA_Variant_setScalar(&var_attr.value, &int_value, &UA_TYPES[UA_TYPES_INT32]);

var_attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;

retval = UA_Client_addVariableNode(client,

UA_NODEID_NUMERIC(1, 0), // Assign new/random NodeID

UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),

UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),

UA_QUALIFIEDNAME(0, "VariableNode"),

UA_NODEID_NULL, // no variable type

var_attr, &var_id);

if (retval == UA_STATUSCODE_GOOD)

printf("Created 'NewVariable' with numeric NodeID %u

", var_id.identifier.numeric);

这个功能我暂时还没有测试,等有时间再深入研究。

结束

---------------------

作者:liwen9016

来源:优快云

原文:https://blog.youkuaiyun.com/liwen9016/article/details/81982662

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值