其他分享
首页 > 其他分享> > OPC UA认知笔记之三

OPC UA认知笔记之三

作者:互联网

读写变量节点,callback和datasource两种方式真的有区别吗?

这个问题是其实是很多初接触open62541应用普遍会遇到的问题,按照网上比较一致的解释是:一个设置了读写回调的节点,客户端对其读写操作是对变量节点所包含的变量进行操作;而一个设置了可变数据源的变量节点,客户端对其读写操作同样是对变量节点所包含的变量进行操作,但是由于该变量节点包含的变量已经同一个内存进行了映射,相当于客户端穿过了该变量节点直接读写了该内存中的数据。

不过,以上解释似乎不能让人心服口服,请看一段程序:
#include "open62541.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <stdlib.h>

static UA_Int32 externValue = 32; // global value for callback and datasource
static volatile UA_Boolean running = true;

static void stopHandler(int sig) {  
    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "received ctrl-c");  
    running = false;  
}

static void beforeReadData(UA_Server *server,  
               const UA_NodeId *sessionId, void *sessionContext,  
               const UA_NodeId *nodeid, void *nodeContext,  
               const UA_NumericRange *range, const UA_DataValue *data) { 
    UA_Variant_setScalarCopy(&dataValue->value, &externValue, &UA_TYPES[UA_TYPES_INT32]);
    UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "read callback"); 
}

static UA_StatusCode readCurrentData(UA_Server *server,
                const UA_NodeId *sessionId, void *sessionContext,
                const UA_NodeId *nodeId, void *nodeContext,
                UA_Boolean sourceTimeStamp, const UA_NumericRange *range,
                UA_DataValue *dataValue) {
    UA_Variant_setScalarCopy(&dataValue->value, &externValue, &UA_TYPES[UA_TYPES_INT32]);
    UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "read data source"); 
    return UA_STATUSCODE_GOOD;
}

static void addDataSourceToDataVariable(UA_Server *server) {  
    UA_NodeId currentNodeId = UA_NODEID_STRING(1, "v-dataSource");  
    UA_DataSource ds;  
    ds.read = readCurrentData;
    ds.write = NULL;
    UA_Server_setVariableNode_dataSource(server, currentNodeId, ds);  
}

static void addCallbackToDataVariable(UA_Server *server) {  
    UA_NodeId currentNodeId = UA_NODEID_STRING(1, "v-callBack");  
    UA_ValueCallback callback;  
    callback.onRead = beforeReadData;
    callback.onWrite = NULL;
    UA_Server_setVariableNode_valueCallback(server, currentNodeId, callback);  
}

static void addVariable(UA_Server *server, char *name) {
    UA_VariableAttributes attr = UA_VariableAttributes_default;
    attr.description = UA_LOCALIZEDTEXT("en-US", name);
    attr.displayName = UA_LOCALIZEDTEXT("en-US", name);
    attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
    attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
    UA_NodeId oldNodeId = UA_NODEID_STRING(1, name);
    UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, name);
    UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
    UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
    UA_NodeId typeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
    UA_Server_addVariableNode(server, oldNodeId, parentNodeId, parentReferenceNodeId,
                              myIntegerName, typeNodeId, attr, NULL, NULL);
}

int main() {  
    signal(SIGINT, stopHandler);  
    signal(SIGTERM, stopHandler);  
   
    UA_Server *server = UA_Server_new();   
    UA_ServerConfig* config = UA_Server_getConfig(server);  
    config->verifyRequestTimestamp = UA_RULEHANDLING_ACCEPT;
    UA_ServerConfig_setMinimal(config, 5566, NULL);

    addVariable(server, "v-callBack");
    addVariable(server, "v-dataSource");
    addDataSourceToDataVariable(server);
    addCallbackToDataVariable(server);
    addchangeDataMethod(server);

    UA_StatusCode retval = UA_Server_run(server, &running);  
    UA_Server_delete(server);  
    return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;  
}

在通过server程序的编译时,callback有一个可以忽略的warning,如下所示。

server.c: In function ‘beforeReadData’:
server.c:48:30: warning: passing argument 1 of ‘UA_Variant_setScalarCopy’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
UA_Variant_setScalarCopy(&data->value, &externValue, &UA_TYPES[UA_TYPES_INT32]);

其实这个warning时可以忽略的,server应用程序可以正常运行,server应用程序创建了两个变量节点“v-callBack”和“v-dataSource”,而且使分别用beforeReadData和readCurrentData两个函数来让UaExpert客户端读取变量节点,通过比较可以发现两种方式的读操作效果几乎没有差别,callBack的方式似乎也可以直接和“老板谈”(直接读取变量)。看来这段代码似乎不能分辨两种操作方式的区别,权且记录一下,以备今后再解释。

标签:const,之三,NodeId,server,OPC,Server,UA,void
来源: https://www.cnblogs.com/ChenMichael/p/16397455.html