#include "open62541.h" #include #include #include #include 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; }