Skip to content

Commit

Permalink
添加不占有所有权的 ServerView
Browse files Browse the repository at this point in the history
  • Loading branch information
zhaoxi-scut committed Jul 6, 2024
1 parent b176af2 commit 776ba3c
Show file tree
Hide file tree
Showing 10 changed files with 297 additions and 136 deletions.
24 changes: 24 additions & 0 deletions cmake/RMVLCompilerOptions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,30 @@ if(ENABLE_PIC)
set(CMAKE_POSITION_INDEPENDENT_CODE ${ENABLE_PIC})
endif()

option(ENABLE_LTO "Enable Link Time Optimization" OFF)
if(ENABLE_LTO)
include(CheckCXXCompilerFlag)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
check_cxx_compiler_flag("-flto=auto" HAS_LTO_AUTO_FLAG)
if(HAS_LTO_AUTO_FLAG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto=auto")
else()
check_cxx_compiler_flag("-flto" HAS_LTO_FLAG)
if(HAS_LTO_FLAG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto")
endif()
endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
check_cxx_compiler_flag("/GL" COMPILER_SUPPORTS_LTO)
if(COMPILER_SUPPORTS_LTO)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GL")
set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /LTCG")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /LTCG")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LTCG")
endif()
endif()
endif()

# ----------------------------------------------------------------------------
# Develop options
# ----------------------------------------------------------------------------
Expand Down
6 changes: 3 additions & 3 deletions cmake/templates/cmake_uninstall.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ string(REGEX REPLACE "\n" ";" files "${files}")
foreach(file ${files})
message(STATUS "Uninstalling: $ENV{DESTDIR}${file}")
if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
exec_program(
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
execute_process(
"@CMAKE_COMMAND@" "-E" "remove" "$ENV{DESTDIR}${file}"
OUTPUT_VARIABLE rm_out
RETURN_VALUE rm_retval
RESULT_VARIABLE rm_retval
)
if(NOT "${rm_retval}" STREQUAL 0)
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
Expand Down
64 changes: 45 additions & 19 deletions doc/tutorials/modules/tools/opcua.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@

相关模块: @ref opcua

### 简介
## 1. 简介

#### OPC UA 是什么
### 1.1 OPC UA 是什么

[OPC UA](https://opcfoundation.org/about/opc-technologies/opc-ua/)(全称为 Open Platform Communications Unified Architecture)是一种用于工业和物联网(IoT)应用的开放通信协议和架构。它提供了一种统一的框架,用于在不同设备和系统之间实现数据传输、通信和集成。

Expand All @@ -32,7 +32,7 @@ OPC UA 的设计目标是建立一种通用的、独立于厂商和平台的通
| 信息建模 | OPC UA 使用统一的信息模型,将数据和功能以标准化的方式表示和描述,使不同系统之间的数据交换更加简化和一致 |
| 可靠性 | OPC UA 提供了可靠的通信机制,包括消息确认、重试和错误处理,以确保数据的可靠传输 |

#### 地址空间
### 1.2 地址空间

在 OPC UA 中,所有的数据都被组织成一个地址空间,地址空间中的每一个元素都被称为一个节点。每个节点都有一个唯一的节点号,在 @ref opcua 中表示为 rm::NodeId 。

Expand Down Expand Up @@ -63,11 +63,11 @@ OPC UA 的设计目标是建立一种通用的、独立于厂商和平台的通

8. 视图节点 rm::View :视图节点可将地址空间中感兴趣的节点提取出来,作为一个子集,视图节点作为该子集的入口,方便客户端浏览。

### 服务器/客户端 {#opcua_server_client}
## 2. 服务器/客户端 {#opcua_server_client}

基于服务器/客户端的方式是 OPC UA 最基本的一种通信方式,上文的地址空间在服务器/客户端通信的过程中完全展现出来。下面列举一些 opcua 模块中常用的服务器与客户端的成员方法。

#### 初始化
### 2.1 初始化

**服务器**

Expand Down Expand Up @@ -104,7 +104,7 @@ int main()
}
```

#### 变量
### 2.2 变量

在上文介绍了变量的 3 种访问方式,这里使用最简单的直接读写的方式。首先在服务器中添加变量节点。

Expand Down Expand Up @@ -158,7 +158,7 @@ int main()
}
```

#### 方法
### 2.3 方法

在服务器中添加两数之和的方法节点,供客户端调用。

Expand Down Expand Up @@ -227,7 +227,7 @@ int main()
}
```

#### 对象
### 2.4 对象

在服务器中添加对象节点:

Expand Down Expand Up @@ -302,7 +302,7 @@ int main()
}
```

#### 视图
### 2.5 视图

`nodeObjectsFolder` 中先添加 `A/num1``num2` 2 个变量节点,并将 `num1``num2` 加入视图,下面的示例演示在 **服务器** 中创建并添加视图节点。若要在客户端中进行此操作,创建并添加视图节点的步骤基本一致,这里不做展示。需要注意的是,在客户端中创建并添加视图节点,需要提前在服务器中加入对应的(变量、方法、对象……)节点

Expand Down Expand Up @@ -336,7 +336,7 @@ int main()
}
```

#### 监视
### 2.6 监视

在服务器中添加待监视的变量节点

Expand Down Expand Up @@ -407,7 +407,7 @@ int main()
}
```

