open62541-server编程

open62541--Server

1、服务构建

#include <signal.h>
#include "open62541.h"
UA_Boolean running = true; //服务器的启停标志
static void stopHandler(int sig) 
{
    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "received ctrl-c");
    running = false;
}
int main(void) 
{
    signal(SIGINT, stopHandler);
    signal(SIGTERM, stopHandler);
    //server->config进行缺省化配置。(部分参数按照系统定义配置)
	UA_ServerConfig *config = UA_ServerConfig_new_default();
    /*
	 * 缺省配置后也可进行自定义修改。
	config->customHostname.data = "192.168.0.108";
    config->customHostname.length = 14;
	*/
	UA_Server *server = UA_Server_new(config); 
    UA_StatusCode retval = UA_Server_run(server, &running); //启动server
    UA_Server_delete(server);
    UA_ServerConfig_delete(config);
    return (int)retval;
}

2、 变量类型(variable)节点的添加

static void addVariable(UA_Server *server)
{
    /*变量节点的属性*/
    UA_VariableAttributes attr = UA_VariableAttributes_default;
    UA_Int32 myInteger = 1024;
	//节点数据的设置attr.value
	//P1:节点的数据属性 P2:要设置的数据 P3:数据的数据类型
    UA_Variant_setScalar(&attr.value,&myInteger,&UA_TYPES[UA_TYPES_INT32]);
	//节点在用户接口显示的名字(本地化)
    attr.description = UA_LOCALIZEDTEXT("en-US","the answer");
	//节点在自身本地化描述
    attr.displayName = UA_LOCALIZEDTEXT("en-US","the answer");
    attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
	//变量节点的访问权限:可读可写
    attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;

 
    /*定义1个节点:节点的命名空间 节点的ID标识符*/
    UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1,"the.answer");
	//节点对外的浏览名称(非本地化)
    UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1,"the answer");
	
	//定义1个节点
    UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0,UA_NS0ID_OBJECTSFOLDER);
	
	//定义1个节点
    UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0,UA_NS0ID_ORGANIZES);
    /*************************************************************
	UA_Server_addVariableNode(UA_Server *server,  // 服务
					      const UA_NodeId requestedNewNodeId, //请求添加的节点
                          const UA_NodeId parentNodeId,      //父节点
                          const UA_NodeId referenceTypeId,   //父节点引用类型节点	
                          const UA_QualifiedName browseName, //节点对外的浏览名称(非本地化)
                          const UA_NodeId typeDefinition,	 //引用节点
                          const UA_VariableAttributes attr,
                          void *nodeContext, UA_NodeId *outNewNodeId)
	**************************************************************/
	
	UA_Server_addVariableNode(server,myIntegerNodeId,parentNodeId,

                              parentReferenceNodeId,myIntegerName,

                              UA_NODEID_NUMERIC(0,UA_NS0ID_BASEDATAVARIABLETYPE),

                              attr,NULL,NULL);

}

2.1、变量节点数据的更新

2.1.1、手动更新

#include <signal.h>
#include "open62541.h"
static void
updateCurrentTime(UA_Server *server) {
    UA_DateTime now = UA_DateTime_now();
    UA_Variant value;
    UA_Variant_setScalar(&value, &now, &UA_TYPES[UA_TYPES_DATETIME]);
    UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time");
    UA_Server_writeValue(server, currentNodeId, value);
}
static void
addCurrentTimeVariable(UA_Server *server) {
    UA_DateTime now = 0;
    UA_VariableAttributes attr = UA_VariableAttributes_default;
    attr.displayName = UA_LOCALIZEDTEXT("en-US", "Current time");
    attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
    UA_Variant_setScalar(&attr.value, &now, &UA_TYPES[UA_TYPES_DATETIME]);
    UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time");
    UA_QualifiedName currentName = UA_QUALIFIEDNAME(1, "current-time");
    UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
    UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
    UA_NodeId variableTypeNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
    UA_Server_addVariableNode(server, currentNodeId, parentNodeId,
                              parentReferenceNodeId, currentName,
                              variableTypeNodeId, attr, NULL, NULL);
    //手动更新变量值
	updateCurrentTime(server);
}

2.1.3、客户端访问时通过回调函数更新

//方法一:当值连续变化时,手动更新值将占用大量资源。值回调允许将变量值与外部进行同步,它们将回调附加到在每次读取之前和每次写入操作之后执行的变量。

static void
beforeReadTime(UA_Server *server,
               const UA_NodeId *sessionId, void *sessionContext,
               const UA_NodeId *nodeid, void *nodeContext,
               const UA_NumericRange *range, const UA_DataValue *data) {
    UA_DateTime now = UA_DateTime_now();
    UA_Variant value;
    UA_Variant_setScalar(&value, &now, &UA_TYPES[UA_TYPES_DATETIME]);
    UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time");
    UA_Server_writeValue(server, currentNodeId, value);
}
//方法二:对于连续变化的数据,
static UA_StatusCode
readCurrentTime(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_DateTime now = UA_DateTime_now();
    UA_Variant_setScalarCopy(&dataValue->value, &now,
                             &UA_TYPES[UA_TYPES_DATETIME]);
    dataValue->hasValue = true;
    return UA_STATUSCODE_GOOD;
}

2.1.4、订阅模式

对变量的当前值感兴趣的客户端不需要定期轮询变量。相反,他可以使用订阅机制来通知有关更改。

在Subscription中,客户端添加了所谓的MonitoredItems。DataChange MonitoredItem定义监视更改的节点属性(通常是值属性)。服务器在内部读取定义的时间间隔内的值并生成相应的通知。上面讨论的更新节点值的三种方式都可以与通知结合使用。这是因为通知使用标准的读取服务来查找值更改。

3、对象节点的添加

4、对象类型节点的使用

5、变量类型节点的使用

6、服务集的使用

6.1.1服务端方法服务集的集成

6.1.2客户端方法服务的调用

原文地址:https://www.cnblogs.com/retry/p/11679332.html