opcuaServer/myServer.c
2024-12-22 17:37:17 +08:00

193 lines
7.9 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)
{
//Add NameSpace
const char *namespaceUri = "http://example.com/MyNamespace";
UA_UInt16 namespaceIndex = UA_Server_addNamespace(server, namespaceUri);
// 声明并获取服务器分配的节点 ID
UA_NodeId pumpId;
// 定义对象属性并设置显示名称
UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
oAttr.displayName = UA_LOCALIZEDTEXT("en-US", "Pump (Manual)");
// 添加泵对象节点
UA_Server_addObjectNode(server,
UA_NODEID_NUMERIC(namespaceIndex, 1),
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;
}