### 发布/订阅 {#opcua_pub_sub}
## 3. 发布/订阅 {#opcua_pub_sub}

这是一段来自 [open62541 手册](https://www.open62541.org)中有关 PubSub 的介绍。

Expand Down Expand Up @@ -437,7 +437,7 @@ int main()
有关 API 使用的更多详细信息,请查看 [PubSub 教程](https://www.open62541.org/doc/master/pubsub.html)。
#### 无代理 Pub/Sub
### 3.1 无代理 Pub/Sub
RMVL 提供了基于 `UDP` 传输协议的 Broker-less 即无代理的发布订阅机制,目前支持 `UADP` 的消息映射方式,对应的枚举类型是 `TransportID::UDP_UADP`。
Expand Down Expand Up @@ -513,11 +513,15 @@ int main()
}
```
#### 有代理 Pub/Sub
### 3.2 有代理 Pub/Sub
@warning RMVL 目前暂不支持有代理的发布订阅机制。
### 参数加载 {#opcua_parameters}
## 4. 使用技巧
以下是 @ref opcua 的使用技巧。
### 4.1 参数加载 {#opcua_parameters}
@ref opcua 中提供了以下几个运行时可调节参数
Expand All @@ -533,9 +537,9 @@ int main()
具体调节方式可参考引言中的 @ref intro_parameters_manager 部分。
### 从 XML 配置 OPC UA {#opcua_nodeset_compiler}
### 4.2 从 XML 配置 OPC UA {#opcua_nodeset_compiler}
#### 安装 UaModeler
#### 4.2.1 安装 UaModeler
可使用 UaModeler 等软件进行可视化信息模型的建立,构建后可以导出为一个 `*.xml` 文件,首先先安装 UaModeler。
Expand All @@ -555,15 +559,15 @@ int main()
具体安装细节可参考 [opcua-modeler on Github](https://github.com/FreeOpcUa/opcua-modeler) 的 README。
#### 可视化配置 OPC UA 信息模型
#### 4.2.2 可视化配置 OPC UA 信息模型
对于项目创建或导出等内容,此处不做过多介绍,可参考[此博客](https://wanghao1314.blog.csdn.net/article/details/104092781)了解上述内容。
@note
- 一般的,定义对象、变量、方法等内容均按照在代码中的顺序进行定义即可,但需要注意的是,添加了方法节点后,还需要在代码中设置该方法节点执行的回调函数,可参见 `rm::Server::setMethodNodeCallBack`
- `NamespaceArray``[1]` 的字符串需要更改为 `urn:open62541.server.application`
#### 生成 \*.c/\*.h 文件
#### 4.2.3 生成 \*.c/\*.h 文件
@note 以下生成 C/C++ 文件的介绍来自 [open62541 nodeset-compiler](https://www.open62541.org/doc/master/nodeset_compiler.html#getting-started)
Expand All @@ -582,8 +586,30 @@ python3 ./nodeset_compiler.py \
myNodeSet # myNodeSet 是要生成的文件名,包含 myNodeSet.h 和 myNodeSet.c,请自行设置
```
### 4.3 不占有所有权的服务器视图
`rm::Server` 使用 RAII 进行设计,一个对象占有了服务器的所有权和生命周期,当对象析构时,会自动停止并结束服务器。使用 `rm::ServerView` 来获取不占有所有权的服务器视图,并进行变量读写、路径搜索的操作,下面用服务器视图的单元测试作为示例。
```cpp
rm::Method method;
method.browse_name = "plus";
method.display_name = "Input + Number";
method.description = "输入值加数";
method.func = [](UA_Server *p_server, const UA_NodeId *, void *, const UA_NodeId *, void *, const UA_NodeId *,
void *, size_t, const UA_Variant *inputs, size_t, UA_Variant *) -> UA_StatusCode {
rm::ServerView sv = p_server;
auto num_node = nodeObjectsFolder | sv.find("num");
int num = sv.read(num_node).cast<int>();
rm::Variable dst = *reinterpret_cast<int *>(inputs->data) + num;
sv.write(num_node, dst);
return UA_STATUSCODE_GOOD;
};
method.iargs = {{"input", UA_TYPES_INT32, 1, "输入值"}};
svr.addMethodNode(method);
```
---
### 引用
## 5. 引用
@cite ua-modeler UaModeler · FreeOpcUa/opcua-modeler · Github
26 changes: 13 additions & 13 deletions modules/opcua/include/rmvl/opcua/client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class Client
* @return 目标节点信息
* @retval fnic `[_client, browse_name]` 元组
*/
inline FindNodeInClient find(const std::string &browse_name, uint16_t ns = 1U) { return {_client, browse_name, ns}; }
inline FindNodeInClient find(const std::string &browse_name, uint16_t ns = 1U) const { return {_client, browse_name, ns}; }

/****************************** 功能配置 ******************************/

Expand All @@ -71,22 +71,22 @@ class Client
* @brief
* - 执行事件循环,等效于 ROS/ROS2 工具包中的 `ros::spin()` 以及 `rclcpp::spin()`
*/
void spin();
void spin() const;

/**
* @brief 在网络上监听并处理到达的异步响应,同时进行内部维护、安全通道的更新和订阅管理
* @brief
* - 处理当前已到来的事件,等效于 ROS/ROS2 工具包中的 `ros::spinOnce()` 以及 `rclcpp::spin_some()`
*/
void spinOnce();
void spinOnce() const;

/**
* @brief 从指定的变量节点读数据
*
* @param[in] node 既存的变量节点的 `NodeId`
* @return 读出的用 `rm::Variable` 表示的数据,未成功读取则返回空
*/
Variable read(const NodeId &node);
Variable read(const NodeId &node) const;

/**
* @brief 给指定的变量节点写数据
Expand All @@ -95,7 +95,7 @@ class Client
* @param[in] val 待写入的数据
* @return 是否写入成功
*/
bool write(const NodeId &node, const Variable &val);
bool write(const NodeId &node, const Variable &val) const;

/**
* @brief 在客户端调用指定对象节点中的方法
Expand All @@ -106,25 +106,25 @@ class Client
* @param[out] outputs 输出参数列表
* @return 是否成功完成当前操作
*/
bool call(const NodeId &obj_node, const std::string &name, const std::vector<Variable> &inputs, std::vector<Variable> &outputs);
bool call(const NodeId &obj_node, const std::string &name, const std::vector<Variable> &inputs, std::vector<Variable> &outputs) const;

/**
* @brief 在客户端调用 ObjectsFolder 中的方法
*
* @param[in] name 方法名
* @param[in] name 方法名 `browse_name`
* @param[in] inputs 输入参数列表
* @param[out] outputs 输出参数列表
* @return 是否成功完成当前操作
*/
inline bool call(const std::string &name, const std::vector<Variable> &inputs, std::vector<Variable> &outputs) { return call(nodeObjectsFolder, name, inputs, outputs); }
inline bool call(const std::string &name, const std::vector<Variable> &inputs, std::vector<Variable> &outputs) const { return call(nodeObjectsFolder, name, inputs, outputs); }

/**
* @brief 添加视图节点 ViewNode 至 `ViewsFolder` 中
* @brief 添加 OPC UA 视图节点 ViewNode 至 `ViewsFolder` 中
*
* @param[in] view `rm::View` 表示的视图
* @return 添加至服务器后,对应视图节点的唯一标识 `NodeId`
*/
NodeId addViewNode(const View &view);
NodeId addViewNode(const View &view) const;

/**
* @brief 创建变量节点监视项,以实现订阅节点的功能
Expand All @@ -151,7 +151,7 @@ class Client
* @param[in] queue_size 通知存放的队列大小,若队列已满,新的通知会覆盖旧的通知,默认为 `10`
* @return 变量节点监视创建成功?
*/
bool monitor(NodeId node, UA_Client_DataChangeNotificationCallback on_change, uint32_t queue_size = 10);
bool monitor(NodeId node, UA_Client_DataChangeNotificationCallback on_change, uint32_t queue_size = 10) const;

/**
* @brief 创建事件监视项,以实现事件的订阅功能
Expand All @@ -161,7 +161,7 @@ class Client
* @param[in] on_event 事件回调函数
* @return 事件监视创建成功?
*/
bool monitor(NodeId node, const std::vector<std::string> &names, UA_Client_EventNotificationCallback on_event);
bool monitor(NodeId node, const std::vector<std::string> &names, UA_Client_EventNotificationCallback on_event) const;

private:
/**
Expand All @@ -170,7 +170,7 @@ class Client
* @param[out] response 订阅请求的响应
* @return 是否成功完成当前操作
*/
bool createSubscription(UA_CreateSubscriptionResponse &responce);
bool createSubscription(UA_CreateSubscriptionResponse &responce) const;
};

//! @} opcua
Expand Down
Loading

0 comments on commit 776ba3c

Please sign in to comment.