Skip to content

Commit

Permalink
🐞 修复 OPC UA 监听事件时,Message 等字段的类型错误
Browse files Browse the repository at this point in the history
  • Loading branch information
zhaoxi-scut committed Feb 13, 2025
1 parent 21759b8 commit 58554b6
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 74 deletions.
6 changes: 1 addition & 5 deletions cmake/RMVLCompilerOptions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,7 @@ function(check_and_add_cxx_flag cxx_flag)
endif()
endfunction()

if(RMVL_MSVC)
option(ENABLE_LTO "Enable Link Time Optimization" OFF)
else()
option(ENABLE_LTO "Enable Link Time Optimization" ON)
endif()
option(ENABLE_LTO "Enable Link Time Optimization" OFF)
if(ENABLE_LTO)
if(RMVL_GNU OR RMVL_CLANG OR RMVL_APPLECLANG)
check_and_add_cxx_flag("-flto=auto")
Expand Down
2 changes: 2 additions & 0 deletions doc/tutorials/modules/tools/opcua.md
Original file line number Diff line number Diff line change
Expand Up @@ -1244,6 +1244,7 @@ public:
// 同步阻塞的 start 函数
bool start()
{
_start_res.reset();
auto [res, oargs] = _cli.call("Start", {});
if (!res)
{
Expand All @@ -1258,6 +1259,7 @@ public:
// 同步阻塞的 stop 函数
bool stop()
{
_stop_res.reset();
auto [res, oargs] = _cli.call("Stop", {});
if (!res)
{
Expand Down
5 changes: 5 additions & 0 deletions modules/opcua/src/helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,11 @@ Variable cvtVariable(const UA_Variant &p_val) noexcept
{
switch (type_flag)
{
case UA_TYPES_LOCALIZEDTEXT: {
UA_LocalizedText *p_ualt = reinterpret_cast<UA_LocalizedText *>(data);
const char *text = reinterpret_cast<const char *>(p_ualt->text.data);
return std::string(text, p_ualt->text.length);
}
case UA_TYPES_STRING: {
UA_String *p_uastr = reinterpret_cast<UA_String *>(data);
const char *str = reinterpret_cast<const char *>(p_uastr->data);
Expand Down
142 changes: 73 additions & 69 deletions modules/opcua/src/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,24 +111,6 @@ Server::~Server()
UA_Server_delete(_server);
}

static NodeId serverFindNode(UA_Server *p_server, std::string_view browse_path, const NodeId &src_nd)
{
RMVL_DbgAssert(p_server != nullptr);

auto paths = str::split(browse_path, "/");
if (paths.empty())
return src_nd;
ServerView sv{p_server};
NodeId retval = src_nd;
for (const auto &path : paths)
{
retval = retval | sv.node(path);
if (retval.empty())
break;
}
return retval;
}

static Variable serverRead(UA_Server *p_server, const NodeId &nd)
{
RMVL_DbgAssert(p_server != nullptr);
Expand All @@ -155,56 +137,13 @@ static bool serverWrite(UA_Server *p_server, const NodeId &nd, const Variable &v
return status == UA_STATUSCODE_GOOD;
}

static bool serverTriggerEvent(UA_Server *server, const Event &event)
{
RMVL_DbgAssert(server != nullptr);

ServerView sv{server};
NodeId type_id = nodeBaseEventType | sv.node(event.type().browse_name);
if (type_id.empty())
{
ERROR_("Failed to find the event type ID during triggering event");
return false;
}
// 创建事件
UA_NodeId event_id;
auto status = UA_Server_createEvent(server, type_id, &event_id);
if (status != UA_STATUSCODE_GOOD)
{
ERROR_("Failed to create event: %s", UA_StatusCode_name(status));
return false;
}

// 设置事件默认属性
UA_DateTime time = UA_DateTime_now();
UA_String source_name = UA_STRING(helper::to_char(event.source_name));
UA_LocalizedText evt_msg = UA_LOCALIZEDTEXT(helper::en_US(), helper::to_char(event.message));
UA_Server_writeObjectProperty_scalar(server, event_id, UA_QUALIFIEDNAME(0, const_cast<char *>("Time")), &time, &UA_TYPES[UA_TYPES_DATETIME]);
UA_Server_writeObjectProperty_scalar(server, event_id, UA_QUALIFIEDNAME(0, const_cast<char *>("SourceName")), &source_name, &UA_TYPES[UA_TYPES_STRING]);
UA_Server_writeObjectProperty_scalar(server, event_id, UA_QUALIFIEDNAME(0, const_cast<char *>("Severity")), &event.severity, &UA_TYPES[UA_TYPES_UINT16]);
UA_Server_writeObjectProperty_scalar(server, event_id, UA_QUALIFIEDNAME(0, const_cast<char *>("Message")), &evt_msg, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
// 设置事件自定义属性
for (const auto &[browse_name, prop] : event.data())
{
NodeId sub_nd = event_id | sv.node(browse_name);
if (!sub_nd.empty())
UA_Server_writeObjectProperty_scalar(server, event_id, UA_QUALIFIEDNAME(event.ns, helper::to_char(browse_name)),
&prop, &UA_TYPES[UA_TYPES_INT32]);
}

// 触发事件
status = UA_Server_triggerEvent(server, event_id, nodeServer, nullptr, true);
if (status != UA_STATUSCODE_GOOD)
{
ERROR_("Failed to trigger event: %s", UA_StatusCode_name(status));
return false;
}
return true;
}

///////////////////////// 节点配置 /////////////////////////

NodeId Server::find(std::string_view browse_path, const NodeId &src_nd) const noexcept { return serverFindNode(_server, browse_path, src_nd); }
NodeId Server::find(std::string_view browse_path, const NodeId &src_nd) const noexcept
{
rm::ServerView sv{_server};
return sv.find(browse_path, src_nd);
}

NodeId Server::addVariableTypeNode(const VariableType &vtype)
{
Expand Down Expand Up @@ -672,14 +611,79 @@ NodeId Server::addEventTypeNode(const EventType &etype)
return retval;
}

bool Server::triggerEvent(const Event &event) const { return serverTriggerEvent(_server, event); }
bool Server::triggerEvent(const Event &event) const
{
rm::ServerView sv{_server};
return sv.triggerEvent(event);
}

//////////////////////// 服务端视图 ////////////////////////

NodeId ServerView::find(std::string_view browse_path, const NodeId &src_nd) const noexcept { return serverFindNode(_server, browse_path, src_nd); }
NodeId ServerView::find(std::string_view browse_path, const NodeId &src_nd) const noexcept
{
RMVL_DbgAssert(_server != nullptr);

auto paths = str::split(browse_path, "/");
if (paths.empty())
return src_nd;
NodeId retval = src_nd;
for (const auto &path : paths)
{
retval = retval | node(path);
if (retval.empty())
break;
}
return retval;
}

Variable ServerView::read(const NodeId &nd) const { return serverRead(_server, nd); }
bool ServerView::write(const NodeId &nd, const Variable &val) const { return serverWrite(_server, nd, val); }
bool ServerView::triggerEvent(const Event &event) const { return serverTriggerEvent(_server, event); }

bool ServerView::triggerEvent(const Event &event) const
{
RMVL_DbgAssert(_server != nullptr);

NodeId type_id = nodeBaseEventType | node(event.type().browse_name);
if (type_id.empty())
{
ERROR_("Failed to find the event type ID during triggering event");
return false;
}
// 创建事件
UA_NodeId event_id;
auto status = UA_Server_createEvent(_server, type_id, &event_id);
if (status != UA_STATUSCODE_GOOD)
{
ERROR_("Failed to create event: %s", UA_StatusCode_name(status));
return false;
}

// 设置事件默认属性
UA_DateTime time = UA_DateTime_now();
UA_String source_name = UA_STRING(helper::to_char(event.source_name));
UA_LocalizedText evt_msg = UA_LOCALIZEDTEXT(helper::en_US(), helper::to_char(event.message));
UA_Server_writeObjectProperty_scalar(_server, event_id, UA_QUALIFIEDNAME(0, const_cast<char *>("Time")), &time, &UA_TYPES[UA_TYPES_DATETIME]);
UA_Server_writeObjectProperty_scalar(_server, event_id, UA_QUALIFIEDNAME(0, const_cast<char *>("SourceName")), &source_name, &UA_TYPES[UA_TYPES_STRING]);
UA_Server_writeObjectProperty_scalar(_server, event_id, UA_QUALIFIEDNAME(0, const_cast<char *>("Severity")), &event.severity, &UA_TYPES[UA_TYPES_UINT16]);
UA_Server_writeObjectProperty_scalar(_server, event_id, UA_QUALIFIEDNAME(0, const_cast<char *>("Message")), &evt_msg, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
// 设置事件自定义属性
for (const auto &[browse_name, prop] : event.data())
{
NodeId sub_nd = event_id | node(browse_name);
if (!sub_nd.empty())
UA_Server_writeObjectProperty_scalar(_server, event_id, UA_QUALIFIEDNAME(event.ns, helper::to_char(browse_name)),
&prop, &UA_TYPES[UA_TYPES_INT32]);
}

// 触发事件
status = UA_Server_triggerEvent(_server, event_id, nodeServer, nullptr, true);
if (status != UA_STATUSCODE_GOOD)
{
ERROR_("Failed to trigger event: %s", UA_StatusCode_name(status));
return false;
}
return true;
}

/////////////////////// 服务器定时器 ///////////////////////

Expand Down

0 comments on commit 58554b6

Please sign in to comment.