有读者问Client如何监测多个变量值,这篇文章给了提示,但是没给例子,本文给出详细例子,使用的open62541版本是1.3.3, 运行环境debian10.5。
一 准备Server
首先准备一个server,然后添加2个变量,再加个定时任务来修改这2个变量的值,代码如下,
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include "open62541.h"
UA_Boolean running = true;
void stopHandler(int sign) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
running = false;
}
UA_NodeId addTheAnswerVariable(UA_Server *server)
{
UA_VariableAttributes attr = UA_VariableAttributes_default;
UA_Int32 myInteger = 1;
UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
attr.description = UA_LOCALIZEDTEXT((char*)"en-US", (char*)"the answer");
attr.displayName = UA_LOCALIZEDTEXT((char*)"en-US", (char*)"the answer");
attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
UA_NodeId theAnswerNodeId = UA_NODEID_STRING(1, (char*)"the.answer");
UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, (char*)"the answer");
UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
UA_Server_addVariableNode(server, theAnswerNodeId, parentNodeId,
parentReferenceNodeId, myIntegerName,
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), attr, NULL, NULL);
return theAnswerNodeId;
}
UA_NodeId addTheAnswer2Variable(UA_Server *server)
{
UA_VariableAttributes attr = UA_VariableAttributes_default;
UA_Int32 myInteger = 1;
UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
attr.description = UA_LOCALIZEDTEXT((char*)"en-US", (char*)"the answer2");
attr.displayName = UA_LOCALIZEDTEXT((char*)"en-US", (char*)"the answer2");
attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
UA_NodeId theAnswerNodeId = UA_NODEID_STRING(1, (char*)"the.answer2");
UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, (char*)"the answer2");
UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
UA_Server_addVariableNode(server, theAnswerNodeId, parentNodeId,
parentReferenceNodeId, myIntegerName,
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), attr, NULL, NULL);
return theAnswerNodeId;
}
void cycleCallback(UA_Server *server, void *data)
{
static UA_Int32 update = 2;
static UA_Int32 update2 = 8;
UA_NodeId * idArray = (UA_NodeId*)data;
UA_Variant myVar;
UA_Variant_init(&myVar);
UA_Variant_setScalar(&myVar, &update, &UA_TYPES[UA_TYPES_INT32]);
UA_Server_writeValue(server, idArray[0], myVar);
UA_Variant_init(&myVar);
UA_Variant_setScalar(&myVar, &update2, &UA_TYPES[UA_TYPES_INT32]);
UA_Server_writeValue(server, idArray[1], myVar);
update++;
update2++;
if (update == 100)
{
update = 2;
}
if (update2 == 200)
{
update = 8;
}
}
int main(void)
{
signal(SIGINT, stopHandler);
signal(SIGTERM, stopHandler);
UA_Server *server = UA_Server_new();
UA_ServerConfig_setDefault(UA_Server_getConfig(server));
UA_NodeId targetNodeId = addTheAnswerVariable(server);
UA_NodeId target2NodeId = addTheAnswer2Variable(server);
UA_NodeId idArr[2] = {targetNodeId, target2NodeId};
UA_UInt64 callbackId = 0;
UA_Server_addRepeatedCallback(server, cycleCallback, idArr, 2000, &callbackId);
UA_StatusCode retval = UA_Server_run(server, &running);
UA_Server_delete(server);
return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}
这里使用了定时接口来做修改任务。
二 Client代码
代码如下,
#include <stdlib.h>
#include <signal.h>
#include "open62541.h"
UA_Boolean running = true;
UA_NodeId idArr[2] = {UA_NODEID_STRING(1, (char*)"the.answer"), UA_NODEID_STRING(1, (char*)"the.answer2")};
void stopHandler(int sign) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
running = false;
}
static void handler_DataChanged(UA_Client *client, UA_UInt32 subId,
void *subContext, UA_UInt32 monId,
void *monContext, UA_DataValue *value)
{
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_CLIENT, "Received Notification");
UA_NodeId *ptr = (UA_NodeId*)monContext;
if (UA_NodeId_equal(ptr, &idArr[0]))
{
UA_Int32 currentValue = *(UA_Int32*)(value->value.data);
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_CLIENT, "SubId:%u, MonId:%u, Current Value: %d\n",
subId, monId, currentValue);
}
else if (UA_NodeId_equal(ptr, &idArr[1]))
{
UA_Int32 currentValue = *(UA_Int32*)(value->value.data);
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_CLIENT, "SubId:%u, MonId:%u, Current Value: %d\n",
subId, monId, currentValue);
}
}
void addMonitoredItemToVariable(UA_Client *client)
{
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)
{
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_CLIENT, "Create subscription succeeded, id %u\n", subId);
}
UA_MonitoredItemCreateRequest items[2];
UA_UInt32 newMonitoredItemIds[2];
UA_Client_DataChangeNotificationCallback callbacks[2];
UA_Client_DeleteMonitoredItemCallback deleteCallbacks[2];
void *contexts[2];
items[0] = UA_MonitoredItemCreateRequest_default(idArr[0]);
callbacks[0] = handler_DataChanged;
contexts[0] = &idArr[0];
deleteCallbacks[0] = NULL;
items[1] = UA_MonitoredItemCreateRequest_default(idArr[1]);
callbacks[1] = handler_DataChanged;
contexts[1] = &idArr[1];
deleteCallbacks[1] = NULL;
UA_CreateMonitoredItemsRequest createRequest;
UA_CreateMonitoredItemsRequest_init(&createRequest);
createRequest.subscriptionId = subId;
createRequest.timestampsToReturn = UA_TIMESTAMPSTORETURN_BOTH;
createRequest.itemsToCreate = items;
createRequest.itemsToCreateSize = 2;
UA_CreateMonitoredItemsResponse createResponse =
UA_Client_MonitoredItems_createDataChanges(client, createRequest, contexts,
callbacks, deleteCallbacks);
for (uint32_t i = 0; i < createResponse.resultsSize; ++i)
{
if (createResponse.results->statusCode != UA_STATUSCODE_GOOD)
{
printf("==> error\n");
}
}
}
int main(void)
{
signal(SIGINT, stopHandler);
signal(SIGTERM, stopHandler);
UA_Client *client = UA_Client_new();
UA_ClientConfig_setDefault(UA_Client_getConfig(client));
UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
if(retval != UA_STATUSCODE_GOOD)
{
UA_Client_delete(client);
return (int)retval;
}
addMonitoredItemToVariable(client);
while(running)
{
UA_Client_run_iterate(client, 1000);
}
UA_Client_delete(client);
return EXIT_SUCCESS;
}
关键部分在addMonitoredItemToVariable()里,其实也比较简单,就是挨个赋值,2个监测项都使用相同的回调函数,里面会判断节点的nodeid,注意代码里使用了一个全局数组idArr来保存目标id。
三 运行
如何编译不再赘述,最后运行如下,
可以看到MonId是不同的,说明监测成功!
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)