187 lines
7.7 KiB
C
187 lines
7.7 KiB
C
![]() |
#include <open62541.h>
|
||
|
#include <stdio.h>
|
||
|
#include <signal.h>
|
||
|
#include <stdbool.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
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 UA_StatusCode
|
||
|
helloMethodCallback(UA_Server *server,
|
||
|
const UA_NodeId *sessionId, void *sessionContext,
|
||
|
const UA_NodeId *methodId, void *methodContext,
|
||
|
const UA_NodeId *objectId, void *objectContext,
|
||
|
size_t inputSize, const UA_Variant *input,
|
||
|
size_t outputSize, UA_Variant *output)
|
||
|
{
|
||
|
UA_String *inputStr = (UA_String*)input[0].data;
|
||
|
const char *helloPrefix = "Hello ";
|
||
|
size_t helloLen = strlen(helloPrefix);
|
||
|
|
||
|
// 分配内存用于存储输出字符串(前缀 + 输入字符串)
|
||
|
size_t resultLen = helloLen + inputStr->length;
|
||
|
UA_Byte *result = (UA_Byte*)UA_malloc(resultLen);
|
||
|
if (!result) {
|
||
|
return UA_STATUSCODE_BADOUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
// 将 "Hello " 和输入字符串复制到结果中
|
||
|
memcpy(result, helloPrefix, helloLen);
|
||
|
memcpy(result + helloLen, inputStr->data, inputStr->length);
|
||
|
|
||
|
// 将输出 variant 设置为结果字符串
|
||
|
UA_String resultStr;
|
||
|
resultStr.data = result;
|
||
|
resultStr.length = resultLen;
|
||
|
UA_Variant_setScalarCopy(output, &resultStr, &UA_TYPES[UA_TYPES_STRING]);
|
||
|
|
||
|
// 清理结果缓冲区
|
||
|
UA_String_clear(&resultStr);
|
||
|
|
||
|
return UA_STATUSCODE_GOOD;
|
||
|
}
|
||
|
|
||
|
static void manuallyDefinePump(UA_Server *server)
|
||
|
{
|
||
|
// 声明并获取服务器分配的节点 ID
|
||
|
UA_NodeId pumpId;
|
||
|
|
||
|
// 定义对象属性并设置显示名称
|
||
|
UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
|
||
|
oAttr.displayName = UA_LOCALIZEDTEXT("en-US", "Pump (Manual)");
|
||
|
|
||
|
// 添加泵对象节点
|
||
|
UA_Server_addObjectNode(server,
|
||
|
UA_NODEID_NULL,
|
||
|
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
|
||
|
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
|
||
|
UA_QUALIFIEDNAME(1, "Pump (Manual)"),
|
||
|
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
|
||
|
oAttr, NULL, &pumpId);
|
||
|
|
||
|
// 定义变量属性并添加“ManufacturerName”变量节点
|
||
|
UA_VariableAttributes mnAttr = UA_VariableAttributes_default;
|
||
|
UA_String manufacturerName = UA_STRING("Pump King Ltd.");
|
||
|
UA_Variant_setScalar(&mnAttr.value, &manufacturerName, &UA_TYPES[UA_TYPES_STRING]);
|
||
|
mnAttr.displayName = UA_LOCALIZEDTEXT("en-US", "ManufacturerName");
|
||
|
|
||
|
UA_Server_addVariableNode(server,
|
||
|
UA_NODEID_NULL,
|
||
|
pumpId,
|
||
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
|
||
|
UA_QUALIFIEDNAME(1, "ManufacturerName"),
|
||
|
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
|
||
|
mnAttr, NULL, NULL);
|
||
|
|
||
|
// 定义变量属性并添加“ModelName”变量节点
|
||
|
UA_VariableAttributes modelAttr = UA_VariableAttributes_default;
|
||
|
UA_String modelName = UA_STRING("Mega Pump 3000");
|
||
|
UA_Variant_setScalar(&modelAttr.value, &modelName, &UA_TYPES[UA_TYPES_STRING]);
|
||
|
modelAttr.displayName = UA_LOCALIZEDTEXT("en-US", "ModelName");
|
||
|
|
||
|
UA_Server_addVariableNode(server,
|
||
|
UA_NODEID_NULL,
|
||
|
pumpId,
|
||
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
|
||
|
UA_QUALIFIEDNAME(1, "ModelName"),
|
||
|
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
|
||
|
modelAttr, NULL, NULL);
|
||
|
|
||
|
// 定义变量属性并添加“Status”变量节点
|
||
|
UA_VariableAttributes statusAttr = UA_VariableAttributes_default;
|
||
|
UA_Boolean status = true;
|
||
|
UA_Variant_setScalar(&statusAttr.value, &status, &UA_TYPES[UA_TYPES_BOOLEAN]);
|
||
|
statusAttr.displayName = UA_LOCALIZEDTEXT("en-US", "Status");
|
||
|
|
||
|
UA_Server_addVariableNode(server,
|
||
|
UA_NODEID_NULL,
|
||
|
pumpId,
|
||
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
|
||
|
UA_QUALIFIEDNAME(1, "Status"),
|
||
|
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
|
||
|
statusAttr, NULL, NULL);
|
||
|
|
||
|
// 定义变量属性并添加“MotorRPM”变量节点
|
||
|
UA_VariableAttributes rpmAttr = UA_VariableAttributes_default;
|
||
|
UA_Double rpm = 50.0;
|
||
|
UA_Variant_setScalar(&rpmAttr.value, &rpm, &UA_TYPES[UA_TYPES_DOUBLE]);
|
||
|
rpmAttr.displayName = UA_LOCALIZEDTEXT("en-US", "MotorRPM");
|
||
|
|
||
|
UA_Server_addVariableNode(server,
|
||
|
UA_NODEID_NULL,
|
||
|
pumpId,
|
||
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
|
||
|
UA_QUALIFIEDNAME(1, "MotorRPM"),
|
||
|
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
|
||
|
rpmAttr, NULL, NULL);
|
||
|
|
||
|
UA_ObjectAttributes ptAttr = UA_ObjectAttributes_default;
|
||
|
ptAttr.displayName = UA_LOCALIZEDTEXT("en-US", "PumpType");
|
||
|
UA_NodeId pumpTypeId;
|
||
|
UA_Server_addObjectNode(server, UA_NODEID_NULL,
|
||
|
pumpId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
|
||
|
UA_QUALIFIEDNAME(1, "PumpType"),
|
||
|
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
|
||
|
ptAttr,
|
||
|
NULL, &pumpTypeId);
|
||
|
|
||
|
|
||
|
UA_Argument inputArgument;
|
||
|
UA_Argument_init(&inputArgument);
|
||
|
inputArgument.description = UA_LOCALIZEDTEXT("zh-CN", "输入字符串");
|
||
|
inputArgument.name = UA_STRING("InputString");
|
||
|
inputArgument.dataType = UA_TYPES[UA_TYPES_STRING].typeId; // 字符串类型
|
||
|
inputArgument.valueRank = UA_VALUERANK_SCALAR; // 标量
|
||
|
|
||
|
// 定义方法的输出参数
|
||
|
UA_Argument outputArgument;
|
||
|
UA_Argument_init(&outputArgument);
|
||
|
outputArgument.description = UA_LOCALIZEDTEXT("zh-CN", "输出字符串");
|
||
|
outputArgument.name = UA_STRING("OutputString");
|
||
|
outputArgument.dataType = UA_TYPES[UA_TYPES_STRING].typeId; // 字符串类型
|
||
|
outputArgument.valueRank = UA_VALUERANK_SCALAR; // 标量
|
||
|
|
||
|
// 添加方法节点
|
||
|
UA_MethodAttributes helloAttr = UA_MethodAttributes_default;
|
||
|
helloAttr.description = UA_LOCALIZEDTEXT("zh-CN", "添加Hello前缀");
|
||
|
helloAttr.displayName = UA_LOCALIZEDTEXT("zh-CN", "HelloMethod");
|
||
|
helloAttr.executable = true;
|
||
|
helloAttr.userExecutable = true;
|
||
|
|
||
|
UA_NodeId helloMethodNodeId;
|
||
|
UA_Server_addMethodNode(server,
|
||
|
UA_NODEID_NULL, // NodeId (自动生成)
|
||
|
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), // 父节点为 ObjectsFolder
|
||
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), // 引用类型
|
||
|
UA_QUALIFIEDNAME(1, "HelloMethod"), // 浏览名称
|
||
|
helloAttr, // 属性
|
||
|
&helloMethodCallback, // 回调函数
|
||
|
1, &inputArgument, // 输入参数的数量和描述
|
||
|
1, &outputArgument, // 输出参数的数量和描述
|
||
|
NULL,NULL);
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
int main(void) {
|
||
|
signal(SIGINT, stopHandler);
|
||
|
signal(SIGTERM, stopHandler);
|
||
|
|
||
|
UA_Server *server = UA_Server_new();
|
||
|
UA_ServerConfig_setDefault(UA_Server_getConfig(server));
|
||
|
|
||
|
manuallyDefinePump(server);
|
||
|
|
||
|
UA_StatusCode retval = UA_Server_run(server, &running);
|
||
|
UA_Server_delete(server);
|
||
|
return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
|
||
|
}
|