连接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