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定義監視更改的節點屬性(通常是值屬性)。服務器在內部讀取定義的時間間隔內的值並生成相應的通知。上面討論的更新節點值的三種方式都可以與通知結合使用。這是因為通知使用標准的讀取服務來查找值更改。